diff --git a/CMakeLists.txt b/CMakeLists.txt index edfd21fcc..e2dc6a42a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -25,6 +25,7 @@ option(BUILD_GUI "Build Tomahawk with GUI" ON) option(BUILD_RELEASE "Generate TOMAHAWK_VERSION without GIT info" OFF) option(WITH_BREAKPAD "Build with breakpad integration" ON) option(WITH_CRASHREPORTER "Build with CrashReporter" ON) +option(WITH_BINARY_ATTICA "Enable support for downloading binary resolvers automatically" ON) option(LEGACY_KDE_INTEGRATION "Install tomahawk.protocol file, deprecated since 4.6.0" OFF) IF( CMAKE_SYSTEM_PROCESSOR MATCHES "arm" ) @@ -68,7 +69,7 @@ SET( CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}" ) SET( CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}" ) # make predefined install dirs available everywhere -INCLUDE(GNUInstallDirs) +INCLUDE( GNUInstallDirs ) # installer creation INCLUDE( TomahawkCPack.cmake ) @@ -100,8 +101,8 @@ if(PHONON_FOUND) message(STATUS "Phonon found; ensure that phonon-vlc is at least 0.4") endif() -macro_optional_find_package(LibEchonest 1.1.10) -macro_log_feature(LIBECHONEST_FOUND "Echonest" "Qt library for communicating with The Echo Nest" "http://projects.kde.org/libechonest" TRUE "" "libechonest 1.1.10 is needed for dynamic playlists and the infosystem") +macro_optional_find_package(LibEchonest 1.2.1) +macro_log_feature(LIBECHONEST_FOUND "Echonest" "Qt library for communicating with The Echo Nest" "http://projects.kde.org/libechonest" TRUE "" "libechonest 1.2.1 is needed for dynamic playlists and the infosystem") macro_optional_find_package(CLucene 0.9.23) macro_log_feature(CLucene_FOUND "CLucene" "The open-source, C++ search engine" "http://clucene.sf.net" TRUE "" "CLucene is used for indexing the collection") @@ -132,11 +133,8 @@ macro_log_feature(JREEN_FOUND "Jreen" "Qt XMPP Library" "http://qutim.org/jreen macro_optional_find_package(QTweetLib) macro_log_feature(QTWEETLIB_FOUND "QTweetLib" "Qt Twitter Library" "https://github.com/minimoog/QTweetLib" FALSE "" "QTweetLib is needed for the Twitter SIP plugin.\n") -# required -#While we distribute our own liblastfm2, don't need to look for it -#macro_optional_find_package(LibLastFm 0.3.3) -#macro_log_feature(LIBLASTFM_FOUND "LastFm" "Qt library for the Last.fm webservices" "https://github.com/mxcl/liblastfm" FALSE "" "liblastfm is needed for scrobbling tracks to Last.fm and fetching cover artwork") -set(LIBLASTFM_FOUND true) +macro_optional_find_package(LibLastFm 1.0.0) +macro_log_feature(LIBLASTFM_FOUND "liblastfm" "Qt library for the Last.fm webservices" "https://github.com/eartle/liblastfm" TRUE "" "liblastfm is needed for scrobbling tracks to Last.fm and fetching cover artwork") #### submodules start # automatically init submodules here, don't delete this code we may add submodules again diff --git a/CMakeModules/FindGloox.cmake b/CMakeModules/FindGloox.cmake deleted file mode 100644 index ccdbdcfbf..000000000 --- a/CMakeModules/FindGloox.cmake +++ /dev/null @@ -1,23 +0,0 @@ -# - Try to find GLOOX -# Find GLOOX headers, libraries and the answer to all questions. -# -# GLOOX_FOUND True if gloox got found -# GLOOX_INCLUDE_DIR Location of gloox headers -# GLOOX_LIBRARIES List of libaries to use gloox -# -# Copyright (c) 2009 Nigmatullin Ruslan -# -# Redistribution and use is allowed according to the terms of the New -# BSD license. -# For details see the accompanying COPYING-CMAKE-SCRIPTS file. -# - -FIND_PATH( GLOOX_INCLUDE_DIR "gloox/gloox.h" ) -FIND_LIBRARY( GLOOX_LIBRARIES gloox ) - -if( GLOOX_LIBRARIES AND GLOOX_INCLUDE_DIR ) - message( STATUS "Found gloox: ${GLOOX_LIBRARIES}" ) - set( GLOOX_FOUND 1 ) -else( GLOOX_LIBRARIES AND GLOOX_INCLUDE_DIR ) - message( STATUS "Could NOT find gloox" ) -endif( GLOOX_LIBRARIES AND GLOOX_INCLUDE_DIR ) diff --git a/CMakeModules/FindJreen.cmake b/CMakeModules/FindJreen.cmake index 3788e9f23..e1f97d16c 100644 --- a/CMakeModules/FindJreen.cmake +++ b/CMakeModules/FindJreen.cmake @@ -30,7 +30,6 @@ ENDIF() INCLUDE(FindPackageHandleStandardArgs) FIND_PACKAGE_HANDLE_STANDARD_ARGS(Jreen - REQUIRED_VARS JREEN_LIBRARIES JREEN_INCLUDE_DIR - VERSION_VAR PC_JREEN_VERSION) + REQUIRED_VARS JREEN_LIBRARIES JREEN_INCLUDE_DIR) MARK_AS_ADVANCED(JREEN_INCLUDE_DIR JREEN_LIBRARIES) diff --git a/CMakeModules/FindLibLastFm.cmake b/CMakeModules/FindLibLastFm.cmake index c73038a7d..27362fe71 100644 --- a/CMakeModules/FindLibLastFm.cmake +++ b/CMakeModules/FindLibLastFm.cmake @@ -1,42 +1,34 @@ -# - Find LibLastFM -# Find the liblastfm includes and the liblastfm libraries -# This module defines -# LIBLASTFM_INCLUDE_DIR, root lastfm include dir -# LIBLASTFM_LIBRARY, the path to liblastfm -# LIBLASTFM_FOUND, whether liblastfm was found +# - Try to find LibLastFm +# +# LIBLASTFM_FOUND - system has liblastfm +# LIBLASTFM_INCLUDE_DIRS - the liblastfm include directories +# LIBLASTFM_LIBRARIES - link these to use liblastfm +# +# (c) Dominik Schmidt +# +# Dependencies +if(NOT QT4_FOUND) + find_package(Qt4 REQUIRED) +endif() -find_path(LIBLASTFM_INCLUDE_DIR NAMES Audioscrobbler - HINTS - ~/usr/include - /opt/local/include - /usr/local/include - /usr/include - /opt/kde4/include - ${KDE4_INCLUDE_DIR} - PATH_SUFFIXES lastfm +# Include dir +find_path(LIBLASTFM_INCLUDE_DIR + # Track.h doesn't exist in liblastfm-0.3.1, was called Track back then + NAMES lastfm/Track.h + PATHS ${KDE4_INCLUDE_DIR} ) -find_library( LIBLASTFM_LIBRARY NAMES lastfm - PATHS - ~/usr/lib - /opt/local/lib - /usr/local/lib - /usr/lib - /usr/lib64 - /opt/kde4/lib - ${KDE4_LIB_DIR} +# Finally the library itself +find_library(LIBLASTFM_LIBRARY + NAMES lastfm + PATHS ${KDE4_LIB_DIR} ) +set(LIBLASTFM_LIBRARIES ${LIBLASTFM_LIBRARY}) +set(LIBLASTFM_INCLUDE_DIRS ${LIBLASTFM_INCLUDE_DIR}) -if(LIBLASTFM_INCLUDE_DIR AND LIBLASTFM_LIBRARY) - set(LIBLASTFM_FOUND TRUE) - message(STATUS "Found liblastfm: ${LIBLASTFM_INCLUDE_DIR}, ${LIBLASTFM_LIBRARY}") -else(LIBLASTFM_INCLUDE_DIR AND LIBLASTFM_LIBRARY) - set(LIBLASTFM_FOUND FALSE) - if (LIBLASTFM_FIND_REQUIRED) - message(FATAL_ERROR "Could NOT find required package LibLastFm") - endif(LIBLASTFM_FIND_REQUIRED) -endif(LIBLASTFM_INCLUDE_DIR AND LIBLASTFM_LIBRARY) +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(LibLastFm DEFAULT_MSG LIBLASTFM_LIBRARIES LIBLASTFM_INCLUDE_DIRS) -mark_as_advanced(LIBLASTFM_INCLUDE_DIR LIBLASTFM_LIBRARY) +mark_as_advanced(LIBLASTFM_LIBRARIES LIBLASTFM_INCLUDE_DIRS) diff --git a/CMakeModules/NSIS.template.in b/CMakeModules/NSIS.template.in index 2e1aa7c93..f3db07863 100644 --- a/CMakeModules/NSIS.template.in +++ b/CMakeModules/NSIS.template.in @@ -278,7 +278,6 @@ Section "Tomahawk Player" SEC_TOMAHAWK_PLAYER File "${INSTALL_PATH}\bin\libqxtweb-standalone.dll" File "${INSTALL_PATH}\bin\libtomahawk_portfwd.dll" - File "${INSTALL_PATH}\bin\libtomahawk_lastfm2.dll" File "${INSTALL_PATH}\bin\libtomahawklib.dll" ; plugins File "${INSTALL_PATH}\lib\libtomahawk_*_*.dll" @@ -293,7 +292,6 @@ Section "Tomahawk Player" SEC_TOMAHAWK_PLAYER File "${BUILD_PATH}\libtomahawklib.dll" File "${BUILD_PATH}\libqxtweb-standalone.dll" File "${BUILD_PATH}\libtomahawk_portfwd.dll" - File "${BUILD_PATH}\libtomahawk_lastfm2.dll" ; plugins File "${BUILD_PATH}\libtomahawk_*_*.dll" !endif @@ -351,6 +349,7 @@ Section "Tomahawk Player" SEC_TOMAHAWK_PLAYER File "${MING_BIN}\zlib1.dll" File "${MING_BIN}\libechonest.dll" + File "${MING_BIN}\liblastfm.dll" File "${MING_BIN}\libQTweetLib.dll" File "${MING_BIN}\libquazip.dll" diff --git a/ChangeLog b/ChangeLog index faa496d26..0fa6c3c4b 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,6 +1,35 @@ +Version 0.5.0: + * Priortize resolution of a track on double-click + * New Tomahawk logo and icon + * Spotify Resolver shipped with Tomahawk and installable via new Preferences interface + * Sync select playlists (and updates) with Spotify + * Support .aiff (AIFF mimetype) files + * Cleaned up Diagnostics window + * Don't show non-resolved tracks as Recently Played + * Added "Stop playback after this track" context menu items + * Double-clicking on a playlist name (in the sidebar) will play the playlist + * You can now import your entire Last.fm playback history into Tomahawk + * Related Artists now sorted by relatedness + * Support for multimedia keys (Play, Pause, Next etc.) on Windows & Linux + * When listening privately scrobbling to Last.fm and Adium is now disabled + * Added a toolbar with page back / forward buttons and the global search + * New grid view with direct playback controls (Charts, Album Page, Artist Page, Track Page) + * New Releases (by Genre) pages added + * Add social sharing widget in Now Playing Controls + * Added a track page showing a song's lyrics and other similar tracks + * Selecting Track name in Now Playing now brings you to Track page + * Separate Loved Tracks and Recently Played views per source. + * Added animated spinner where needed + * Some new sidebar icons + * Support Transifex for localization and add translations for Arabic, French, Bulgarian, Catalan, Spanish (Castillian), and more. + * New Context Menu items (Love, Add to Queue, etc.) + * Fading album art + * New Account and Plug-in Preferences/Management Interface + * Fix XSPF auto-updating + + Version 0.4.2: * Fix ZeroConf protocol showing IP addresses instead of host names. - Sometimes. Full fix coming later. * Updated translations for various languages. * Resuming playback restores correct volume settings. * Reduced CPU usage during playback. @@ -22,7 +51,7 @@ Version 0.4.0: * Fixed icons not appearing in resolvers list. * Fixed various UI glitches and stray error messages in stations. * Fixed bug where album page would resolve bottom-to-top. - * Fixed bug where Footnotes would not update when changing selected album in Album View. + * Fixed bug where Footnotes would not update when changing selected album. * Fixed dragging albums and artists from charts, album, and artist views. * Fixed bug where filter text would be one step behind filter value. * Fixed bug where resolvers would enable themselves after auto-updating. diff --git a/README b/README index 7b47a9de1..5558b875b 100644 --- a/README +++ b/README @@ -17,7 +17,7 @@ Detailed building instructions for Ubuntu Detailed building instructions for OS X --------------------------------------- - See: http://wiki.tomahawk-player.org/mediawiki/index.php/Building_OS_X_Application_Bundle_on_Snow_Leopard_(10.6) + See: http://wiki.tomahawk-player.org/mediawiki/index.php/Building_OS_X_Application_Bundle_on_Snow_Leopard_(10.6)_and_Lion_(10.7) Doxygen Documentation --------------------- @@ -34,18 +34,18 @@ Dependencies TagLib 1.6.2 - http://developer.kde.org/~wheeler/taglib.html Boost 1.3 - http://www.boost.org/ CLucene 0.9.23 (0.9.21 will fail) - http://clucene.sourceforge.net/download.shtml - libechonest 1.2.0 - http://projects.kde.org/projects/playground/libs/libechonest/ + libechonest 1.2.1 - http://projects.kde.org/projects/playground/libs/libechonest/ + Attica 0.3.0 - ftp://ftp.kde.org/pub/kde/stable/attica/ + QuaZip 0.4.3 - http://quazip.sourceforge.net/ The following dependencies are optional, but recommended: - Attica 0.3.0 - ftp://ftp.kde.org/pub/kde/stable/attica/ - QuaZip 0.4.3 - http://quazip.sourceforge.net/ Jreen 1.0.5 - http://qutim.org/jreen / https://github.com/euroelessar/jreen QTweetLib 0.5.0 - https://github.com/minimoog/QTweetLib + liblastfm 1.0.0 - http://github.com/eartle/liblastfm/ Third party libraries that we ship with our source: MiniUPnP 1.6 - http://miniupnp.free.fr/ - liblastfm 0.4.0 - http://github.com/jonocole/liblastfm/ Enjoy! diff --git a/admin/mac/macdeploy.py b/admin/mac/macdeploy.py index 6d7987982..8acda2049 100755 --- a/admin/mac/macdeploy.py +++ b/admin/mac/macdeploy.py @@ -29,159 +29,159 @@ LIBRARY_SEARCH_PATH=['/usr/local/lib', '/usr/local/Cellar/gettext/0.18.1.1/lib', VLC_PLUGINS=[ - 'access/libaccess_attachment_plugin.dylib', - #'access/libaccess_avio_plugin.dylib', - 'access/libaccess_fake_plugin.dylib', - 'access/libaccess_ftp_plugin.dylib', - 'access/libaccess_http_plugin.dylib', - 'access/libaccess_imem_plugin.dylib', - 'access/libaccess_mmap_plugin.dylib', - 'access/libaccess_mms_plugin.dylib', - 'access/libaccess_realrtsp_plugin.dylib', - 'access/libaccess_tcp_plugin.dylib', - 'access/libaccess_udp_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', - 'audio_filter/libconverter_fixed_plugin.dylib', - 'audio_filter/libdolby_surround_decoder_plugin.dylib', - 'audio_filter/libdtstofloat32_plugin.dylib', - 'audio_filter/libdtstospdif_plugin.dylib', - 'audio_filter/libequalizer_plugin.dylib', - 'audio_filter/libheadphone_channel_mixer_plugin.dylib', - 'audio_filter/libmono_plugin.dylib', - 'audio_filter/libmpgatofixed32_plugin.dylib', - 'audio_filter/libnormvol_plugin.dylib', - 'audio_filter/libparam_eq_plugin.dylib', - 'audio_filter/libscaletempo_plugin.dylib', - 'audio_filter/libsimple_channel_mixer_plugin.dylib', - 'audio_filter/libspatializer_plugin.dylib', - 'audio_filter/libtrivial_channel_mixer_plugin.dylib', - 'audio_filter/libugly_resampler_plugin.dylib', - 'audio_mixer/libfloat32_mixer_plugin.dylib', - 'audio_mixer/libspdif_mixer_plugin.dylib', - 'audio_mixer/libtrivial_mixer_plugin.dylib', - 'audio_output/libaout_file_plugin.dylib', - 'audio_output/libauhal_plugin.dylib', - 'codec/liba52_plugin.dylib', - 'codec/libadpcm_plugin.dylib', - 'codec/libaes3_plugin.dylib', - 'codec/libaraw_plugin.dylib', - 'codec/libavcodec_plugin.dylib', - 'codec/libcc_plugin.dylib', - 'codec/libcdg_plugin.dylib', - 'codec/libdts_plugin.dylib', - 'codec/libfaad_plugin.dylib', - 'codec/libfake_plugin.dylib', - 'codec/libflac_plugin.dylib', - 'codec/libfluidsynth_plugin.dylib', - 'codec/libinvmem_plugin.dylib', - 'codec/liblpcm_plugin.dylib', - 'codec/libmpeg_audio_plugin.dylib', - 'codec/libpng_plugin.dylib', - 'codec/librawvideo_plugin.dylib', - 'codec/libspeex_plugin.dylib', - 'codec/libspudec_plugin.dylib', - 'codec/libtheora_plugin.dylib', - 'codec/libtwolame_plugin.dylib', - 'codec/libvorbis_plugin.dylib', - 'control/libgestures_plugin.dylib', - 'control/libhotkeys_plugin.dylib', - 'control/libmotion_plugin.dylib', - 'control/libnetsync_plugin.dylib', - 'control/libsignals_plugin.dylib', - 'demux/libaiff_plugin.dylib', - 'demux/libasf_plugin.dylib', - 'demux/libau_plugin.dylib', - #'demux/libavformat_plugin.dylib', - 'demux/libavi_plugin.dylib', - 'demux/libdemux_cdg_plugin.dylib', - 'demux/libdemuxdump_plugin.dylib', - 'demux/libdirac_plugin.dylib', - 'demux/libes_plugin.dylib', - 'demux/libflacsys_plugin.dylib', - 'demux/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', - 'misc/libaudioscrobbler_plugin.dylib', - 'misc/libdummy_plugin.dylib', - 'misc/libexport_plugin.dylib', - 'misc/libfreetype_plugin.dylib', - 'misc/libgnutls_plugin.dylib', - 'misc/liblogger_plugin.dylib', - 'misc/liblua_plugin.dylib', - 'misc/libosd_parser_plugin.dylib', - 'misc/libquartztext_plugin.dylib', - 'misc/libstats_plugin.dylib', - 'misc/libvod_rtsp_plugin.dylib', - 'misc/libxml_plugin.dylib', - 'misc/libxtag_plugin.dylib', - 'mmx/libi420_rgb_mmx_plugin.dylib', - 'mmx/libi420_yuy2_mmx_plugin.dylib', - 'mmx/libi422_yuy2_mmx_plugin.dylib', - 'mmx/libmemcpymmx_plugin.dylib', - 'mmxext/libmemcpymmxext_plugin.dylib', - 'mux/libmux_asf_plugin.dylib', - 'mux/libmux_avi_plugin.dylib', - 'mux/libmux_dummy_plugin.dylib', - 'mux/libmux_mp4_plugin.dylib', - 'mux/libmux_mpjpeg_plugin.dylib', - 'mux/libmux_ogg_plugin.dylib', - 'mux/libmux_ps_plugin.dylib', - 'mux/libmux_ts_plugin.dylib', - 'mux/libmux_wav_plugin.dylib', - 'packetizer/libpacketizer_copy_plugin.dylib', - 'packetizer/libpacketizer_dirac_plugin.dylib', - 'packetizer/libpacketizer_flac_plugin.dylib', - 'packetizer/libpacketizer_h264_plugin.dylib', - 'packetizer/libpacketizer_mlp_plugin.dylib', - 'packetizer/libpacketizer_mpeg4audio_plugin.dylib', - 'packetizer/libpacketizer_mpeg4video_plugin.dylib', - 'packetizer/libpacketizer_mpegvideo_plugin.dylib', - 'packetizer/libpacketizer_vc1_plugin.dylib', - 'sse2/libi420_rgb_sse2_plugin.dylib', - 'sse2/libi420_yuy2_sse2_plugin.dylib', - 'sse2/libi422_yuy2_sse2_plugin.dylib', - 'stream_filter/libdecomp_plugin.dylib', - 'stream_filter/libstream_filter_rar_plugin.dylib', - 'stream_filter/libstream_filter_record_plugin.dylib', - 'visualization/libvisual_plugin.dylib', + 'libaccess_attachment_plugin.dylib', + #'libaccess_avio_plugin.dylib', + #'libaccess_fake_plugin.dylib', + 'libaccess_ftp_plugin.dylib', + 'libaccess_http_plugin.dylib', + 'libaccess_imem_plugin.dylib', + #'libaccess_mmap_plugin.dylib', + 'libaccess_mms_plugin.dylib', + 'libaccess_realrtsp_plugin.dylib', + 'libaccess_tcp_plugin.dylib', + 'libaccess_udp_plugin.dylib', + 'libcdda_plugin.dylib', + 'libfilesystem_plugin.dylib', + 'libqtcapture_plugin.dylib', + 'librtp_plugin.dylib', + 'libzip_plugin.dylib', + 'libaccess_output_dummy_plugin.dylib', + 'libaccess_output_file_plugin.dylib', + 'libaccess_output_http_plugin.dylib', + 'libaccess_output_shout_plugin.dylib', + 'libaccess_output_udp_plugin.dylib', + 'liba52tofloat32_plugin.dylib', + 'liba52tospdif_plugin.dylib', + 'libaudio_format_plugin.dylib', + 'libaudiobargraph_a_plugin.dylib', + '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', + 'libfloat32_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', + #'libfake_plugin.dylib', + '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', + 'libhotkeys_plugin.dylib', + 'libmotion_plugin.dylib', + 'libnetsync_plugin.dylib', + #'libsignals_plugin.dylib', + 'libaiff_plugin.dylib', + 'libasf_plugin.dylib', + 'libau_plugin.dylib', + #'libavformat_plugin.dylib', + 'libavi_plugin.dylib', + 'libdemux_cdg_plugin.dylib', + 'libdemuxdump_plugin.dylib', + 'libdirac_plugin.dylib', + 'libes_plugin.dylib', + 'libflacsys_plugin.dylib', + 'liblive555_plugin.dylib', + 'libmkv_plugin.dylib', + 'libmod_plugin.dylib', + 'libmp4_plugin.dylib', + 'libmpc_plugin.dylib', + 'libmpgv_plugin.dylib', + 'libnsc_plugin.dylib', + 'libnsv_plugin.dylib', + 'libnuv_plugin.dylib', + 'libogg_plugin.dylib', + 'libplaylist_plugin.dylib', + 'libps_plugin.dylib', + 'libpva_plugin.dylib', + 'librawaud_plugin.dylib', + 'librawdv_plugin.dylib', + 'librawvid_plugin.dylib', + 'libreal_plugin.dylib', + 'libsmf_plugin.dylib', + 'libts_plugin.dylib', + 'libtta_plugin.dylib', + 'libty_plugin.dylib', + 'libvc1_plugin.dylib', + 'libvoc_plugin.dylib', + 'libwav_plugin.dylib', + 'libxa_plugin.dylib', + 'libfolder_plugin.dylib', + 'libtaglib_plugin.dylib', + 'libaudioscrobbler_plugin.dylib', + 'libdummy_plugin.dylib', + 'libexport_plugin.dylib', + 'libfreetype_plugin.dylib', + 'libgnutls_plugin.dylib', + 'liblogger_plugin.dylib', + 'liblua_plugin.dylib', + 'libosd_parser_plugin.dylib', + 'libquartztext_plugin.dylib', + 'libstats_plugin.dylib', + 'libvod_rtsp_plugin.dylib', + 'libxml_plugin.dylib', + #'libxtag_plugin.dylib', + 'libi420_rgb_mmx_plugin.dylib', + 'libi420_yuy2_mmx_plugin.dylib', + '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', + 'libstream_filter_record_plugin.dylib', + 'libvisual_plugin.dylib', ] VLC_SEARCH_PATH=[ @@ -203,10 +203,20 @@ TOMAHAWK_PLUGINS = [ 'libtomahawk_account_google.so', 'libtomahawk_account_twitter.so', 'libtomahawk_account_zeroconf.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_spotify.so', ] QT_PLUGINS_SEARCH_PATH=[ - '/usr/local/Cellar/qt/4.7.4/plugins', + '/usr/local/Cellar/qt/4.8.2/plugins', ] @@ -249,7 +259,7 @@ frameworks_dir = os.path.join(bundle_dir, 'Contents', 'Frameworks') commands.append(['mkdir', '-p', frameworks_dir]) resources_dir = os.path.join(bundle_dir, 'Contents', 'Resources') commands.append(['mkdir', '-p', resources_dir]) -plugins_dir = os.path.join(bundle_dir, 'Contents', 'PlugIns') +plugins_dir = os.path.join(bundle_dir, 'Contents', 'qt-plugins') binary = os.path.join(bundle_dir, 'Contents', 'MacOS', bundle_name) fixed_libraries = [] @@ -363,8 +373,7 @@ def FixVLCPlugin(abs_path, subdir): FixAllLibraries(broken_libs) #print "Copying plugin....%s %s %s" % (plugins_dir, subdir, os.path.join(abs_path.split('/')[-2:])) - plugindir = abs_path.split('/')[-2] - new_path = os.path.join(plugins_dir, subdir, plugindir, os.path.basename(abs_path)) + new_path = os.path.join(plugins_dir, subdir, os.path.basename(abs_path)) args = ['mkdir', '-p', os.path.dirname(new_path)] commands.append(args) args = ['ditto', '--arch=i386', '--arch=x86_64', abs_path, new_path] @@ -490,7 +499,7 @@ def FindVLCPlugin(name): FixBinary(binary) for plugin in VLC_PLUGINS: - FixVLCPlugin(FindVLCPlugin(plugin), '../Frameworks/vlc/plugins') + FixVLCPlugin(FindVLCPlugin(plugin), '../plugins') for plugin in TOMAHAWK_PLUGINS: FixPlugin(plugin, '../MacOS') diff --git a/admin/mac/qt.conf b/admin/mac/qt.conf index 64d729736..d0e7835ac 100644 --- a/admin/mac/qt.conf +++ b/admin/mac/qt.conf @@ -1,2 +1,2 @@ [Paths] -Plugins = PlugIns +Plugins = qt-plugins diff --git a/data/icons/tomahawk-icon-128x128-grayscale.png b/data/icons/tomahawk-icon-128x128-grayscale.png index 550781596..f9daadb33 100644 Binary files a/data/icons/tomahawk-icon-128x128-grayscale.png and b/data/icons/tomahawk-icon-128x128-grayscale.png differ diff --git a/data/icons/tomahawk-icon-128x128.png b/data/icons/tomahawk-icon-128x128.png index bbee6eb80..4701db23a 100644 Binary files a/data/icons/tomahawk-icon-128x128.png and b/data/icons/tomahawk-icon-128x128.png differ diff --git a/data/icons/tomahawk-icon-16x16.png b/data/icons/tomahawk-icon-16x16.png index cd5709e6b..8d2cd8589 100644 Binary files a/data/icons/tomahawk-icon-16x16.png and b/data/icons/tomahawk-icon-16x16.png differ diff --git a/data/icons/tomahawk-icon-256x256.png b/data/icons/tomahawk-icon-256x256.png index 227abc838..559067acd 100644 Binary files a/data/icons/tomahawk-icon-256x256.png and b/data/icons/tomahawk-icon-256x256.png differ diff --git a/data/icons/tomahawk-icon-32x32.png b/data/icons/tomahawk-icon-32x32.png index 396e3f8fa..952151ba2 100644 Binary files a/data/icons/tomahawk-icon-32x32.png and b/data/icons/tomahawk-icon-32x32.png differ diff --git a/data/icons/tomahawk-icon-512x512.png b/data/icons/tomahawk-icon-512x512.png index e42d30e85..14db6cbc3 100644 Binary files a/data/icons/tomahawk-icon-512x512.png and b/data/icons/tomahawk-icon-512x512.png differ diff --git a/data/icons/tomahawk-icon-64x64.png b/data/icons/tomahawk-icon-64x64.png index d8b278ce5..e27712df7 100644 Binary files a/data/icons/tomahawk-icon-64x64.png and b/data/icons/tomahawk-icon-64x64.png differ diff --git a/data/icons/tomahawk-icon.svg b/data/icons/tomahawk-icon.svg index 49f1a86b5..05b80614d 100644 --- a/data/icons/tomahawk-icon.svg +++ b/data/icons/tomahawk-icon.svg @@ -1,304 +1,80 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + +image/svg+xml + + + + + + + \ No newline at end of file diff --git a/data/images/scrollbar-horizontal-handle.png b/data/images/scrollbar-horizontal-handle.png new file mode 100644 index 000000000..3589d64a4 Binary files /dev/null and b/data/images/scrollbar-horizontal-handle.png differ diff --git a/data/images/scrollbar-vertical-handle.png b/data/images/scrollbar-vertical-handle.png new file mode 100644 index 000000000..2676d365d Binary files /dev/null and b/data/images/scrollbar-vertical-handle.png differ diff --git a/data/images/track-icon-sidebar.png b/data/images/track-icon-sidebar.png new file mode 100644 index 000000000..b579f957c Binary files /dev/null and b/data/images/track-icon-sidebar.png differ diff --git a/data/images/track-placeholder.png b/data/images/track-placeholder.png index 2851e5b3f..333ea9101 100644 Binary files a/data/images/track-placeholder.png and b/data/images/track-placeholder.png differ diff --git a/data/www/auth.html b/data/www/auth.html index cdfba330d..d1193ee5d 100644 --- a/data/www/auth.html +++ b/data/www/auth.html @@ -43,8 +43,8 @@ - - Tomahawk - Powered by Playdar + + Tomahawk - Powered by Playdar
diff --git a/data/www/auth.na.html b/data/www/auth.na.html index d1b816572..ee4463d5b 100644 --- a/data/www/auth.na.html +++ b/data/www/auth.na.html @@ -32,8 +32,8 @@ - - Tomahawk - Powered by Playdar + + Tomahawk - Powered by Playdar
diff --git a/data/www/tomahawk_banner_small.png b/data/www/tomahawk_banner_small.png index 83a818d17..67fc8b4cb 100644 Binary files a/data/www/tomahawk_banner_small.png and b/data/www/tomahawk_banner_small.png differ diff --git a/lang/tomahawk_ar.ts b/lang/tomahawk_ar.ts index c8d84f64b..db68a1516 100644 --- a/lang/tomahawk_ar.ts +++ b/lang/tomahawk_ar.ts @@ -2,17 +2,17 @@ AccountFactoryWrapper - + Dialog حوار - + Description goes here أضف الوصف هنا - + Add Account أضف حساب @@ -20,19 +20,19 @@ AccountFactoryWrapperDelegate - + Online - على الهواء + متصل - + Connecting... - يجرى الاتصال... + جاري الاتصال... - + Offline - خارج الهواء + غير متصل @@ -40,14 +40,15 @@ Error displaying ACL info - + خطأ في عرض معلومات ACL Allow %1 to connect and stream from you? - + هل تسمح ل %1 +بالربط بك ومشاركة أغانيك ؟ @@ -55,12 +56,12 @@ connect and stream from you? &Listen Along - ظاهرة + &استمع مع Stop &Listening Along - توقيف &متابعة الإستماع + توقيف &الاستماع مع @@ -133,7 +134,17 @@ connect and stream from you? ألبومات أخرى للفنان - + + Sorry, we could not find any other albums for this artist! + نعتذر, لم نستطيع إيجاد ألبومات أخرى لهذا الفنان! + + + + Sorry, we could not find any tracks for this album! + نعتذر، لم نستطيع إيجاد أغاني أخرى لهذا الألبوم! + + + Other Albums by %1 ألبومات أخرى ل%1 @@ -141,35 +152,17 @@ connect and stream from you? AlbumModel - - Album - البوم - - - - + + All albums from %1 جميع الألبومات من %1 - + All albums جميع الألبومات - - AlbumView - - - After you have scanned your music collection you will find your latest album additions right here. - بعد إجراء مسح مجموعة أغانيك الخاصة ستجد ألبوماتك المضافة هنا. - - - - This collection doesn't have any recent albums. - هذه المجموعة لا تحتوي على ألبومات جديدة. - - ArtistInfoWidget @@ -178,12 +171,12 @@ connect and stream from you? استمارة - + Top Hits الأكثر شهرة - + Related Artists الفنانين ذات الذوق القريب @@ -192,23 +185,25 @@ connect and stream from you? Albums ألبومات - - - ArtistView - - After you have scanned your music collection you will find your tracks right here. - بعد إجراء مسح مجموعة أغانيك الخاصة ستجد أغانيك هنا. + + Cover + - - This collection is currently empty. - المجموعة فارغة حاليا. + + Sorry, we could not find any albums for this artist! + نعتذر, لم نستطيع إيجاد ألبومات أخرى لهذا الفنان! - - Sorry, your filter '%1' did not match any results. - نتأسف، نظام البحث لم يجد شيئا تحت عنوان '%1'. + + Sorry, we could not find any related artists! + نعتذر، لم نستطيع إيجاد فنانين! + + + + Sorry, we could not find any top hits for this artist! + نعتذر، لم نستطيع إيجاد أغاني مشهورة جدا لهذا الفنان! @@ -221,7 +216,7 @@ connect and stream from you? Play - إستماع + إستمع @@ -234,57 +229,57 @@ connect and stream from you? التالي - + Artist - الفنان + فنان - + Album البوم - + Owner المالك - + social - + اجتماعي - + love أحب - + Time الوقت - + Time Left الوقت المتبقي - + Shuffle خلط - + Repeat إعادة - + Low منخفض - + High مرتفع @@ -293,22 +288,25 @@ connect and stream from you? CategoryAddItem - - New Playlist - خلق قائمة أغاني جديدة + Create new Playlist + إنشاء قائمة أغاني جديدة - - - - + + Create new Station + إنشاء إذاعة جديدة + + + + + New Station - خلق إذاعة جديدة + إنشاء إذاعة جديدة - - - + + + %1 Station إذاعة %1 @@ -331,28 +329,7 @@ connect and stream from you? Clear - حذف - - - - CollectionFlatModel - - - My Collection - مجموعتي الخاصة - - - - Collection of %1 - مجموعة %1 - - - - CollectionView - - - This collection is empty. - هذه المجموعة فارغة. + مسح @@ -364,12 +341,12 @@ connect and stream from you? - + Show Footnotes أظهر الحاشية - + Hide Footnotes إخفي الحاشية @@ -383,23 +360,23 @@ connect and stream from you? - <html><head/><body><p><span style=" font-weight:600;">Sorry!</span> Tomahawk crashed. Please tell us about it! Tomahawk has created an error report for you that can help improve the stability in the future. You can now send the this report directly to the Tomahawk developers.</p></body></html> - + <html><head/><body><p><span style=" font-weight:600;">Sorry!</span> Tomahawk crashed. Please tell us about it! Tomahawk 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 Tomahawk developers.</p></body></html> + <html><head/><body><p><span style=" font-weight:600;">نتأسف!</span>&nbsp;توماهوك تحطم. يرجى أن تخبرنا عن ذلك! لقد أنشئ توماهوك تقرير عن الخطأ نيابة عنك لمساعدتنا في تحسين استقرار البرنامج في المستقبل. يمكنك إرسال هذا التقرير الأن مباشرة لمطوري توماهوك.</p></body></html> Send this report - + أرسل هذا التقرير Don't send - + لا ترسل Abort - اجهاض + الغاء @@ -409,13 +386,13 @@ connect and stream from you? Uploaded %L1 of %L2 KB. - + تحميل %L1 من أصل %L2 كيلو بايت. Close - غلق + اغلاق @@ -439,17 +416,17 @@ connect and stream from you? DelegateConfigWrapper - + About - + عن - + Delete Account حذف الحساب - + About this Account عن هذا الحساب @@ -462,24 +439,11 @@ connect and stream from you? تشخيص توماهوك - - Update - تحديث - - - + Copy to Clipboard نسخ إلى الحافظة - - DropJob - - - No tracks found for given %1 - لم يتم إيجاد أي أغاني ل%1 - - GlobalSearchWidget @@ -504,56 +468,43 @@ connect and stream from you? InfoBar - + Filter... - فلتر... - - - - JobStatusView - - - Searching For - تفتيش عن - - - - Pending - انتظار - - - - Idle - عاطلة + مرشح... LastFmConfig - + Form استمارة - + Scrobble tracks to Last.fm نقل الأغاني إلى Last.fm - + Username: اسم المستخدم: - + Password: كلمة السر: - + Test Login اختبار الدخول + + + Import Playback History + استيراد تاريخ إعادة الإستماع + LastfmContext @@ -635,7 +586,7 @@ connect and stream from you? Tomahawk offers a variety of ways to help you create playlists and find music you enjoy! - توماهوك يقدم مجموعة متنوعة من الطرق اللتي تساعدك على خلق قوائم أغاني و إيجاد الموسيقى اللتي تستمتع إليها! + توماهوك يقدم مجموعة متنوعة من الطرق اللتي تساعدك على إنشاء قوائم أغاني و إيجاد الموسيقى اللتي تستمتع إليها! @@ -645,20 +596,89 @@ connect and stream from you? &Create Playlist - &خلق قائمة أغاني + &إنشاء قائمة أغاني Create a new playlist - خلق قائمة أغاني جديدة + إنشاء قائمة أغاني جديدة NewReleasesWidget - + New Releases - + جديد الاصدارات + + + + PlayableModel + + + Artist + فنان + + + + Title + عنوان + + + + Composer + مؤلف + + + + Album + البوم + + + + Track + اغنية + + + + Duration + مدة + + + + Bitrate + معدل البت + + + + Age + عمر + + + + Year + سنة + + + + Size + حجم + + + + Origin + أصل + + + + Score + علامة + + + + + Name + إسم @@ -666,28 +686,28 @@ connect and stream from you? played %1 by you - + سمعت %1 played %1 by %2 - + %2 سمع %1 PlaylistLargeItemDelegate - + played %1 by you - + سمعت %1 - + played %1 by %2 - + %2 سمع %1 - + added %1 إضافة %1 @@ -695,12 +715,12 @@ connect and stream from you? PlaylistModel - + A playlist by %1, created %2 - + قائمة أغاني من قبل %1, أنشئت %2 - + you أنت @@ -745,18 +765,23 @@ connect and stream from you? Create Manual Playlist - خلق قائمة أغاني جديدة يدويا + إنشاء قائمة أغاني جديدة يدويا Create Automatic Playlist - خلق قائمة أغاني جديدة تلقائيا + إنشاء قائمة أغاني جديدة أوتوماتيكية PlaylistView - + + This playlist is currently empty. + هذه المجموعة فارغة حاليا. + + + This playlist is currently empty. Add some tracks to it and enjoy the music! هذه القائمة فارغة حاليا. أضف لها بعض الأغاني واستمتع للموسيقى! @@ -808,7 +833,8 @@ connect and stream from you? No Proxy Hosts: (Overrides system proxy) - + لا مضيف للوكيل: +(تجاوز وكيل النظام) @@ -818,73 +844,73 @@ connect and stream from you? Use proxy for DNS lookups? - + استخدام ألوكيل لعمليات البحث عن ألدي أن أس (DNS ) ؟ QObject - + %n year(s) ago - + منذ %n سنةمنذ سنة %nمنذ سنتين %nمنذ %n سنواتمنذ %n سنواتمنذ %n سنوات - + %n year(s) - + منذ %n سنةمنذ سنة %nمنذ سنتين %nمنذ %n سنواتمنذ %n سنواتمنذ %n سنوات - + %n month(s) ago - + منذ %n شهرمنذ شهر %nمنذ شهرين %nمنذ %n أشهرمنذ %n أشهرمنذ %n أشهر - + %n month(s) - + منذ %n شهرمنذ شهر %nمنذ شهرين %nمنذ %n أشهرمنذ %n أشهرمنذ %n أشهر - + %n week(s) ago - + منذ %n أسبوعمنذ أسبوع %nمنذ أسبوعين %nمنذ %n أسابيعمنذ %n أسابيعمنذ %n أسابيع - + %n week(s) - + منذ %n أسبوعمنذ أسبوع %nمنذ أسبوعين %nمنذ %n أسابيعمنذ %n أسابيعمنذ %n أسابيع - + %n day(s) ago - + منذ %n يوممنذ يوم %nمنذ يومين %nمنذ %n أياممنذ %n أياممنذ %n أيام - + %n day(s) - + منذ %n يوممنذ يوم %nمنذ يومين %nمنذ %n أياممنذ %n أياممنذ %n أيام - + %n hour(s) ago - + منذ %n ساعةمنذ ساعة %nمنذ ساعتين %nمنذ %n ساعاتمنذ %n ساعاتمنذ %n ساعات - + %n hour(s) - + منذ %n ساعةمنذ ساعة %nمنذ ساعتين %nمنذ %n ساعاتمنذ %n ساعاتمنذ %n ساعات - + %1 minutes ago منذ %1 دقائق - + %1 minutes %1 دقائق - + just now الآن @@ -901,7 +927,7 @@ connect and stream from you? Status Updaters - + أنظمة تحديث حالتك @@ -909,7 +935,7 @@ connect and stream from you? ZIP/UNZIP API error %1 - + مشكلة %1 في "ZIP/UNZIP API" @@ -921,20 +947,25 @@ connect and stream from you? - - Show Queue - أظهر قائمة الانتظار + + Open Queue + إفتح قائمة الإنتظار + + + + Open Queue - %n item(s) + إفتح قائمة الإنتظار - %n بندإفتح قائمة الإنتظار - بند %nإفتح قائمة الإنتظار - بندين %nإفتح قائمة الإنتظار - %n بنودإفتح قائمة الإنتظار - %n بنودإفتح قائمة الإنتظار - %n بنود - - Hide Queue - إخفي قائمة الانتظار + + Close Queue + أغلق قائمة الإنتظار RelatedArtistsContext - + Related Artists الفنانين ذات الذوق القريب @@ -944,12 +975,12 @@ connect and stream from you? Not found: %1 - + لم يوجد: %1 Failed to load: %1 - + فشل في تحميل: %1 @@ -970,7 +1001,7 @@ connect and stream from you? Results for '%1' - + نتائج البحث عن '%1' @@ -993,7 +1024,7 @@ connect and stream from you? Some changed settings will not take effect until Tomahawk is restarted - + بعض الإعدادات التي تم تغييرها لن تصبح نافذة المفعول حتى يتم إعادة تشغيل توماهوك @@ -1003,7 +1034,7 @@ connect and stream from you? Install resolver from file - + تثبيت محلل من ملف @@ -1021,12 +1052,12 @@ connect and stream from you? Most Played Playlists - + قوائم الأغاني التي سمعت كثيرا Most Played Tracks You Don't Have - + الأغاني التي سمعت كثيرا و التي ليست موجودة لديك @@ -1039,37 +1070,42 @@ connect and stream from you? Facebook - + فيسبوك (Facebook) Twitter - + تويتر (Twitter) Cover - + غلاف TextLabel - + TextLabel - - Listening to "%1" by %2 and loving it! %3 - + + Tweet + تويت (Tweet) - - Listening to "%1" by %2 on "%3" and loving it! %4 - + + Listening to "%1" by %2. %3 + إنني أستمع إلى "%1" من قبل %2. %3 - + + Listening to "%1" by %2 on "%3". %4 + إنني أستمع إلى "%1" من قبل %2 على "%3". %4 + + + %1 characters left - + تبقى %1 حروف @@ -1087,7 +1123,7 @@ connect and stream from you? Artist - الفنان + فنان @@ -1097,32 +1133,22 @@ connect and stream from you? Top 10 - + توب ١٠ - - Offline - خارج الهواء - - - + All available tracks جميع الأغاني المتاحة - - Online - على الهواء - - - - + + Show أظهر - - + + Hide إخفي @@ -1137,7 +1163,7 @@ connect and stream from you? Latest Additions - + الإضافة الأخيرة @@ -1145,101 +1171,158 @@ connect and stream from you? الأغاني التي إستمعت إليها مؤخرا - + New Additions - + الإضافة الجديدة - + My recent activity - + نشاطاتي الأخيرة - + Recent activity from %1 - + النشاطات المؤخرة ل %1 SourceItem - + Collection مجموعة - - + + Latest Additions أحدث الإضافات - + Recently Played - + تم الاستماع لها مؤخرا - + Loved Tracks الأغاني المحبوبة - + SuperCollection - + سوبر كولكشن - + + Sorry, we could not find any loved tracks! + نعتذر، لم نستطيع إيجاد أغاني محبوبة! + + + Latest additions to your collection - + آخر إضافات على مجموعتك - + Latest additions to %1's collection - + آخر إضافات على مجموعة %1 - + + Sorry, we could not find any recent additions! + نعتذر، لم نستطيع إيجاد إضافة جديدة! + + + Recently Played Tracks الأغاني التي إستمعت إليها مؤخرا - + Your recently played tracks - + الأغاني التي إستمعت إليها مؤخرا - + %1's recently played tracks - + الأغاني التي سمعها مؤخرا %1 + + + + Sorry, we could not find any recent plays! + نعتذر، لم نستطيع إيجاد أغاني مسموعة مؤخرا! SourceTreeView - + &Copy Link &نسخ الرابط - + &Delete %1 - + &أحذف %1 - + + Add to my Playlists + أضف إلى لوائحي للأغاني + + + + Add to my Automatic Playlists + أضف إلى لوائحي الأوتوماتيكية للأغاني + + + + Add to my Stations + أضف إلى إذاعاتي + + + &Export Playlist - + &تصدير قائمة الأغاني - + + playlist + قائمة الأغاني + + + + automatic playlist + قائمة أغاني أوتوماتيكية + + + + station + إذاعة + + + + Delete %1? + playlist/station/... + أحذف %1؟ + + + + Would you like to delete the %1 <b>"%2"</b>? + e.g. Would you like to delete the playlist named Foobar? + هل ترغب في حذف %1 <b>"%2"</b>؟ + + + Save XSPF حفظ XSPF - + Playlists (*.xspf) - + قوائم أغاني (*.xspf) @@ -1262,7 +1345,7 @@ connect and stream from you? Automatic Playlist - + قائمة أغاني أوتوماتيكية @@ -1270,52 +1353,52 @@ connect and stream from you? إذاعة - + Browse تصفح - + Search History تاريخ البحث - + My Music - + موسيقتي الخاصة - + SuperCollection - + سوبر كولكشن - + Top Loved Tracks الأغاني المحبوبة الأكثر شهرة - + Dashboard - + لوحة القيادة - + Recently Played - تم الإستماع مؤخرا + تم الاستماع لها مؤخرا - + Charts الرسوم البيانية - + New Releases - + جديد الاصدارات - + Friends الأصدقاء @@ -1323,52 +1406,52 @@ connect and stream from you? SpotifyConfig - + Form استمارة - + Configure your Spotify account تكوين حساب "Spotify" - + Username or Facebook Email إسم المستخدم أو الايميل على فيسبوك (Facebook Email) - + Log In - + تسجيل الدخول - + Right click on any Tomahawk playlist to sync it to Spotify. - + أنقر يمينا على أية قائمة أغاني في توماهوك للمزامنة مع سبوتيفي (Spotify). - + High Quality Streams - + جودة عالية في الأغاني المحملة - + Spotify playlists to keep in sync: - + قوائم أغاني سبوتيفي (Spotify) التي يجب إبقائها بتزامن: - + Delete Tomahawk playlist when removing synchronization - + حذف قوائم أغاني توماهوك عند إزالة التزام - + Username: اسم المستخدم: - + Password: كلمة السر: @@ -1376,14 +1459,14 @@ connect and stream from you? SpotifyPlaylistUpdater - + Delete in Spotify? - + أحذف في سبوتيفي (Spotify)؟ - + Would you like to delete the corresponding Spotify playlist as well? - + هل ترغب في حذف قائمة التشغيل المطابقة على سبوتيفي (Spotify)؟ @@ -1401,7 +1484,7 @@ connect and stream from you? Path to scan for music files: - + ماسار لتفحص ملفات الموسيقى: @@ -1409,7 +1492,9 @@ connect and stream from you? and using it to craft personalized radios. Enabling this option will allow you (and all your friends) to create automatic playlists and stations based on your personal taste profile. - + "The Echo Nest" يدعم إبقاء مسار فوقية فهرسك واستخدامه + لصياغة إذاعات شخصية. تمكين هذا الخيار يسمح لك (و لأصدقائك) +إنشاء قوائم أغاني أوتوماتيكيا و إذاعات حسب ذوقك الشخصي. @@ -1419,87 +1504,87 @@ connect and stream from you? Watch for changes - + إنتبه للتغييرات Time between scans, in seconds: - + الوقت بين المسوحات، بالثواني: Advanced Settings - + إعدادات متقدمة Remote Peer Connection Method - + طريقة الاتصال بالند البعيد None (outgoing connections only) - + لا شيء (الاتصالات الصادرة فقط) Use UPnP to establish port forward (recommended) - + استخدم عمل UPnP لإنشاء بوابة إعادة التوجيه (موصى به) Use static external IP address/host name and port - + استخدم عنوان/مضيف ايب (IP) و بوابة ثابتين Set this to your external IP address or host name. Make sure to forward the port to this host! - + عين هذا إلى عنوان الايب الخارجي (External IP) الخاص بك أو اسم المضيف. تأكد من إحالة البوابة إلى هذا المضيف! SOCKS Proxy - + سوكس الوكيل Use SOCKS Proxy - + استخدم سوكس الوكيل Internet Services - + خدمات الانترنت Install from file... - + تثبيت من ملف... Filter by capability: - + ترشيح حسب القدرة: Static Host Name: - + اسم مضيف ثابت: Static Port: - + بوابة ثابتة: Proxy Settings... - + إعدادات الوسيط... Other Settings - + إعدادات أخرى @@ -1509,53 +1594,53 @@ connect and stream from you? Allow web browsers to interact with Tomahawk (recommended) - + السماح لمحرك البحث بالتفاعل مع توماهوك (موصى به) Tomahawk::Accounts::AccountDelegate - + Add Account أضف حساب - - Remove Account - حذف الحساب + + Remove + إزالة - + %1 downloads - + تحميل %1 - + Online - على الهواء + متصل - + Connecting... - + جاري الاتصال... - + Offline - خارج الهواء + غير متصل Tomahawk::Accounts::AccountModel - + Manual Install Required - + مطلوب تثبيت يدوي - - Unfortunately, automatic installation of this resolver is not yet available on Linux.<br /><br />Please use "Install from file" above, by fetching it from your distribution or compiling it yourself. Further instructions can be found here:<br /><br />http://www.tomahawk-player.org/resolvers/%1 - + + Unfortunately, automatic installation of this resolver is not available or disabled for your platform.<br /><br />Please use "Install from file" above, by fetching it from your distribution or compiling it yourself. Further instructions can be found here:<br /><br />http://www.tomahawk-player.org/resolvers/%1 + لسوء الحظ، التثبيت التلقائي لهذا المحلل لم يتوفر بعد على منصتك. <br /><br /> الرجاء إستخدام " التثبيت من الملف" أعلاه، بواسطة جلبه من توزيعتك أو تجميعه بنفسك. ويمكن الاطلاع على مزيد من التعليمات هنا: <br /><br />http://www.tomahawk-player.org/resolvers/%1 @@ -1568,7 +1653,7 @@ connect and stream from you? Google Address - + الحساب الخاص بجوجل (Google) @@ -1586,7 +1671,7 @@ connect and stream from you? Connect to Google Talk to find your friends - + تواصل مع جوجل توك (Google Talk) لإيجاد أصدقائك @@ -1594,88 +1679,119 @@ connect and stream from you? Add Friend - + أضف صديق Enter Google Address: - + أدخل الحساب الخاص بجوجل (Google): Tomahawk::Accounts::LastFmAccountFactory - + Scrobble your tracks to last.fm, and find freely downloadable tracks to play - + إبعث أغانيك الخاصة إلى last .fm و جد أغاني جديدة مجانا للاستماع إليها Tomahawk::Accounts::LastFmConfig - + + Testing... + اختبار... + + + Test Login اختبار الدخول - - + + Importing %1 + e.g. Importing 2012/01/01 + استيراد %1 + + + + Importing History... + نقل التاريخ... + + + + History Incomplete. Resume + تاريخ ناقص. استأنف + + + + Playback History Imported + تم استيراد تاريخ إعادة الإستماع + + + + Failed - + فشلت - + Success - + نجاح - + Could not contact server - + لم أستطيع الإتصال بالخادم Tomahawk::Accounts::SpotifyAccount - + Sync with Spotify - + مزامنة مع سبوتيفي (Spotify) - + + Re-enable syncing with Spotify + إعادة تمكين المزامنة مع سبوتيفي (Spotify) + + + Stop syncing with Spotify - + أوقف المزامنة مع سبوتيفي (Spotify) Tomahawk::Accounts::SpotifyAccountConfig - + Logging in... - + جاري تسجيل الدخول... - + Logged in! - + مسجل! - + Failed: %1 - + فشل: %1 - + Log In - + تسجيل الدخول Tomahawk::Accounts::SpotifyAccountFactory - + Play music from and sync your playlists with Spotify Premium - + إسمع موسيقى و زامن قوائم تشغيلك مع سبوتيفي بريميوم (Spotify Premium) @@ -1683,7 +1799,7 @@ connect and stream from you? Connect to your Twitter followers. - + تواصل مع أصدقائك على تويتر (Twitter). @@ -1693,32 +1809,32 @@ connect and stream from you? Tweet! - + تويت (Tweet)! Status: No saved credentials - + الحالة: بيانات غير محفوظة Authenticate - + صادق Status: Credentials saved for %1 - + الحالة: بيانات %1 حفظت De-authenticate - + قطع المصادقة @@ -1729,43 +1845,44 @@ connect and stream from you? Tweetin' Error - + خطأ توتينغ ('Tweetin) The credentials could not be verified. You may wish to try re-authenticating. - + لم نستطيع التحقق من صحة البيانات. +قد ترغب بإعادة المصادقة. Status: Error validating credentials - + الحالة: خطأ في التحقق من صحة البيانات Global Tweet - + تويت شامل (Global Tweet) Direct Message - + رسالة مباشرة Send Message! - + إرسل رسالة! @Mention - + @ذكر Send Mention! - + إرسال ذكر! @@ -1776,40 +1893,42 @@ You may wish to try re-authenticating. Your saved credentials could not be loaded. You may wish to try re-authenticating. - + لم نستطيع تحميل بياناتك المحفوظة. +قد ترغب بمعاودة التصديق. Your saved credentials could not be verified. You may wish to try re-authenticating. - + لم نستطيع التحقق من بياناتك المحفوظة. +قد ترغب بمعاودة التصديق. There was an error posting your status -- sorry! - + عذراً... حصل خطأ في تسجيل رسالتك! Tweeted! - + ثبت التويت! (!Tweeted) Your tweet has been posted! - + رسالتك على تويتر قد نشرت! There was an error posting your direct message -- sorry! - + نعتذر، حصل خطأ في نشر رسالتك المباشرة ! Your message has been posted! - + رسالتك قد نشرت! @@ -1817,15 +1936,15 @@ You may wish to try re-authenticating. Log on to your Jabber/XMPP account to connect to your friends - + أدخل إلى حسابك على Jabber/XMPP للربط بأصدقائك Tomahawk::Accounts::ZeroconfFactory - + Automatically connect to Tomahawks on the local network - أربط نفسك بيتوماهاوك على الشبكة المحلية بطريقة مباشرة + أربط نفسك بتوماهاوك على الشبكة المحلية بطريقة مباشرة أوتوماتيكيا @@ -1833,63 +1952,63 @@ You may wish to try re-authenticating. &Play - + &إستمع - - + + Add to &Queue - + أضف إلى &قائمة الانتظار - + &Love - + &أحب - + &Copy Track Link &إنسخ رابط الأغنية - + Un-&Love - + لا &أحب - + &Delete Items - + &أحذف البنود &Continue Playback after this Track - + &أكمل الاستماع بعد هذه الأغنية &Stop Playback after this Track - + &أوقف الاستماع بعد هذه الأغنية - + &Show Track Page &أظهر صفحة الأغاني - + &Delete Item - + &أحذف البند - + &Show Album Page &أظهر صفحة الألبومات - + &Show Artist Page &أظهر صفحة الفنان @@ -1930,14 +2049,34 @@ You may wish to try re-authenticating. Tomahawk::DropJobNotifier - - Fetching %1 from database - + + playlist + قائمة الأغاني - + + artist + فنان + + + + track + اغنية + + + + album + البوم + + + + Fetching %1 from database + جلب %1 من قاعدة البيانات + + + Parsing %1 %2 - + تحليل %1 %2 @@ -1945,7 +2084,7 @@ You may wish to try re-authenticating. Click to collapse - + إضغط للتقليص @@ -1956,12 +2095,14 @@ You may wish to try re-authenticating. Could not find a playable track. Please change the filters or try again. - + لم يوجد أغنية للاستماع إليها. + +غير كلمة الترشيح وأعد الكرة. Failed to generate preview with the desired filters - + فشل في إيجاد عرض مسبق للبحث المطلوب @@ -1969,40 +2110,42 @@ Please change the filters or try again. Type: - + نوع: Generate - + توليد Tomahawk::DynamicView - + Add some filters above to seed this station! - + أدخل بعض الترشيحات أعلاه لتوزيع هذه الإذاعة! - + Press Generate to get started! - + إضغط "توليد" لتبدأ! - + Add some filters above, and press Generate to get started! - + أدخل بعض الترشيحات أعلاه ثم iضغط "توليد" لتبدأ! Tomahawk::DynamicWidget - + Station ran out of tracks! Try tweaking the filters for a new set of songs to play. - + الإذاعة فرغت من الأغاني! + +عدل في كلمة الترشيح لإيجاد مجموعة جديدة من الأغاني. @@ -2015,7 +2158,7 @@ Try tweaking the filters for a new set of songs to play. is - + هو @@ -2026,12 +2169,12 @@ Try tweaking the filters for a new set of songs to play. No users with Echo Nest Catalogs enabled. Try enabling option in Collection settings - لا يوجد مستخدمين مع فهرس "Echo Nest" ممكن. تجربة تمكين خيار المجموعة في الإعدادات يمكن أن يساعد. + لا يوجد مستخدمين مع فهرس "Echo Nest" ممكن. تجربة تمكين خيار المجموعة في الإعدادات يمكن أن يساعد similar to - + مشابهة ل @@ -2042,7 +2185,7 @@ Try tweaking the filters for a new set of songs to play. Less - + أقل @@ -2053,132 +2196,132 @@ Try tweaking the filters for a new set of songs to play. More - + أكثر 0 BPM - + ٠ نبضة في الدقيقة 500 BPM - + ٥٠٠ نبضة في الدقيقة 0 secs - + ٠ ثانية 3600 secs - + ٣٦٠٠ ثانية -100 dB - + -١٠٠ د.ب. 100 dB - + ١٠٠ د.ب. Major - + رئيسي Minor - + ثانوي C - + C C Sharp - + C Sharp D - + D E Flat - + E Flat E - + E F - + F F Sharp - + F Sharp G - + G A Flat - + A Flat A - + A B Flat - + B Flat B - + B Ascending - + تصاعدي Descending - + تنازلي Tempo - + سرعة إيقاع Duration - + مدة Loudness - + قوة الصوت @@ -2193,118 +2336,118 @@ Try tweaking the filters for a new set of songs to play. Song Hotttnesss - + شعبية الأغنية Latitude - + مدى Longitude - + طول Mode - + أسلوب Key - + مفتاح Energy - + حيوية Danceability - + القابلية للرقص only by ~%1 - + فقط من جانب ~%1 similar to ~%1 - + مشابهة ل%1 with genre ~%1 - + مع النوع ~%1 from no one - + من لا أحد My Collection - + مجموعتي الخاصة from %1 radio - + من إذاعة %1 with %1 %2 - + مع %1 %2 about %1 BPM - + حوالي %1 نبضة في الدقيقة about %n minute(s) long - + بطول حوالي %n دقائقبطول حوالي دقيقة %nبطول حوالي دقيقتين %nبطول حوالي %n دقائقبطول حوالي %n دقائقبطول حوالي %n دقائق about %1 dB - + حوالي %1 د.ب. at around %1%2 %3 - + في حوالي %1%2 %3 in %1 - + في %1 in a %1 key - + في المفتاح %1 sorted in %1 %2 order - + تم فرزها بالترتيب %1 %2 with a %1 mood - + في مزاج %1 in a %1 style - + في أسلوب %1 @@ -2312,97 +2455,97 @@ Try tweaking the filters for a new set of songs to play. Steer this station: - - - - - Much less - - - - - Less - - - - - A bit less - - - - - Keep at current - - - - - A bit more - - - - - More - - - - - Much more - + قد هذه الإذاعة: - Tempo - + Much less + أقل بكثير - Loudness - + Less + أقل - Danceability - + A bit less + أقل بقليل - Energy - + Keep at current + أبقه على حاله - Song Hotttnesss - + A bit more + أكثر قليلا + More + أكثر + + + + Much more + أكثر من ذلك بكثير + + + + Tempo + سرعة إيقاع + + + + Loudness + قوة الصوت + + + + Danceability + درجة الرقص + + + + Energy + حيوية + + + + Song Hotttnesss + شعبية الأغنية + + + Artist Hotttnesss شعبية الفنان - + Artist Familiarity ألفة الفنان - + By Description - + من خلال الوصف - + Enter a description - + أدخل الوصف - + Apply steering command - + طبق أوامر القيادة - + Reset all steering commands - + إعادة ضبط جميع أوامر القيادة @@ -2416,22 +2559,22 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::InfoSystem::ChartsPlugin - + Top Overall - + الأكثر شهرة بالإجمال - + Artists - الفنانين + فنانين - + Albums ألبومات - + Tracks أغاني @@ -2441,38 +2584,38 @@ Try tweaking the filters for a new set of songs to play. Tomahawk is playing "%1" by %2%3. - + توماهوك يلعب "%1" ل%2%3. on "%1" - + على "%1" Tomahawk::InfoSystem::LastFmInfoPlugin - + Top Tracks أفضل الأغاني - + Loved Tracks الأغاني المحبوبة - + Hyped Tracks فقت الأغاني - + Top Artists - أهم الفنانين + أفضل الفنانين - + Hyped Artists فقت الفنانين @@ -2480,7 +2623,7 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::InfoSystem::NewReleasesPlugin - + Albums ألبومات @@ -2488,9 +2631,9 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::InfoSystem::TwitterInfoPlugin - + Listening to "%1" by %2 and loving it! %3 - + إنني أستمع إلى "%1" من قبل %2 وقد أحببتها! %3 @@ -2506,7 +2649,7 @@ Try tweaking the filters for a new set of songs to play. New Playlist - + قائمة أغاني جديدة @@ -2516,17 +2659,17 @@ Try tweaking the filters for a new set of songs to play. Some tracks in the playlist do not contain an artist and a title. They will be ignored. - + بعض الأغاني في قائمة التشغيل لا تحتوي على إسم الفنان أو إسم الأغنية. هذه الأغاني سوف تتجاهل. XSPF Error - + خطأ XSPF This is not a valid XSPF playlist. - + قائمة الأغاني XSPF هذه ليست صالحة. @@ -2534,49 +2677,49 @@ Try tweaking the filters for a new set of songs to play. &Catch Up - + &إلحق &Listen Along - + &استمع مع Tomahawk::Query - + and - + و + + + + You + أنت + + + + you + أنت + + + + and + و + + + + %n other(s) + %n أخرين%n أخر%n أخرين%n أخرين%n أخرين%n أخرين - You - + %1 people + %1 أشخاص - you - - - - - and - - - - - %n other(s) - - - - - %1 people - - - - loved this track أحببت هذه الأغنية @@ -2592,43 +2735,53 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::ShortenedLinkParser - + Network error parsing shortened link! - + خطأ شبكة في تحليل تقصير الرابط! Tomahawk::Source - - + + Scanning (%L1 tracks) - + يجري مسح (%L1 أغنية) - + Scanning - + مسح - + Checking - + فحص - + Fetching - + جلب - + Parsing - + تحليل - + Saving (%1%) - + تحفيظ(%1%) + + + + Online + متصل + + + + Offline + غير متصل @@ -2644,15 +2797,15 @@ Try tweaking the filters for a new set of songs to play. Automatically update from XSPF - + تحديث تلقائي (أوتوماتيكيا) من XSPF TomahawkApp - + My Collection - + مجموعتي الخاصة @@ -2660,53 +2813,63 @@ Try tweaking the filters for a new set of songs to play. Twitter PIN - + رقم البن لتويتر (Twitter Pin) After authenticating on Twitter's web site, enter the displayed PIN number here: - + بعد المصادقة على موقع تويتر (Twitter)، +أدخل رقم البين (PIN) الموجود أمامك على الشاشة هنا: TomahawkTrayIcon - - + &Stop Playback after current Track - + &أوقف الاستماع بعد الأغنية الحالية - - + + Hide Tomahawk Window إخفي نافذة توماهوك - + Show Tomahawk Window أظهر نافذة توماهوك - + Currently not playing. - + لا يتم الاستماع حاليا. - + Play - + إستمع - + Pause - + تعليق - + + &Love + &أحب + + + + Un-&Love + لا &أحب + + + &Continue Playback after current Track - + &أكمل الاستماع بعد الأغنية الحالية @@ -2719,57 +2882,57 @@ enter the displayed PIN number here: &Settings - + &إعدادات &Controls - + &ضوابط &Network - + &شبكة &Window - + &نافذة &Help - + &مساعدة &Quit - + &إنهاء Ctrl+Q - + Ctrl+Q Go &Online - إذهب &على الهواء + اصبح &متصل Add &Friend... - + أضف &صديق... U&pdate Collection - + &تحديث المجموعة Update Collection - + تحديث المجموعة @@ -2779,12 +2942,12 @@ enter the displayed PIN number here: Load &XSPF... - + تحميل XSPF&... Create &New Playlist... - + إنشاء &قائمة أغاني جديدة... @@ -2794,42 +2957,42 @@ enter the displayed PIN number here: Create New &Automatic Playlist - + إنشاء قائمة أغاني جديدة أ&وتوماتيكيا Create New &Station - + إنشاء &قائمة أغاني جديدة Show Offline Sources - أظهر مصادر خارج الهواء + أظهر المصادر الغير متصلة Hide Offline Sources - إخفي مصادر خارج الهواء + إخفي المصادر الغير متصلة Minimize - + خفض Ctrl+M - + Ctrl+M Zoom - + زوم Meta+Ctrl+Z - + Meta+Ctrl+Z @@ -2839,191 +3002,201 @@ enter the displayed PIN number here: Fully &Rescan Collection - + إعادة &مسح المجموعة كاملة Fully Rescan Collection - + إعادة مسح المجموعة كاملة - + Play - + إستمع Space - + مساحة Previous - + سابق Next - - - - - Back - - - - - Go back one page - - - - - Forward - - - - - Go forward one page - + التالي + Back + إلى الوراء + + + + Go back one page + العودة صفحة واحدة إلى الوراء + + + + Forward + تقدم + + + + Go forward one page + تقدم صفحة واحدة + + + Global Search... - + بحث شامل... - - + + Check For Updates... - + التحقق من التحديثات... - - - + + + Connect To Peer - + ربط بالند - + Enter peer address: - + أدخل عنوان الند: - + Enter peer port: - + أدخل بوابة الند: - + Enter peer key: - + أدخل مفتاح الند: - + XSPF Error - + خطأ XSPF - + This is not a valid XSPF playlist. - + قائمة الأغاني XSPF هذه ليست صالحة. - + Failed to save tracks فشل في حفظ الأغاني - + Some tracks in the playlist do not contain an artist and a title. They will be ignored. - + بعض الأغاني في قائمة الأغاني لا تحتوي على إسم الفنان أو إسم الأغنية. هذه الأغاني سوف تتجاهل. - + Sorry, there is a problem accessing your audio device or the desired track, current track will be skipped. Make sure you have a suitable Phonon backend and required plugins installed. - + عذرا، هناك مشكلة في الوصول إلى جهاز الصوت أو الأغنية المطلوب، سوف يتم تخطي الأغنية الحالية. تأكد أن لديك خلفية فونون المناسبة والإضافات المطلوبة مثبتة. - + Sorry, there is a problem accessing your audio device or the desired track, current track will be skipped. - + عذرا، هناك مشكلة في الوصول إلى جهاز الصوت أو الأغنية المطلوب، سوف يتم تخطي الأغنية الحالية. - + + Station + إذاعة + + + Create New Station - + إنشاء قائمة أغاني جديدة - + Name: - + الاسم: - - New Station - + + Playlist + قائمة الأغاني - - New Playlist - + + Automatic Playlist + قائمة أغاني أوتوماتيكية - + Pause - + تعليق - + Go &offline - إذهب &خارج الهواء + أصبح &غير متصل - + Go &online - إذهب &على الهواء + اصبح &متصل - + Authentication Error - + خطأ في المصادقة - + Error connecting to SIP: Authentication failed! - + خطأ في الاتصال بسيب (SIP): فشلت المصادقة! - + %1 by %2 track, artist name - + %1 من قبل %2 - + %1 - %2 current track, some window title - + %1 - %2 - + <h2><b>Tomahawk %1<br/>(%2)</h2> <h2><b>Tomahawk %1<br/>(%2)</h2> - + <h2><b>Tomahawk %1</h2> <h2><b>Tomahawk %1</h2> - - Copyright 2010 - 2012<br/>Christian Muehlhaeuser &lt;muesli@tomahawk-player.org&gt;<br/><br/>Thanks to: Leo Franchi, Jeff Mitchell, Dominik Schmidt, Jason Herskowitz, Alejandro Wainzinger, Hugo Lindstr&ouml;m, Michael Zanetti, Harald Sitter and Steve Robertson - Copyright 2010 - 2012<br/>Christian Muehlhaeuser &lt;muesli@tomahawk-player.org&gt;<br/><br/>Thanks to: Leo Franchi, Jeff Mitchell, Dominik Schmidt, Jason Herskowitz, Alejandro Wainzinger, Hugo Lindstr&ouml;m, Michael Zanetti, Harald Sitter and Steve Robertson + + Copyright 2010 - 2012 + حقوق الطبع والنشر ٢٠١٠ - ٢٠١٢ - + + Thanks to: + شكر لكل من: + + + About Tomahawk عن توماهوك @@ -3038,7 +3211,7 @@ enter the displayed PIN number here: 0 Sources - + ٠ مصادر @@ -3063,12 +3236,12 @@ enter the displayed PIN number here: Artists - الفنانين + فنانين Filter - + مرشح @@ -3078,12 +3251,12 @@ enter the displayed PIN number here: Flat View - + نظرة مسطحة Sources - + المصادر @@ -3094,9 +3267,9 @@ enter the displayed PIN number here: TopTracksContext - + Top Hits - + الأكثر شهرة @@ -3107,145 +3280,72 @@ enter the displayed PIN number here: استمارة - + Cover - + غلاف - + Track اغنية - - by - - - - + Artist - الفنان + فنان - - from - - - - + Album البوم - + Statistics - + إحصائيات - - Lyrics - - - - + Similar Tracks أغاني قريبة + + + Sorry, but we could not find similar tracks for this song! + نعتذر، لم نستطيع إيجاد أغاني قريبة من هذه الأغنية! + - + You've listened to this track %n time(s). - + لقد استمعت إلى هذه الأغنية %n مرة.لقد استمعت إلى هذه الأغنية مرة %n.لقد استمعت إلى هذه الأغنية مرتين %n.لقد استمعت إلى هذه الأغنية %n مرات.لقد استمعت إلى هذه الأغنية %n مرات.لقد استمعت إلى هذه الأغنية %n مرات. - + You've never listened to this track before. لم تستمع لهذه الأغنية من قبل. - + You first listened to it on %1. - + استمعت إليها أولاً في %1. - + You've listened to %1 %n time(s). - + لقد استمعت إلى %1 %n مرة.لقد استمعت إلى %1 مرة %n.لقد استمعت إلى %1 مرتين %n.لقد استمعت إلى %1 %n مرات.لقد استمعت إلى %1 %n مرات.لقد استمعت إلى %1 %n مرات. - + You've never listened to %1 before. - - - - - TrackModel - - - Artist - الفنان - - - - Title - - - - - Album - البوم - - - - Track - اغنية - - - - Duration - - - - - Bitrate - - - - - Age - - - - - Year - - - - - Size - - - - - Origin - - - - - Score - - - - - Composer - + لم تستمع إلى %1 من قبل. TrackView - + Sorry, your filter '%1' did not match any results. - + عذراً، ترشيحك "%1" لم يطابق أي نتائج. @@ -3253,12 +3353,12 @@ enter the displayed PIN number here: from - + من to - + إلى @@ -3266,67 +3366,35 @@ enter the displayed PIN number here: Unknown - + مجهول TreeModel - - Name - - - - - Duration - - - - - Bitrate - - - - - Age - - - - - Year - - - - - Size - - - - - Origin - - - - - Composer - - - - + All Artists جميع الفنانين - - + + My Collection - + مجموعتي الخاصة - - + + Collection of %1 - + مجموعة %1 + + + + TreeView + + + Sorry, your filter '%1' did not match any results. + نتأسف، نظام الترشيح لم يجد شيئا تحت عنوان '%1'. @@ -3339,22 +3407,22 @@ enter the displayed PIN number here: The Twitter plugin allows you to discover and play music from your Twitter friends running Tomahawk and post messages to your account. - + مساعد تويتر (Twitter) يسمح لك بإكتشاف والإستماع إلى الموسيقى من أصدقائك على تويتر المستخدمين لتوماهوك بالإضافة إلى نشر الرسائل إلى حسابك. Status: No saved credentials - + الحالة: بيانات غير محفوظة Authenticate with Twitter - + صادق مع تويتر (Twitter) Twitter Connections - + إتصالات بتويتر (Twitter) @@ -3364,27 +3432,32 @@ If you only want to post tweets, you're done. If you want to connect Tomahawk to your friends using Twitter, select the type of tweet and press the button below to send a sync message. You must both be following each other as Direct Messages are used. Then be (very) patient -- it can take several minutes! You can re-send a sync message at any time simply by sending another tweet using the button. - + +إن كنت تريد نشر التويت (Tweet) فقط، لقد انتهيت! + +إن كنت تريد لتوماهوك الاتصال بأصدقائك من خلال تويتر (Twitter)، حدد نوع التويت (Tweet) و إضغط على الزر أدناه لإرسال رسالة مزامنة. يجب أن تكونا تابعين لبعضكما البعض على حد سواء لأن الرسائل المباشرة تستخدم. ثم يجب الإنتظار بصبر (كبير) - يمكن أن تستغرق العملية عدة دقائق! + +يمكنك إعادة إرسال رسالة المزامنة في أي وقت عن طريق إرسال تويت (Tweet) آخر بضغط هذا الزر من جديد. Select the kind of tweet you would like, then press the button to post it: - + حدد نوع التويت (Tweet) اللذي ترغب به، ثم إضغط على الزر لنشره: Global Tweet - + تويت شامل (Global Tweet) @Mention - + @ذكر Direct Message - + رسالة مباشرة @@ -3394,33 +3467,43 @@ You can re-send a sync message at any time simply by sending another tweet using Send Message - + إرسل رسالة ViewManager - + + After you have scanned your music collection you will find your tracks right here. + بعد إجراء مسح مجموعة أغانيك الخاصة ستجد أغانيك هنا. + + + + This collection is empty. + هذه المجموعة فارغة. + + + SuperCollection - + سوبر كولكشن - + Combined libraries of all your online friends - جمع مكاتب أصدقائك الذين على الهواء + مكتبات مجمعة لكل اصحابك المتصلين - + All available albums جميع الألبومات الجديدة - + Recently Played Tracks الأغاني التي إستمعت إليها مؤخرا - + Recently played tracks from all your friends جميع الأغاني التي استمع إليها أصدقائك مؤخرا @@ -3430,12 +3513,12 @@ You can re-send a sync message at any time simply by sending another tweet using Recent Additions - + آخر الإضافات Newest Stations & Playlists - + أجدد الإذاعات و قوائم الأغاني @@ -3443,12 +3526,12 @@ You can re-send a sync message at any time simply by sending another tweet using الأغاني التي إستمعت إليها مؤخرا - + No recently created playlists in your network. - + لا قوائم أغاني جديدة أنشئت مؤخرا على شبكتك. - + Welcome to Tomahawk مرحبا بكم في توماهوك @@ -3456,9 +3539,9 @@ You can re-send a sync message at any time simply by sending another tweet using WhatsHotWidget - + Charts - + الرسوم البيانية @@ -3466,7 +3549,7 @@ You can re-send a sync message at any time simply by sending another tweet using Wikipedia - + ويكيبيديا @@ -3476,26 +3559,30 @@ You can re-send a sync message at any time simply by sending another tweet using Terms for %1: - + شروط %1: No terms found, sorry. - + لا شروط موجودة، نتأسف. Hotttness for %1: %2 - + +شعبية %1:%2 + Familiarity for %1: %2 - + +ألفت %1:%2 + @@ -3504,7 +3591,11 @@ Lyrics for "%1" by %2: %3 - + +كلمات أغاني "%1" من قبل %2" + +%3 + @@ -3512,22 +3603,22 @@ Lyrics for "%1" by %2: Failed to parse contents of XSPF playlist - + فشل في تحليل محتويات قائمة الأغاني XSPF Some playlist entries were found without artist and track name, they will be omitted - + تم العثور على مداخل في قوائم الأغاني لا تحتوي على إسم فنان أو إسم أغنية، هذه المداخل سوف تحذف Failed to fetch the desired playlist from the network, or the desired file does not exist - + فشل في جلب قائمة الأغاني المطلوبة من الشبكة، أو الملف المطلوب غير موجود New Playlist - + قائمة أغاني جديدة @@ -3535,43 +3626,43 @@ Lyrics for "%1" by %2: Xml stream console - + Xml stream console Filter - + مرشح Save log - + حفظ تسجيل الدخول Disabled - + تعطيل By JID - + By JID By namespace uri - + By namespace uri By all attributes - + By all attributes Visible stanzas - + Visible stanzas @@ -3581,27 +3672,27 @@ Lyrics for "%1" by %2: Message - + رسالة Presence - + Presence Custom - + تعديل Close - + اغلاق Save XMPP log to file - + Save XMPP log to file @@ -3614,7 +3705,7 @@ Lyrics for "%1" by %2: Xmpp Configuration - + تكوينات أكسمبب (XMPP) @@ -3634,7 +3725,7 @@ Lyrics for "%1" by %2: Xmpp ID: - + تعريف أكسمبب (XMPP ID): @@ -3654,140 +3745,140 @@ Lyrics for "%1" by %2: Advanced Xmpp Settings - + إعدادات أكسمبب (XMPP) المتقدمة Server: - + خادم: Port: - + بوابة: Lots of servers don't support this (e.g. GTalk, jabber.org) - + الكثير من الخوادم لا تدعم هذا (e.g. GTalk, jabber.org) Publish currently playing track - + أنشر الأغنية التي تسمع الآن Enforce secure connection - + أفرض إتصال أمن XmppSipPlugin - + User Interaction تفاعل المستخدم - + Host is unknown - + المضيف مجهول - + Item not found - + البند غير موجودة - + Authorization Error - + خطا في الترخيص - + Remote Stream Error - + خطأ في التحميل (المجرى) البعيد - + Remote Connection failed - + فشل في الاتصال البعيد - + Internal Server Error - + خطأ داخلي في الخادم - + System shutdown - + إغلاق النظام - + Conflict - - - - - Unknown - + تضارب + Unknown + مجهول + + + No Compression Support - + لا دعم للضغط - + No Encryption Support - + لا دعم للتشفير - + No Authorization Support - + لا دعم للترخيص - + No Supported Feature - + لا ميزة معتمدة - + Add Friend - + أضف صديق - + Enter Xmpp ID: - + أدخل تعريف أكسمبب (XMPP ID): - + Add Friend... - + أضف صديق... - + XML Console... - + وحدة التحكم XML... - + I'm sorry -- I'm just an automatic presence used by Tomahawk Player (http://gettomahawk.com). If you are getting this message, the person you are trying to reach is probably not signed on, so please try again later! - + أنا أسف... أنا مجرد وجود ألي مستخدم من قبل توماهوك (http://gettomahawk.com). في حال الحصول على هذه الرسالة، فإن الشخص اللذي تحاول الوصول إليه خارج الخدمة، فنرجو المحاولة لاحقاً! - + Authorize User أعطي الإذن للمستخدم - + Do you want to grant <b>%1</b> access to your Collection? - + هل تريد أن تسمح ل <b>%1</b> بالوصول إلى مجموعتك ؟ @@ -3805,7 +3896,7 @@ Lyrics for "%1" by %2: This plugin will automatically find other users running Tomahawk on your local network - هذا المساعد سيجد مستخدمين أخرين لتوماهاوك على الشبكة المحلية + هذا المساعد سيجد مستخدمين أخرين لتوماهاوك على الشبكة المحلية أوتوماتيكيا diff --git a/lang/tomahawk_bg.ts b/lang/tomahawk_bg.ts index 71b43078c..654d3d5d0 100644 --- a/lang/tomahawk_bg.ts +++ b/lang/tomahawk_bg.ts @@ -2,17 +2,17 @@ AccountFactoryWrapper - + Dialog - + Description goes here - + Add Account Добави регистрация @@ -20,17 +20,17 @@ AccountFactoryWrapperDelegate - + Online На линия - + Connecting... Свързване... - + Offline Извън линия @@ -133,7 +133,17 @@ connect and stream from you? Други албуми на този артист - + + Sorry, we could not find any other albums for this artist! + Съжалявам, но не откривам нито един албум от този артист! + + + + Sorry, we could not find any tracks for this album! + Съжалявам, но не откривам нито една песен за този артист! + + + Other Albums by %1 Други албуми от %1 @@ -141,35 +151,17 @@ connect and stream from you? AlbumModel - - Album - Албум - - - - + + All albums from %1 Всички албуми на %1 - + All albums Всички албуми - - AlbumView - - - After you have scanned your music collection you will find your latest album additions right here. - След като бъде сканирана музикалната ти колекция, ще откриеш тук най-скоро добавените албуми. - - - - This collection doesn't have any recent albums. - В тази колекция все още няма добавени наскоро албуми. - - ArtistInfoWidget @@ -178,12 +170,12 @@ connect and stream from you? - + Top Hits Най-големи хитове - + Related Artists Свързани артисти @@ -192,24 +184,25 @@ connect and stream from you? Albums Албуми - - - ArtistView - - After you have scanned your music collection you will find your tracks right here. - След като приключи сканирането на музикалната ти колекция, ще откриеш музиката си тук. + + Cover + - - This collection is currently empty. - Базата данни с песни е празна. + + Sorry, we could not find any albums for this artist! + Съжалявам, но не откривам нито един албум за този артист! - - Sorry, your filter '%1' did not match any results. - Съжалявам. -Твоят филтър '%1' не върна никакъв резултат. + + Sorry, we could not find any related artists! + Съжалявам, но не откривам нито един подобен на този артист! + + + + Sorry, we could not find any top hits for this artist! + Съжалявам, но не откривам нито една хитова песен на този артист! @@ -235,57 +228,57 @@ connect and stream from you? Следваща - + Artist Артист - + Album Албум - + Owner Притежател - + social социален - + love Харесай - + Time Продължителност - + Time Left Оставащо време - + Shuffle Разбъркано - + Repeat Повтори - + Low 0 - + High 100% @@ -294,22 +287,25 @@ connect and stream from you? CategoryAddItem - - New Playlist - Нов списък + Create new Playlist + Създай нов списък - - - - + + Create new Station + Създай нова станция + + + + + New Station Нова станция - - - + + + %1 Station %1 Станция @@ -335,27 +331,6 @@ connect and stream from you? Изчисти - - CollectionFlatModel - - - My Collection - Моята колекция - - - - Collection of %1 - Колекцията на %1 - - - - CollectionView - - - This collection is empty. - Тази колекция е празна. - - ContextWidget @@ -365,12 +340,12 @@ connect and stream from you? - + Show Footnotes Покажи подробности - + Hide Footnotes Скрий подробности @@ -384,7 +359,7 @@ connect and stream from you? - <html><head/><body><p><span style=" font-weight:600;">Sorry!</span> Tomahawk crashed. Please tell us about it! Tomahawk has created an error report for you that can help improve the stability in the future. You can now send the this report directly to the Tomahawk developers.</p></body></html> + <html><head/><body><p><span style=" font-weight:600;">Sorry!</span> Tomahawk crashed. Please tell us about it! Tomahawk 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 Tomahawk developers.</p></body></html> <html><head/><body><p><span style=" font-weight:600;">Извинявай!</span> Tomahawk заби. Моля уведоми ни за този слуай! Tomahaw създаде доклад относно това и изпращайки го, ще помогнеш за по-добрата работа на приложението за в бъдеще. @@ -443,17 +418,17 @@ Tomahaw създаде доклад относно това и изпращай DelegateConfigWrapper - + About Относно - + Delete Account Изтрий регистрация - + About this Account Относно тази регистрация @@ -466,24 +441,11 @@ Tomahaw създаде доклад относно това и изпращай Диагностична информация относно Tomahawk - - Update - Обнови - - - + Copy to Clipboard Копирай в буферът - - DropJob - - - No tracks found for given %1 - Няма открити изпълнения на %1 - - GlobalSearchWidget @@ -508,56 +470,43 @@ Tomahaw създаде доклад относно това и изпращай Информационно поле - + Filter... Филтър... - - JobStatusView - - - Searching For - Търсене за - - - - Pending - Изчакващо - - - - Idle - Бездействам - - LastFmConfig - + Form - + Scrobble tracks to Last.fm Изпращане на изпълнени песни към Last.fm - + Username: Потребителско име: - + Password: Парола: - + Test Login Пробна връзка + + + Import Playback History + Импортирай история на просвирените песни + LastfmContext @@ -660,11 +609,80 @@ Tomahaw създаде доклад относно това и изпращай NewReleasesWidget - + New Releases Нови албуми + + PlayableModel + + + Artist + Артист + + + + Title + Име + + + + Composer + Композитор + + + + Album + Албум + + + + Track + Песен + + + + Duration + Продължителност + + + + Bitrate + Качество + + + + Age + Възраст + + + + Year + Година + + + + Size + Големина + + + + Origin + Източник + + + + Score + Резултат + + + + + Name + Име + + PlaylistItemDelegate @@ -681,17 +699,17 @@ Tomahaw създаде доклад относно това и изпращай PlaylistLargeItemDelegate - + played %1 by you изпълнена %1 от мен - + played %1 by %2 изпълнена %1 от %2 - + added %1 добавен %1 @@ -699,12 +717,12 @@ Tomahaw създаде доклад относно това и изпращай PlaylistModel - + A playlist by %1, created %2 Списък - създател %1, от %2 - + you ти @@ -760,7 +778,12 @@ Tomahaw създаде доклад относно това и изпращай PlaylistView - + + This playlist is currently empty. + Този списък е празен в момента. + + + This playlist is currently empty. Add some tracks to it and enjoy the music! Този списък в момента е празен. Добави няколко изпълнения и се наслади на музиката! @@ -827,67 +850,67 @@ Tomahaw създаде доклад относно това и изпращай QObject - + %n year(s) ago преди %n годинапреди %n години - + %n year(s) %n година%n години - + %n month(s) ago преди %n месецпреди %n месеца - + %n month(s) %n месец%n месеца - + %n week(s) ago преди %n седмицапреди %n седмици - + %n week(s) %n седмица%n седмици - + %n day(s) ago преди %n денпреди %n дена - + %n day(s) %n ден%n дена - + %n hour(s) ago преди %n часпреди %n часа - + %n hour(s) %n час %n часа - + %1 minutes ago преди %1 минути - + %1 minutes %1 минути - + just now току-що @@ -924,20 +947,25 @@ Tomahaw създаде доклад относно това и изпращай - - Show Queue - Покажи опашката + + Open Queue + Отвори опашката + + + + Open Queue - %n item(s) + - - Hide Queue - Скрий опашката + + Close Queue + Затвори опашката RelatedArtistsContext - + Related Artists Подобни артисти @@ -1060,17 +1088,22 @@ Tomahaw създаде доклад относно това и изпращай Етикет - - Listening to "%1" by %2 and loving it! %3 - ♥ "%1" от %2 %3 + + Tweet + - - Listening to "%1" by %2 on "%3" and loving it! %4 - #fb ♥ "%1" от %2 от "%3" %4 + + Listening to "%1" by %2. %3 + - + + Listening to "%1" by %2 on "%3". %4 + + + + %1 characters left Остават още %1 символа @@ -1103,29 +1136,19 @@ Tomahaw създаде доклад относно това и изпращай Първите 10 - - Offline - Извън линия - - - + All available tracks Всички налични изпълнения - - Online - На линия - - - - + + Show Покажи - - + + Hide Скрий @@ -1148,17 +1171,17 @@ Tomahaw създаде доклад относно това и изпращай Наскоро изпълнени песни - + New Additions Нови попълнения - + My recent activity Скорошна активност - + Recent activity from %1 Скорошна активност на %1 @@ -1166,82 +1189,139 @@ Tomahaw създаде доклад относно това и изпращай SourceItem - + Collection Колекция - - + + Latest Additions Последно добавени - + Recently Played Наскоро изпълнени песни - + Loved Tracks Харесани песни - + SuperCollection Супер колекция /Сборен излед от локалните и наличните в колекциите на приятелите ти/ - + + Sorry, we could not find any loved tracks! + Съжалявам, но не откривам нито една харесана песен! + + + Latest additions to your collection Последно добавени към колекцията - + Latest additions to %1's collection Последно добавени в колекцията на %1 - + + Sorry, we could not find any recent additions! + Съжалявам, но не откривам нито една ново-добавена позиция! + + + Recently Played Tracks Наскоро изпълнени песни - + Your recently played tracks Наскоро изпълнени песни от теб - + %1's recently played tracks Наскоро изпълнените песни от %1 + + + Sorry, we could not find any recent plays! + Съжалявам, но не откривам нито една наскоро изпълнена песен! + SourceTreeView - + &Copy Link &Копирай адресът - + &Delete %1 &Изтрий %1 - + + Add to my Playlists + Добави към моите списъци + + + + Add to my Automatic Playlists + Добави към моите автоматично-генерирани списъци + + + + Add to my Stations + Добави към станциите ми + + + &Export Playlist &Изнеси списък - + + playlist + списък + + + + automatic playlist + автоматично-генериран списък + + + + station + станция + + + + Delete %1? + playlist/station/... + Изтрий %1? + + + + Would you like to delete the %1 <b>"%2"</b>? + e.g. Would you like to delete the playlist named Foobar? + Наистина ли желаеш да изтриеш %1 <b>''%2" </b> + + + Save XSPF Запази XSPF - + Playlists (*.xspf) Списъци (*.xspf) @@ -1274,53 +1354,53 @@ Tomahaw създаде доклад относно това и изпращай Станция - + Browse Разгледай - + Search History Търси в историята - + My Music Моята музика - + SuperCollection Супер колекция /Сборен излед от локалните и наличните в колекциите на приятелите ти/ - + Top Loved Tracks Най-харесвани песни - + Dashboard Табло - + Recently Played Наскоро изпълнени песни - + Charts Класации - + New Releases Нови албуми - + Friends Приятели @@ -1328,52 +1408,52 @@ Tomahaw създаде доклад относно това и изпращай SpotifyConfig - + Form - + Configure your Spotify account Настрой своята регистрация в Spotify - + Username or Facebook Email Потребителско име или електронна поща във Facebook - + Log In Влез - + Right click on any Tomahawk playlist to sync it to Spotify. Щракни с десен бутон върху, който и да е списък в Tomahawk, за да го добавиш и в Spotify. - + High Quality Streams Високо качество - + Spotify playlists to keep in sync: Spotify списъци, които да бъдат поддържани обновени: - + Delete Tomahawk playlist when removing synchronization Изтрий запазените списъци, когато бъде премахната синхронизацията - + Username: Потребителско име: - + Password: Парола: @@ -1381,12 +1461,12 @@ Tomahaw създаде доклад относно това и изпращай SpotifyPlaylistUpdater - + Delete in Spotify? Изтривам и в Spotify? - + Would you like to delete the corresponding Spotify playlist as well? Желаеш ли да изтриеш и съответните Spotify списъци? @@ -1523,32 +1603,32 @@ Tomahaw създаде доклад относно това и изпращай Tomahawk::Accounts::AccountDelegate - + Add Account Добави регистрация - - Remove Account - Премахни регистрация + + Remove + - + %1 downloads %1 сваляния - + Online На линия - + Connecting... Свързване... - + Offline Извън линия @@ -1556,14 +1636,17 @@ Tomahaw създаде доклад относно това и изпращай Tomahawk::Accounts::AccountModel - + Manual Install Required Изисква се ръчно инсталиране - - Unfortunately, automatic installation of this resolver is not yet available on Linux.<br /><br />Please use "Install from file" above, by fetching it from your distribution or compiling it yourself. Further instructions can be found here:<br /><br />http://www.tomahawk-player.org/resolvers/%1 - + + Unfortunately, automatic installation of this resolver is not available or disabled for your platform.<br /><br />Please use "Install from file" above, by fetching it from your distribution or compiling it yourself. Further instructions can be found here:<br /><br />http://www.tomahawk-player.org/resolvers/%1 + За съжаление, автоматичното инсталиране на този компонен е деактивирано за твоята платформа. +<br /><br /> +Моля използвай опцията 'Инсталирай от файл', намираща се по-горе. За целта е необходимо предварително да изтеглиш необходимите файлове за твоята платформа и да ги компилираш самостоятелно. +Допълнителни инструкции могат да бъдат открити на <br /><br />http://www.tomahawk-player.org/resolvers/%1 @@ -1613,7 +1696,7 @@ Tomahaw създаде доклад относно това и изпращай Tomahawk::Accounts::LastFmAccountFactory - + Scrobble your tracks to last.fm, and find freely downloadable tracks to play Качи информация за изпълнените песни в Last.fm и открий свободно разпространявани. @@ -1621,23 +1704,49 @@ Tomahaw създаде доклад относно това и изпращай Tomahawk::Accounts::LastFmConfig - + + Testing... + Тествам... + + + Test Login Тествай връзката - - + + Importing %1 + e.g. Importing 2012/01/01 + Импортирам %1 + + + + Importing History... + Импортирам... + + + + History Incomplete. Resume + Непълна информация. Продължи. + + + + Playback History Imported + Историята на просвирените песни е импортирана + + + + Failed Неуспешно - + Success Ура! - + Could not contact server Не мога да се свържа със сървъра @@ -1645,12 +1754,17 @@ Tomahaw създаде доклад относно това и изпращай Tomahawk::Accounts::SpotifyAccount - + Sync with Spotify Синхронизирай със Spotify - + + Re-enable syncing with Spotify + Включи отново синхронизирането със Spotify + + + Stop syncing with Spotify Спри синхронизацията със Spotify @@ -1658,22 +1772,22 @@ Tomahaw създаде доклад относно това и изпращай Tomahawk::Accounts::SpotifyAccountConfig - + Logging in... Влизам... - + Logged in! Готово! - + Failed: %1 Неуспех: %1 - + Log In Влез @@ -1681,7 +1795,7 @@ Tomahaw създаде доклад относно това и изпращай Tomahawk::Accounts::SpotifyAccountFactory - + Play music from and sync your playlists with Spotify Premium Слушай музика и синхронизирай твоите списъци със Spotify Premium @@ -1835,7 +1949,7 @@ You may wish to try re-authenticating. Tomahawk::Accounts::ZeroconfFactory - + Automatically connect to Tomahawks on the local network Автоматично свързва Tomahawk с останалите копия на програмата, работещи в локалната мрежа. @@ -1850,29 +1964,29 @@ You may wish to try re-authenticating. - - + + Add to &Queue Добави към &опашката - + &Love &Харесай - + &Copy Track Link &Копирай адресът на изпълнението - + Un-&Love Не-&харесай - + &Delete Items &Изтрий позициите @@ -1887,24 +2001,24 @@ You may wish to try re-authenticating. &Спри след тази песен - + &Show Track Page - + &Покажи страницата на песента - + &Delete Item &Изтрий позицията - + &Show Album Page - + &Покажи страницата на албума - + &Show Artist Page - + &Покажи страницата на артистът @@ -1943,12 +2057,32 @@ You may wish to try re-authenticating. Tomahawk::DropJobNotifier - + + playlist + списък + + + + artist + артист + + + + track + песен + + + + album + албум + + + Fetching %1 from database Извличане на %1 от БД - + Parsing %1 %2 Обединяване на %1 %2 @@ -1994,17 +2128,17 @@ Please change the filters or try again. Tomahawk::DynamicView - + Add some filters above to seed this station! Добави няколко критерия, за да разпространиш тази станция - + Press Generate to get started! Натисни "Генерирай" за да почне просвирване. - + Add some filters above, and press Generate to get started! Добави няколко критерия и натисни "Генерирай" за да почне просвирване. @@ -2012,7 +2146,7 @@ Please change the filters or try again. Tomahawk::DynamicWidget - + Station ran out of tracks! Try tweaking the filters for a new set of songs to play. @@ -2331,92 +2465,92 @@ Try tweaking the filters for a new set of songs to play. Настройки: - + Much less Много по-малко - + Less По-малко - + A bit less Малко по-малко - + Keep at current Запази - + A bit more Малко повече - + More Повече - + Much more Много повече - + Tempo Темпо - + Loudness Сила - + Danceability Танцувалност - + Energy Енергия - + Song Hotttnesss Популярност на изпълненията - + Artist Hotttnesss Популярност на изпълнителя - + Artist Familiarity Близост на изпълнителите - + By Description По описание - + Enter a description Въведи описание - + Apply steering command Приложи избраната команда - + Reset all steering commands Нулирай всички предишни настройки @@ -2432,22 +2566,22 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::InfoSystem::ChartsPlugin - + Top Overall Най-известни - + Artists Артисти - + Albums Албуми - + Tracks Песни @@ -2468,27 +2602,27 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::InfoSystem::LastFmInfoPlugin - + Top Tracks Най-слушани песни - + Loved Tracks Харесани песни - + Hyped Tracks Песни, изпъкващи сред останалите - + Top Artists Най-слушани артисти - + Hyped Artists Изпълнители, изпъкващи сред останалите @@ -2496,7 +2630,7 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::InfoSystem::NewReleasesPlugin - + Albums Албуми @@ -2504,7 +2638,7 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::InfoSystem::TwitterInfoPlugin - + Listening to "%1" by %2 and loving it! %3 #fb ♥ "%1" от %2 %3 @@ -2562,37 +2696,37 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::Query - + and и - + You Ти - + you ти - + and и - + %n other(s) %n друг%n други - + %1 people %1 хора - + loved this track хареса тази песен @@ -2608,7 +2742,7 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::ShortenedLinkParser - + Network error parsing shortened link! Мрежова грешка при извличане на съкратеният адрес. @@ -2616,36 +2750,46 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::Source - - + + Scanning (%L1 tracks) Сканиране (%L1 песни) - + Scanning Сканирам - + Checking Проверявам - + Fetching Извличам - + Parsing Сортирам - + Saving (%1%) Запазвам (%1%) + + + Online + На линия + + + + Offline + Извън линия + Tomahawk::SpotifyParser @@ -2666,7 +2810,7 @@ Try tweaking the filters for a new set of songs to play. TomahawkApp - + My Collection Моята колекция @@ -2689,39 +2833,48 @@ enter the displayed PIN number here: TomahawkTrayIcon - - + &Stop Playback after current Track &Спри възпроизвеждането след текущата песен - - + + Hide Tomahawk Window Скрий главният прозорец - + Show Tomahawk Window Покажи главният прозорец - + Currently not playing. В момента не се изпълнява нищо - + Play Изпълни - + Pause Пауза - + + &Love + &Харесай + + + + Un-&Love + Не-&Харесай + + + &Continue Playback after current Track &Продължи възпроизвеждането след текущата песен @@ -2865,7 +3018,7 @@ enter the displayed PIN number here: - + Play Изпълни @@ -2885,165 +3038,175 @@ enter the displayed PIN number here: Следваща - + Back - + Go back one page - + Една страница назад - + Forward - + Напред - + Go forward one page - + Една страница напред - + Global Search... Глобално търсене... - - + + Check For Updates... Провери за обновления... - - - + + + Connect To Peer Свържи се с друг потребител - + Enter peer address: Въведи адресът на отдалеченият потребител: - + Enter peer port: Въведи порт: - + Enter peer key: Въведи ключът за удостоверяване: - + XSPF Error XSPF Грешка - + This is not a valid XSPF playlist. Това не е валиден XSPF списък - + Failed to save tracks Не мога да запазя списъкът с песни - + Some tracks in the playlist do not contain an artist and a title. They will be ignored. Някои от песните в този списък нямат артист и заглавие. Те ще бъдат игнорирани. - + Sorry, there is a problem accessing your audio device or the desired track, current track will be skipped. Make sure you have a suitable Phonon backend and required plugins installed. Съжалявам. Има проблем с достъпа до твоето аудио-устройство или до избраната песен - тя ще бъде прескочена. Моля, увери се, че са инсталирани подходящ Phonon и приставки. - + Sorry, there is a problem accessing your audio device or the desired track, current track will be skipped. Съжалявам. Има проблем с достъпа до твоето аудио устройство или избраната песен. Тя ще бъде пропусната. - + + Station + Станция + + + Create New Station Създай нова станция - + Name: Име: - - New Station - Нова станция + + Playlist + Списък - - New Playlist - Нов списък + + Automatic Playlist + Автоматично-генериран списък - + Pause Пауза - + Go &offline Излез &извън линия - + Go &online Свържи &се - + Authentication Error Грешка при удостоверяване - + Error connecting to SIP: Authentication failed! - + Грешка при свързване: Неуспешно удостоверяване! - + %1 by %2 track, artist name %1 от %2 - + %1 - %2 current track, some window title %1 - %2 - + <h2><b>Tomahawk %1<br/>(%2)</h2> <h2><b>Tomahawk %1<br/>(%2)</h2> - + <h2><b>Tomahawk %1</h2> <h2><b>Tomahawk %1</h2> - - Copyright 2010 - 2012<br/>Christian Muehlhaeuser &lt;muesli@tomahawk-player.org&gt;<br/><br/>Thanks to: Leo Franchi, Jeff Mitchell, Dominik Schmidt, Jason Herskowitz, Alejandro Wainzinger, Hugo Lindstr&ouml;m, Michael Zanetti, Harald Sitter and Steve Robertson - Всички права запазени 2010 - 2012<br/>Christian Muehlhaeuser &lt;muesli@tomahawk-player.org&gt;<br/><br/> Благодарности на: Leo Franchi, Jeff Mitchell, Dominik Schmidt, Jason Herskowitz, Alejandro Wainzinger, Hugo Lindstr&ouml;m, Michael Zanetti, Harald Sitter and Steve Robertson + + Copyright 2010 - 2012 + Всички права - запазени. 2010 - 2012 - + + Thanks to: + Благодарности на: + + + About Tomahawk Относно Tomahawk @@ -3114,7 +3277,7 @@ enter the displayed PIN number here: TopTracksContext - + Top Hits Най-слушани @@ -3127,143 +3290,70 @@ enter the displayed PIN number here: - + Cover Обложка - + Track Песен - - by - от - - - + Artist Изпълнител - - from - от - - - + Album Албум - + Statistics Статистика - - Lyrics - - - - + Similar Tracks Подобни песни + + + Sorry, but we could not find similar tracks for this song! + Съжалявам, но не откривам нито една подобна на тази песен! + - + You've listened to this track %n time(s). Ти си слушал тази песен %n път(и)Ти си слушал тази песен %n път(и) - + You've never listened to this track before. Никога не си слушал тази песен преди - + You first listened to it on %1. Първоначално си я слушал на %1 - + You've listened to %1 %n time(s). Слушал си %1 път(и)Слушал си %1 %n път(и) - + You've never listened to %1 before. Никога не си слушал %1 преди - - TrackModel - - - Artist - Артист - - - - Title - Заглавие - - - - Album - Албум - - - - Track - Номер - - - - Duration - Продължителност - - - - Bitrate - Качество - - - - Age - Възраст - - - - Year - Година - - - - Size - Размер - - - - Origin - Произход - - - - Score - Популярност - - - - Composer - Композитор - - TrackView - + Sorry, your filter '%1' did not match any results. Съжалявам, твоят филтър %1 не върна никакъв резултат. @@ -3292,63 +3382,31 @@ enter the displayed PIN number here: TreeModel - - Name - Име - - - - Duration - Продължителност - - - - Bitrate - Качество - - - - Age - Възраст - - - - Year - Година - - - - Size - Размер - - - - Origin - Произход - - - - Composer - Композитор - - - + All Artists Всички артисти - - + + My Collection Моята колекция - - + + Collection of %1 Колекцията на %1 + + TreeView + + + Sorry, your filter '%1' did not match any results. + Съжалявам, но филтърът '%1' не върна никакви резултати. + + TwitterConfigWidget @@ -3426,28 +3484,38 @@ You can re-send a sync message at any time simply by sending another tweet using ViewManager - + + After you have scanned your music collection you will find your tracks right here. + След като бъде сканирана колекцията ти, ще откриеш твоите песни точно тук. + + + + This collection is empty. + Празна колекция. + + + SuperCollection Супер колекция /Сборен излед от локалните и наличните в колекциите на приятелите ти/ - + Combined libraries of all your online friends Обща колекция с всичките ми приятели на линия - + All available albums Всички налични албуми - + Recently Played Tracks Наскоро изпълени песни - + Recently played tracks from all your friends Наскоро изпълнени песни от всичките ти приятели @@ -3470,12 +3538,12 @@ You can re-send a sync message at any time simply by sending another tweet using Наскоро изпълнени - + No recently created playlists in your network. Не откривам наскоро създадени списъци в твоята мрежа - + Welcome to Tomahawk Здравей! @@ -3483,7 +3551,7 @@ You can re-send a sync message at any time simply by sending another tweet using WhatsHotWidget - + Charts Класации @@ -3716,107 +3784,107 @@ Lyrics for "%1" by %2: XmppSipPlugin - + User Interaction Действие от потребителя - + Host is unknown Непознат адрес - + Item not found Обектът не е открит - + Authorization Error Грешка при даване на достъп - + Remote Stream Error Грешка в стриймът от отдалечената машина - + Remote Connection failed Отдалечената връзка е неуспешна - + Internal Server Error Вътрешна грешка на сървъра - + System shutdown Изключване на системата - + Conflict Конфликт - + Unknown Неизвестно - + No Compression Support Няма поддръжка на компресия - + No Encryption Support Няма поддръжка на криптиране - + No Authorization Support Няма поддръжка на удостоверяване - + No Supported Feature Неподдържана функция - + Add Friend Добави приятел - + Enter Xmpp ID: Въведи Xmpp ID: - + Add Friend... Добави приятел... - + XML Console... XML Конзола... - + I'm sorry -- I'm just an automatic presence used by Tomahawk Player (http://gettomahawk.com). If you are getting this message, the person you are trying to reach is probably not signed on, so please try again later! Извинявай.. Аз съм режимът за автоматични отговори изпълзван от Tomahawk. ( http://gettomahawk.com ) Щом получаваш това съобщение, този с който се опитваш да се свържеш вероятно не е на линия. Моля, опитай отново по-късно. - + Authorize User Оправомощяване на потребител - + Do you want to grant <b>%1</b> access to your Collection? Искате ли да позволите на <b>%1</b> достъп до вашата колекция? diff --git a/lang/tomahawk_ca.ts b/lang/tomahawk_ca.ts index 9c075f80e..2ac692eea 100644 --- a/lang/tomahawk_ca.ts +++ b/lang/tomahawk_ca.ts @@ -2,17 +2,17 @@ AccountFactoryWrapper - + Dialog Diàleg - + Description goes here Aquí va la descripció - + Add Account Afegiu un compte @@ -20,17 +20,17 @@ AccountFactoryWrapperDelegate - + Online En línia - + Connecting... Connectant-se... - + Offline Fora de línia @@ -133,7 +133,17 @@ connect and stream from you? Altres Àlbums de l'Artista - + + Sorry, we could not find any other albums for this artist! + + + + + Sorry, we could not find any tracks for this album! + + + + Other Albums by %1 Altres Àlbums de %1 @@ -141,35 +151,17 @@ connect and stream from you? AlbumModel - - Album - Àlbum - - - - + + All albums from %1 Tots els Àlbums de %1 - + All albums Tots els Àlbums - - AlbumView - - - After you have scanned your music collection you will find your latest album additions right here. - Després d'escanejar la vostra col·lecció musical, aquí trobareu els àlbums afegits últimament. - - - - This collection doesn't have any recent albums. - Aquesta col·lecció no té àlbums recents. - - ArtistInfoWidget @@ -178,12 +170,12 @@ connect and stream from you? Formulari - + Top Hits Grans Èxits - + Related Artists Artistes Relacionats @@ -192,23 +184,25 @@ connect and stream from you? Albums Àlbums - - - ArtistView - - After you have scanned your music collection you will find your tracks right here. - Després d'escanejar la vostra col·lecció musical, aquí trobareu les cançons afegides últimament. + + Cover + - - This collection is currently empty. - Aquesta col·lecció es troba buida actualment. + + Sorry, we could not find any albums for this artist! + - - Sorry, your filter '%1' did not match any results. - El filtre '%1' no ha obtingut cap resultat. + + Sorry, we could not find any related artists! + + + + + Sorry, we could not find any top hits for this artist! + @@ -234,57 +228,57 @@ connect and stream from you? Següent - + Artist Artista - + Album Àlbum - + Owner Propietari - + social social - + love M'encanta - + Time Temps - + Time Left Temps Restant - + Shuffle Mescla - + Repeat Repeteix - + Low Baix - + High Alt @@ -293,22 +287,25 @@ connect and stream from you? CategoryAddItem - - New Playlist - Nova llista de reproducció + Create new Playlist + - - - - + + Create new Station + + + + + + New Station Nova Emissora - - - + + + %1 Station Emissora %1 @@ -334,27 +331,6 @@ connect and stream from you? Suprimeix - - CollectionFlatModel - - - My Collection - La meva Col·lecció - - - - Collection of %1 - Col·lecció de %1 - - - - CollectionView - - - This collection is empty. - Aquesta col·lecció és buida. - - ContextWidget @@ -364,12 +340,12 @@ connect and stream from you? - + Show Footnotes Mostra les Notes al peu - + Hide Footnotes Amaga les Notes al peu @@ -383,7 +359,7 @@ connect and stream from you? - <html><head/><body><p><span style=" font-weight:600;">Sorry!</span> Tomahawk crashed. Please tell us about it! Tomahawk has created an error report for you that can help improve the stability in the future. You can now send the this report directly to the Tomahawk developers.</p></body></html> + <html><head/><body><p><span style=" font-weight:600;">Sorry!</span> Tomahawk crashed. Please tell us about it! Tomahawk 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 Tomahawk developers.</p></body></html> @@ -439,17 +415,17 @@ connect and stream from you? DelegateConfigWrapper - + About Quant a - + Delete Account Esborra el Compte - + About this Account Quant a aquest compte @@ -462,24 +438,11 @@ connect and stream from you? Diagnòstics de Tomahawk - - Update - Actualitza - - - + Copy to Clipboard Copia al Porta-retalls - - DropJob - - - No tracks found for given %1 - No s'han trobat cançons per %1 - - GlobalSearchWidget @@ -504,56 +467,43 @@ connect and stream from you? Barra d'Informació - + Filter... Filtra... - - JobStatusView - - - Searching For - Cercant - - - - Pending - Pendent - - - - Idle - Inactiu - - LastFmConfig - + Form Formulari - + Scrobble tracks to Last.fm Fes scrobbling de les cançons a Last.fm - + Username: Nom d'usuari: - + Password: Contrasenya: - + Test Login Comprova l'autenticació + + + Import Playback History + + LastfmContext @@ -656,11 +606,80 @@ connect and stream from you? NewReleasesWidget - + New Releases Nous llançaments + + PlayableModel + + + Artist + + + + + Title + + + + + Composer + + + + + Album + + + + + Track + + + + + Duration + + + + + Bitrate + + + + + Age + + + + + Year + + + + + Size + + + + + Origin + + + + + Score + + + + + + Name + + + PlaylistItemDelegate @@ -677,17 +696,17 @@ connect and stream from you? PlaylistLargeItemDelegate - + played %1 by you reproduït %1 - + played %1 by %2 reproduït %1 per %2 - + added %1 afegit %1 @@ -695,12 +714,12 @@ connect and stream from you? PlaylistModel - + A playlist by %1, created %2 Una llista de reproduccó de %1, creada %2 - + you @@ -756,7 +775,12 @@ connect and stream from you? PlaylistView - + + This playlist is currently empty. + + + + This playlist is currently empty. Add some tracks to it and enjoy the music! Aquesta llista es troba buida. Afegiu-hi algunes cançons i gaudiu de la música! @@ -824,67 +848,67 @@ connect and stream from you? QObject - + %n year(s) ago fa %n anyfa %n anys - + %n year(s) %n any%n anys - + %n month(s) ago fa %n mesfa %n mesos - + %n month(s) %n mes%n mesos - + %n week(s) ago fa %n setmanafa %n setmanes - + %n week(s) %n setmana%n setmanes - + %n day(s) ago fa %n diafa %n dies - + %n day(s) %n dia%n dies - + %n hour(s) ago fa %n horafa %n hores - + %n hour(s) %n hora%n hores - + %1 minutes ago fa %1 minut - + %1 minutes %1 minuts - + just now ara mateix @@ -921,20 +945,25 @@ connect and stream from you? - - Show Queue - Mostra la Cua + + Open Queue + + + + + Open Queue - %n item(s) + - - Hide Queue - Amaga la Cua + + Close Queue + RelatedArtistsContext - + Related Artists Artistes Relacionats @@ -1057,17 +1086,22 @@ connect and stream from you? TextLabel - - Listening to "%1" by %2 and loving it! %3 - Estic escoltant "%1" de "%2" i m'encanta!%3 + + Tweet + - - Listening to "%1" by %2 on "%3" and loving it! %4 - Estic escoltant "%1" de "%2" a "%3" i m'encanta!%4 + + Listening to "%1" by %2. %3 + - + + Listening to "%1" by %2 on "%3". %4 + + + + %1 characters left %1 caràcters restants @@ -1100,29 +1134,19 @@ connect and stream from you? Top 10 - - Offline - Fora de Línia - - - + All available tracks Totes les cançons disponibles - - Online - En Línia - - - - + + Show Mostra - - + + Hide Amaga @@ -1145,17 +1169,17 @@ connect and stream from you? Cançons Escoltades Recentment - + New Additions Novetats - + My recent activity La meva activitat recent - + Recent activity from %1 Activitat recent de %1 @@ -1163,81 +1187,138 @@ connect and stream from you? SourceItem - + Collection Col·lecció - - + + Latest Additions Darreres Novetats - + Recently Played Escoltades Recentment - + Loved Tracks Cançons Preferides - + SuperCollection SuperCol·lecció - + + Sorry, we could not find any loved tracks! + + + + Latest additions to your collection Darreres novetats a la vostra col·lecció - + Latest additions to %1's collection Darreres novetats a la col·lecció de %1 - + + Sorry, we could not find any recent additions! + + + + Recently Played Tracks Cançons Escoltades Recentment - + Your recently played tracks Cançons Escoltades Recentment - + %1's recently played tracks Cançons Escoltades Recentment per %1 + + + Sorry, we could not find any recent plays! + + SourceTreeView - + &Copy Link &Copia l'Enllaç - + &Delete %1 &Esborra %1 - + + Add to my Playlists + + + + + Add to my Automatic Playlists + + + + + Add to my Stations + + + + &Export Playlist E&xporta la Llista de Reproducció - + + playlist + + + + + automatic playlist + + + + + station + + + + + Delete %1? + playlist/station/... + + + + + Would you like to delete the %1 <b>"%2"</b>? + e.g. Would you like to delete the playlist named Foobar? + + + + Save XSPF Desa com XSPF - + Playlists (*.xspf) Llistes de reproducció (*.xspf) @@ -1270,52 +1351,52 @@ connect and stream from you? Emissora - + Browse Cerca - + Search History Historial de Cerca - + My Music La Meva Música - + SuperCollection SuperCol·lecció - + Top Loved Tracks Top de Cançons Preferides - + Dashboard Presentació - + Recently Played Escoltades Recentment - + Charts Llistes - + New Releases Nous Llançaments - + Friends Amics @@ -1323,52 +1404,52 @@ connect and stream from you? SpotifyConfig - + Form Formulari - + Configure your Spotify account Configureu el compte Spotify - + Username or Facebook Email Nom d'usuari o adreça de Facebook - + Log In Inicia Sessió - + Right click on any Tomahawk playlist to sync it to Spotify. Feu click dret a qualsevol llista de reproducció de Tomahawk per sincronitzar-la amb Spotify. - + High Quality Streams Fluxos d'Alta Qualitat - + Spotify playlists to keep in sync: Llistes de reproducció de Spotify per mantenir sincronitzades: - + Delete Tomahawk playlist when removing synchronization Esborra les llistes de Tomahawk quan es tregui la sincronització - + Username: Usuari: - + Password: Contrasenya: @@ -1376,12 +1457,12 @@ connect and stream from you? SpotifyPlaylistUpdater - + Delete in Spotify? Voleu esborrar-ho de Spotify? - + Would you like to delete the corresponding Spotify playlist as well? Voleu esborrar les llistes de Spotify, també? @@ -1518,32 +1599,32 @@ i emissores de ràdio basades en el vostre gust musical. Tomahawk::Accounts::AccountDelegate - + Add Account Afegeix un compte - - Remove Account - Esborra el compte + + Remove + - + %1 downloads %1 descàrregues - + Online En Línia - + Connecting... Connectant-se... - + Offline Fora de Línia @@ -1551,13 +1632,13 @@ i emissores de ràdio basades en el vostre gust musical. Tomahawk::Accounts::AccountModel - + Manual Install Required - - Unfortunately, automatic installation of this resolver is not yet available on Linux.<br /><br />Please use "Install from file" above, by fetching it from your distribution or compiling it yourself. Further instructions can be found here:<br /><br />http://www.tomahawk-player.org/resolvers/%1 + + Unfortunately, automatic installation of this resolver is not available or disabled for your platform.<br /><br />Please use "Install from file" above, by fetching it from your distribution or compiling it yourself. Further instructions can be found here:<br /><br />http://www.tomahawk-player.org/resolvers/%1 @@ -1608,7 +1689,7 @@ i emissores de ràdio basades en el vostre gust musical. Tomahawk::Accounts::LastFmAccountFactory - + Scrobble your tracks to last.fm, and find freely downloadable tracks to play Fes scrobbling de les cançons a last.fm, i cerca cançons descarregables gratuïtament per escoltar-les @@ -1616,23 +1697,49 @@ i emissores de ràdio basades en el vostre gust musical. Tomahawk::Accounts::LastFmConfig - + + Testing... + + + + Test Login Comprova l'inici de sessió - - + + Importing %1 + e.g. Importing 2012/01/01 + + + + + Importing History... + + + + + History Incomplete. Resume + + + + + Playback History Imported + + + + + Failed Error - + Success Èxit - + Could not contact server No s'ha pogut contactar amb el servidor @@ -1640,12 +1747,17 @@ i emissores de ràdio basades en el vostre gust musical. Tomahawk::Accounts::SpotifyAccount - + Sync with Spotify Sincronitza amb Spotify - + + Re-enable syncing with Spotify + + + + Stop syncing with Spotify Atura la sincronització amb Spotify @@ -1653,22 +1765,22 @@ i emissores de ràdio basades en el vostre gust musical. Tomahawk::Accounts::SpotifyAccountConfig - + Logging in... Iniciant sessió... - + Logged in! Sessió iniciada! - + Failed: %1 Error: %1 - + Log In Incia Sessió @@ -1676,7 +1788,7 @@ i emissores de ràdio basades en el vostre gust musical. Tomahawk::Accounts::SpotifyAccountFactory - + Play music from and sync your playlists with Spotify Premium Reprodueix música i sincronitza les llistes de reproducció amb Spotify Premium @@ -1829,7 +1941,7 @@ Torneu a autenticar-vos. Tomahawk::Accounts::ZeroconfFactory - + Automatically connect to Tomahawks on the local network Connecta't automàticament a altres Tomahawks de la xarxa local @@ -1843,29 +1955,29 @@ Torneu a autenticar-vos. - - + + Add to &Queue &Afegeix a la Cua - + &Love &M'encanta - + &Copy Track Link &Copia l'Enllaç de la Cançó - + Un-&Love &Treu de les preferides - + &Delete Items &Elimina els Ítems @@ -1880,22 +1992,22 @@ Torneu a autenticar-vos. &Atura la Reproducció després d'aquesta Cançó - + &Show Track Page - + &Delete Item &Elimina l'Ítem - + &Show Album Page - + &Show Artist Page @@ -1936,12 +2048,32 @@ Torneu a autenticar-vos. Tomahawk::DropJobNotifier - + + playlist + + + + + artist + + + + + track + + + + + album + + + + Fetching %1 from database Cercant %1 a la base de dades - + Parsing %1 %2 Analitzant %1 %2 @@ -1988,17 +2120,17 @@ Canvieu els filtres o intenteu-ho de nou. Tomahawk::DynamicView - + Add some filters above to seed this station! Afegeiu slguns filtres per omplir aquesta emissora! - + Press Generate to get started! Premeu Genera per començar! - + Add some filters above, and press Generate to get started! Afegeiu alguns filtres i premeu Genera per començar! @@ -2006,7 +2138,7 @@ Canvieu els filtres o intenteu-ho de nou. Tomahawk::DynamicWidget - + Station ran out of tracks! Try tweaking the filters for a new set of songs to play. @@ -2325,92 +2457,92 @@ Intenteu ajustar els filtres per reproduir noves cançons. Dirigeix aquesta emissora: - + Much less Molt més - + Less Menys - + A bit less Una mica menys - + Keep at current Mantingues a l'actual - + A bit more Una mica més - + More Més - + Much more Molt més - + Tempo Temps - + Loudness Volum - + Danceability Ballabilitat - + Energy Energia - + Song Hotttnesss Rellevància de Cançó - + Artist Hotttnesss Rellevància d'Artista - + Artist Familiarity Semblança amb l'artista - + By Description Per Descripció - + Enter a description Introduïu una descripció - + Apply steering command Aplica la comanda de control - + Reset all steering commands Restaura totes les comandes de control @@ -2426,22 +2558,22 @@ Intenteu ajustar els filtres per reproduir noves cançons. Tomahawk::InfoSystem::ChartsPlugin - + Top Overall Top General - + Artists Artistes - + Albums Àlbums - + Tracks Cançons @@ -2462,27 +2594,27 @@ Intenteu ajustar els filtres per reproduir noves cançons. Tomahawk::InfoSystem::LastFmInfoPlugin - + Top Tracks Top Cançons Musicals - + Loved Tracks Cançons Preferides - + Hyped Tracks Cançons en alça - + Top Artists Top Artistes - + Hyped Artists Artistes en alça @@ -2490,7 +2622,7 @@ Intenteu ajustar els filtres per reproduir noves cançons. Tomahawk::InfoSystem::NewReleasesPlugin - + Albums Àlbums @@ -2498,7 +2630,7 @@ Intenteu ajustar els filtres per reproduir noves cançons. Tomahawk::InfoSystem::TwitterInfoPlugin - + Listening to "%1" by %2 and loving it! %3 Estic escoltant "%1" de "%2" i m'encanta! %3 @@ -2556,37 +2688,37 @@ Intenteu ajustar els filtres per reproduir noves cançons. Tomahawk::Query - + and i - + You Jo - + you jo - + and i - + %n other(s) %n més%n més - + %1 people %1 persones - + loved this track els ha encantat aquesta cançó @@ -2602,7 +2734,7 @@ Intenteu ajustar els filtres per reproduir noves cançons. Tomahawk::ShortenedLinkParser - + Network error parsing shortened link! Error de la xarxa en analitzar l'enllaç escurçat! @@ -2610,36 +2742,46 @@ Intenteu ajustar els filtres per reproduir noves cançons. Tomahawk::Source - - + + Scanning (%L1 tracks) Escanejant (%L1 cançons) - + Scanning Escanejant - + Checking Comprovant - + Fetching Cercant - + Parsing Analitzant - + Saving (%1%) Desant (%1%) + + + Online + + + + + Offline + + Tomahawk::SpotifyParser @@ -2660,7 +2802,7 @@ Intenteu ajustar els filtres per reproduir noves cançons. TomahawkApp - + My Collection La meva Col·lecció @@ -2683,39 +2825,48 @@ introduïu el PIN aquí: TomahawkTrayIcon - - + &Stop Playback after current Track &Atura la Reproducció després d'aquesta Cançó - - + + Hide Tomahawk Window Amaga la finestra de Tomahawk - + Show Tomahawk Window Mostra la finestra de Tomahawk - + Currently not playing. No s'està reproduint res. - + Play Reprodueix - + Pause Pausa - + + &Love + + + + + Un-&Love + + + + &Continue Playback after current Track &Continua la reproducció després d'aquesta Cançó @@ -2859,7 +3010,7 @@ introduïu el PIN aquí: - + Play Reprodueix @@ -2879,162 +3030,172 @@ introduïu el PIN aquí: Següent - + Back - + Go back one page - + Forward - + Go forward one page - + Global Search... Cerca Global... - - + + Check For Updates... Comprova les actualitzacions... - - - + + + Connect To Peer Connexió Remota - + Enter peer address: Introduïu l'adreça remota: - + Enter peer port: Introduïu el port remot: - + Enter peer key: Introduïu la clau remota: - + XSPF Error Error XSPF - + This is not a valid XSPF playlist. No és una llista XSPF vàlida. - + Failed to save tracks Error en desar les cançons - + Some tracks in the playlist do not contain an artist and a title. They will be ignored. Algunes cançons de la llista no contenen ni artista ni titol i s'han ignorat. - + Sorry, there is a problem accessing your audio device or the desired track, current track will be skipped. Make sure you have a suitable Phonon backend and required plugins installed. Hi ha un problema per accedir al dispositiu de so o a la cançó. La cançó actual s'ha saltat. Assegureu-vos que teniu un back.end de Phonon adequant i els plugins necessaris instal·lats. - + Sorry, there is a problem accessing your audio device or the desired track, current track will be skipped. Hi ha un problema per accedir al dispositiu de so o a la cançó, la cançó actual s'ha saltat. - + + Station + + + + Create New Station Crea una Nova Emissora - + Name: Nom: - - New Station - Nova Emissora + + Playlist + - - New Playlist - Nova llista de reproducció + + Automatic Playlist + - + Pause Pausa - + Go &offline &Desconnecta't - + Go &online &Connecta't - + Authentication Error Error d'autentificació - + Error connecting to SIP: Authentication failed! - + %1 by %2 track, artist name %1 de %2 - + %1 - %2 current track, some window title %1 - %2 - + <h2><b>Tomahawk %1<br/>(%2)</h2> <h2><b>Tomahawk %1<br/>(%2)</h2> - + <h2><b>Tomahawk %1</h2> <h2><b>Tomahawk %1</h2> - - Copyright 2010 - 2012<br/>Christian Muehlhaeuser &lt;muesli@tomahawk-player.org&gt;<br/><br/>Thanks to: Leo Franchi, Jeff Mitchell, Dominik Schmidt, Jason Herskowitz, Alejandro Wainzinger, Hugo Lindstr&ouml;m, Michael Zanetti, Harald Sitter and Steve Robertson - Copyright 2010 - 2012<br/>Christian Muehlhaeuser &lt;muesli@tomahawk-player.org&gt;<br/><br/>Gràcies a: Leo Franchi, Jeff Mitchell, Dominik Schmidt, Jason Herskowitz, Alejandro Wainzinger, Hugo Lindstr&ouml;m, Michael Zanetti, Harald Sitter i Steve Robertson + + Copyright 2010 - 2012 + - + + Thanks to: + + + + About Tomahawk Quant a Tomahawk @@ -3105,7 +3266,7 @@ introduïu el PIN aquí: TopTracksContext - + Top Hits Grans Èxits @@ -3118,143 +3279,70 @@ introduïu el PIN aquí: Formulari - + Cover Cover - + Track Cançó - - by - de - - - + Artist Artista - - from - de - - - + Album Àlbum - + Statistics Estadístiques - - Lyrics - - - - + Similar Tracks Cançons Semblants + + + Sorry, but we could not find similar tracks for this song! + + - + You've listened to this track %n time(s). Heu escoltat aquesta cançó %n cop.Heu escoltat aquesta cançó %n cops. - + You've never listened to this track before. No heu escoltat mai aquesta cançó abans. - + You first listened to it on %1. Vau escoltar aquesta cançó per primer cop el %1. - + You've listened to %1 %n time(s). Heu escoltat %1 %n cop.Heu escoltat %1 %n cops. - + You've never listened to %1 before. No heu escoltat mai %1 abans. - - TrackModel - - - Artist - Artista - - - - Title - Títol - - - - Album - Àlbum - - - - Track - Cançó - - - - Duration - Durada - - - - Bitrate - Bitrate - - - - Age - Edat - - - - Year - Any - - - - Size - Mida - - - - Origin - Origen - - - - Score - Puntuació - - - - Composer - Compositor - - TrackView - + Sorry, your filter '%1' did not match any results. El filtre '%1' no ha obtingut cap resultat. @@ -3283,63 +3371,31 @@ introduïu el PIN aquí: TreeModel - - Name - Nom - - - - Duration - Durada - - - - Bitrate - Bitrate - - - - Age - Edat - - - - Year - Any - - - - Size - Mida - - - - Origin - Origen - - - - Composer - Compositor - - - + All Artists Tots els Artistes - - + + My Collection La meva Col·lecció - - + + Collection of %1 Col·lecció de %1 + + TreeView + + + Sorry, your filter '%1' did not match any results. + + + TwitterConfigWidget @@ -3416,27 +3472,37 @@ Podeu reenviar un missatge de sincronisme en qualsevol moment simplement enviant ViewManager - + + After you have scanned your music collection you will find your tracks right here. + + + + + This collection is empty. + + + + SuperCollection SuperCol·lecció - + Combined libraries of all your online friends Biblioteques combinades de tots els amis en línia - + All available albums Tots els àlbums disponibles - + Recently Played Tracks Cançons Escoltades Recentment - + Recently played tracks from all your friends Cançons escoltades recentment pels amics @@ -3459,12 +3525,12 @@ Podeu reenviar un missatge de sincronisme en qualsevol moment simplement enviant Cançons Escoltades Recentment - + No recently created playlists in your network. No hi ha cançons escoltades recentment a la xarxa. - + Welcome to Tomahawk Us donem la benvinguda a Tomahawk @@ -3472,7 +3538,7 @@ Podeu reenviar un missatge de sincronisme en qualsevol moment simplement enviant WhatsHotWidget - + Charts Llistes @@ -3707,107 +3773,107 @@ Lletres de la cancó "%1" de %2: XmppSipPlugin - + User Interaction Interacció d'usuari - + Host is unknown El nom de l'ordinador és desconegut - + Item not found No s'ha trobat l'element - + Authorization Error Error d'autorització - + Remote Stream Error Error de flux remot - + Remote Connection failed Ha fallat la connexió remota - + Internal Server Error Error del servidor intern - + System shutdown Sistema apagat - + Conflict Conflicte - + Unknown Desconegut - + No Compression Support Compressió no suportada - + No Encryption Support Encriptació no suportada - + No Authorization Support Autorització no suportada - + No Supported Feature Característica no suportada - + Add Friend Afegeix un Amic - + Enter Xmpp ID: Introduiu la ID XMPP: - + Add Friend... Afegeix un Amic... - + XML Console... Consola XML... - + I'm sorry -- I'm just an automatic presence used by Tomahawk Player (http://gettomahawk.com). If you are getting this message, the person you are trying to reach is probably not signed on, so please try again later! Sóc una presència automàtica emprada pel Reproductor Tomahawk. (http://gettomahawk.com. Si rebeu aquest missatge, la persona amb qui intenteu contactar probablement no està en línia, intenteu-ho més tard! - + Authorize User Autorització d'Usuari - + Do you want to grant <b>%1</b> access to your Collection? Voleu permetre que <b>%1</b> accedeixi a la vostra Col·lecció? diff --git a/lang/tomahawk_de.ts b/lang/tomahawk_de.ts index d1ffb4e3c..acdd07389 100644 --- a/lang/tomahawk_de.ts +++ b/lang/tomahawk_de.ts @@ -2,17 +2,17 @@ AccountFactoryWrapper - + Dialog Dialog - + Description goes here Beschreibung hier - + Add Account Konto hinzufügen @@ -20,17 +20,17 @@ AccountFactoryWrapperDelegate - + Online Verbunden - + Connecting... Verbinde... - + Offline Nicht Verbunden @@ -133,7 +133,17 @@ connect and stream from you? Andere Alben des Künstlers - + + Sorry, we could not find any other albums for this artist! + + + + + Sorry, we could not find any tracks for this album! + + + + Other Albums by %1 Andere Alben von %1 @@ -141,35 +151,17 @@ connect and stream from you? AlbumModel - - Album - Album - - - - + + All albums from %1 Alle Alben von %1 - + All albums Alle Alben - - AlbumView - - - After you have scanned your music collection you will find your latest album additions right here. - Nachdem Tomahawk deine Sammlung durchsucht hast siehst du hier deine neuesten Alben. - - - - This collection doesn't have any recent albums. - Diese Sammlung ist leer. - - ArtistInfoWidget @@ -178,12 +170,12 @@ connect and stream from you? Form - + Top Hits Top Hits - + Related Artists Ähnliche Künstler @@ -192,23 +184,25 @@ connect and stream from you? Albums Alben - - - ArtistView - - After you have scanned your music collection you will find your tracks right here. - Nachdem Tomahawk deine Sammlung durchsucht hat siehst du deine Lieder hier. + + Cover + - - This collection is currently empty. - Diese Sammlung is momentan leer. + + Sorry, we could not find any albums for this artist! + - - Sorry, your filter '%1' did not match any results. - Entschuldige, dein Filter '%1' erzeugte keine Ergebnisse. + + Sorry, we could not find any related artists! + + + + + Sorry, we could not find any top hits for this artist! + @@ -234,57 +228,57 @@ connect and stream from you? Weiter - + Artist Künstler - + Album Album - + Owner Eigentümer - + social Sozial - + love Lieben - + Time Zeit - + Time Left Zeit verbleibend - + Shuffle Zufall - + Repeat Wiederholen - + Low Niedrig - + High Hoch @@ -293,22 +287,25 @@ connect and stream from you? CategoryAddItem - - New Playlist - Neue Playliste + Create new Playlist + - - - - + + Create new Station + + + + + + New Station Neue Station - - - + + + %1 Station %1 Station @@ -334,27 +331,6 @@ connect and stream from you? Leeren - - CollectionFlatModel - - - My Collection - Meine Sammlung - - - - Collection of %1 - Sammlung von %1 - - - - CollectionView - - - This collection is empty. - Diese Sammlung ist leer. - - ContextWidget @@ -364,12 +340,12 @@ connect and stream from you? - + Show Footnotes Footnotes einblenden - + Hide Footnotes Footnotes ausblenden @@ -383,18 +359,18 @@ connect and stream from you? - <html><head/><body><p><span style=" font-weight:600;">Sorry!</span> Tomahawk crashed. Please tell us about it! Tomahawk has created an error report for you that can help improve the stability in the future. You can now send the this report directly to the Tomahawk developers.</p></body></html> + <html><head/><body><p><span style=" font-weight:600;">Sorry!</span> Tomahawk crashed. Please tell us about it! Tomahawk 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 Tomahawk developers.</p></body></html> Send this report - + Report abschicken Don't send - + Nicht abschicken @@ -439,17 +415,17 @@ connect and stream from you? DelegateConfigWrapper - + About Über - + Delete Account Konto entfernen - + About this Account Über dieses Konto @@ -462,24 +438,11 @@ connect and stream from you? Tomahawk Diagnose Tool - - Update - Aktualisieren - - - + Copy to Clipboard In die Zwischenablage kopieren - - DropJob - - - No tracks found for given %1 - Keine Stücke gefunden für %1 - - GlobalSearchWidget @@ -504,56 +467,43 @@ connect and stream from you? Infoleiste - + Filter... Filter... - - JobStatusView - - - Searching For - Suche nach - - - - Pending - Verbleibend - - - - Idle - Warte - - LastFmConfig - + Form Formular - + Scrobble tracks to Last.fm Scrobbel Stücke zu Last.fm - + Username: Benutzer: - + Password: Passwort: - + Test Login Login testen + + + Import Playback History + + LastfmContext @@ -656,11 +606,80 @@ connect and stream from you? NewReleasesWidget - + New Releases Neuerscheinungen + + PlayableModel + + + Artist + Künstler + + + + Title + + + + + Composer + + + + + Album + + + + + Track + + + + + Duration + + + + + Bitrate + + + + + Age + + + + + Year + + + + + Size + + + + + Origin + + + + + Score + + + + + + Name + + + PlaylistItemDelegate @@ -677,17 +696,17 @@ connect and stream from you? PlaylistLargeItemDelegate - + played %1 by you angehört %1 von dir - + played %1 by %2 hörte %1 von %2 - + added %1 fügte %1 hinzu @@ -695,12 +714,12 @@ connect and stream from you? PlaylistModel - + A playlist by %1, created %2 Eine Playliste von %1, erstellt %2 - + you dir @@ -756,7 +775,12 @@ connect and stream from you? PlaylistView - + + This playlist is currently empty. + + + + This playlist is currently empty. Add some tracks to it and enjoy the music! Diese Playliste ist derzeit leer. Füge einige Stücke hinzu und genieße die Musik! @@ -824,67 +848,67 @@ connect and stream from you? QObject - + %n year(s) ago vor %n Jahrvor %n Jahren - + %n year(s) %n Jahr%n Jahre - + %n month(s) ago vor %n Monatvor %n Monaten - + %n month(s) %n Monat%n Monate - + %n week(s) ago vor %n Wochevor %n Wochen - + %n week(s) %n Woche%n Wochen - + %n day(s) ago vor %n Tagvor %n Tagen - + %n day(s) %n Tag%n Tage - + %n hour(s) ago vor %n Stundevor %n Stunden - + %n hour(s) %n Stunde%n Stunden - + %1 minutes ago - vor %1 Minute + vor %1 Minuten - + %1 minutes %1 Minuten - + just now gerade eben @@ -921,20 +945,25 @@ connect and stream from you? - - Show Queue - Warteschlange einblenden + + Open Queue + + + + + Open Queue - %n item(s) + - - Hide Queue - Warteschlange ausblenden + + Close Queue + RelatedArtistsContext - + Related Artists Ähnliche Künstler @@ -1057,17 +1086,22 @@ connect and stream from you? TextLabel - - Listening to "%1" by %2 and loving it! %3 - Höre "%1" von %2 und liebe es! %3 + + Tweet + - - Listening to "%1" by %2 on "%3" and loving it! %4 - Höre "%1" von %2 auf "%3" und liebe es! %4 + + Listening to "%1" by %2. %3 + - + + Listening to "%1" by %2 on "%3". %4 + + + + %1 characters left %1 Zeichen übrig @@ -1100,29 +1134,19 @@ connect and stream from you? Top 10 - - Offline - Nicht Verbunden - - - + All available tracks Alle verfügbaren Stücke - - Online - Verbunden - - - - + + Show Einblenden - - + + Hide Verstecken @@ -1145,17 +1169,17 @@ connect and stream from you? Kürzlich gehörte Lieder - + New Additions Kürzlich hinzugekommen - + My recent activity Meine letzten Aktivitäten - + Recent activity from %1 Die letzten Aktivitäten von %1 @@ -1163,81 +1187,138 @@ connect and stream from you? SourceItem - + Collection Sammlung - - + + Latest Additions Kürzlich hinzugekommen - + Recently Played Kürzlich gehörte Lieder - + Loved Tracks Lieblingslieder - + SuperCollection Supersammlung - + + Sorry, we could not find any loved tracks! + + + + Latest additions to your collection - + Neueste Lieder in deiner Sammlung - + Latest additions to %1's collection + Neueste Lieder in %1's Sammlung + + + + Sorry, we could not find any recent additions! - + Recently Played Tracks - + Zuletzt gehörte Lieder - + Your recently played tracks - + Deine zuletzt gehörten Lieder - + %1's recently played tracks + %1's zuletzt gehörte Lieder + + + + Sorry, we could not find any recent plays! SourceTreeView - + &Copy Link &Kopiere Link - + &Delete %1 &Lösche %1 - + + Add to my Playlists + Zu meinen Playlisten hinzufügen + + + + Add to my Automatic Playlists + Zu meinen Automatischen Playlisten hinzufügen + + + + Add to my Stations + Zu meinen Stationen hinzufügen + + + &Export Playlist Playliste &exportieren - + + playlist + + + + + automatic playlist + + + + + station + + + + + Delete %1? + playlist/station/... + + + + + Would you like to delete the %1 <b>"%2"</b>? + e.g. Would you like to delete the playlist named Foobar? + + + + Save XSPF XSPF speichern - + Playlists (*.xspf) Playlisten (*.xspf) @@ -1270,52 +1351,52 @@ connect and stream from you? Station - + Browse Stöbern - + Search History Suchverlauf - + My Music Meine Musik - + SuperCollection Supersammlung - + Top Loved Tracks Gemeinsame Lieblingslieder - + Dashboard Dashboard - + Recently Played Kürzlich gehörte Lieder - + Charts Charts - + New Releases Neuerscheinungen - + Friends Freunde @@ -1323,52 +1404,52 @@ connect and stream from you? SpotifyConfig - + Form Formular - + Configure your Spotify account Konfiguriere dein Spotify Konto - + Username or Facebook Email Nutzername oder Facebook Email - + Log In Anmeldung - + Right click on any Tomahawk playlist to sync it to Spotify. - + High Quality Streams - + Spotify playlists to keep in sync: Spotify Listen die du synchronisieren willst: - + Delete Tomahawk playlist when removing synchronization - + Username: Benutzer: - + Password: Passwort: @@ -1376,12 +1457,12 @@ connect and stream from you? SpotifyPlaylistUpdater - + Delete in Spotify? Auf Spotify löschen - + Would you like to delete the corresponding Spotify playlist as well? @@ -1515,32 +1596,32 @@ connect and stream from you? Tomahawk::Accounts::AccountDelegate - + Add Account Konto hinzufügen - - Remove Account - Konto entfernen + + Remove + - + %1 downloads %1 Downloads - + Online Verbunden - + Connecting... Verbinde... - + Offline Nicht Verbunden @@ -1548,13 +1629,13 @@ connect and stream from you? Tomahawk::Accounts::AccountModel - + Manual Install Required - + Manuelle Installation benötigt - - Unfortunately, automatic installation of this resolver is not yet available on Linux.<br /><br />Please use "Install from file" above, by fetching it from your distribution or compiling it yourself. Further instructions can be found here:<br /><br />http://www.tomahawk-player.org/resolvers/%1 + + Unfortunately, automatic installation of this resolver is not available or disabled for your platform.<br /><br />Please use "Install from file" above, by fetching it from your distribution or compiling it yourself. Further instructions can be found here:<br /><br />http://www.tomahawk-player.org/resolvers/%1 @@ -1605,7 +1686,7 @@ connect and stream from you? Tomahawk::Accounts::LastFmAccountFactory - + Scrobble your tracks to last.fm, and find freely downloadable tracks to play Gehörte Stücke zu last.fm scrobbeln und frei-verfügbare Stücke anhören @@ -1613,23 +1694,49 @@ connect and stream from you? Tomahawk::Accounts::LastFmConfig - + + Testing... + + + + Test Login Login testen - - + + Importing %1 + e.g. Importing 2012/01/01 + + + + + Importing History... + + + + + History Incomplete. Resume + + + + + Playback History Imported + + + + + Failed Fehlgeschlagen - + Success Erfolgreich - + Could not contact server Konnte den Server nicht erreichen! @@ -1637,12 +1744,17 @@ connect and stream from you? Tomahawk::Accounts::SpotifyAccount - + Sync with Spotify Mit Spotify synchronisieren - + + Re-enable syncing with Spotify + + + + Stop syncing with Spotify Synchronisation beenden @@ -1650,22 +1762,22 @@ connect and stream from you? Tomahawk::Accounts::SpotifyAccountConfig - + Logging in... Anmelden... - + Logged in! Angemeldet! - + Failed: %1 Fehler: %1 - + Log In Anmelden @@ -1673,7 +1785,7 @@ connect and stream from you? Tomahawk::Accounts::SpotifyAccountFactory - + Play music from and sync your playlists with Spotify Premium Musik abspielen und Playlisten synchronisieren mit Spotify Premium @@ -1824,7 +1936,7 @@ You may wish to try re-authenticating. Tomahawk::Accounts::ZeroconfFactory - + Automatically connect to Tomahawks on the local network Automatisch mit anderen Tomahawks im Netzwerk verbinden @@ -1838,29 +1950,29 @@ You may wish to try re-authenticating. - - + + Add to &Queue In &Warteschlange einreihen - + &Love &Lieblingslied - + &Copy Track Link &Kopiere Link zu diesem Stück - + Un-&Love Kein &Lieblingslied - + &Delete Items Elemente &entfernen @@ -1875,22 +1987,22 @@ You may wish to try re-authenticating. Wiedergabe nach diesem Lied &stoppen - + &Show Track Page - + &Delete Item Element &entfernen - + &Show Album Page - + &Show Artist Page @@ -1931,12 +2043,32 @@ You may wish to try re-authenticating. Tomahawk::DropJobNotifier - + + playlist + + + + + artist + + + + + track + + + + + album + + + + Fetching %1 from database Lade %1 aus der Datenbank - + Parsing %1 %2 Parse %1 %2 @@ -1983,17 +2115,17 @@ Bitte ändere den Filter oder versuche es erneut. Tomahawk::DynamicView - + Add some filters above to seed this station! Füge einige Filter hinzu, um diese Station zu starten! - + Press Generate to get started! Drücke Erzeugen, und los geht's! - + Add some filters above, and press Generate to get started! Füge oben einige Filter hinzu und drücke Erzeugen um loszulegen! @@ -2001,7 +2133,7 @@ Bitte ändere den Filter oder versuche es erneut. Tomahawk::DynamicWidget - + Station ran out of tracks! Try tweaking the filters for a new set of songs to play. @@ -2274,7 +2406,7 @@ Versuch die Filter anzupassen für neue Lieder. about %n minute(s) long - ungefähr %n Minute langungefähr %n Minuten lang + ungefähr eine Minute langungefähr %n Minuten lang @@ -2320,92 +2452,92 @@ Versuch die Filter anzupassen für neue Lieder. Steuere diese Station: - + Much less Viel weniger - + Less Weniger - + A bit less Etwas weniger - + Keep at current So belassen - + A bit more Etwas mehr - + More Mehr - + Much more Viel mehr - + Tempo Tempo - + Loudness Lautstärke - + Danceability Tanzbarkeit - + Energy Energie - + Song Hotttnesss - + Artist Hotttnesss - + Artist Familiarity Ähnlichkeit Künstler - + By Description Von der Beschreibung - + Enter a description Gib eine Beschreibung ein - + Apply steering command Steuerkommando anwenden - + Reset all steering commands Setze alle Steuerkommandos zurück @@ -2421,22 +2553,22 @@ Versuch die Filter anzupassen für neue Lieder. Tomahawk::InfoSystem::ChartsPlugin - + Top Overall Top Allgemein - + Artists Künstler - + Albums Alben - + Tracks Stücke @@ -2457,27 +2589,27 @@ Versuch die Filter anzupassen für neue Lieder. Tomahawk::InfoSystem::LastFmInfoPlugin - + Top Tracks - + Loved Tracks - + Hyped Tracks - + Top Artists - + Hyped Artists @@ -2485,7 +2617,7 @@ Versuch die Filter anzupassen für neue Lieder. Tomahawk::InfoSystem::NewReleasesPlugin - + Albums Alben @@ -2493,7 +2625,7 @@ Versuch die Filter anzupassen für neue Lieder. Tomahawk::InfoSystem::TwitterInfoPlugin - + Listening to "%1" by %2 and loving it! %3 Höre "%1" von %2 und liebe es! %3 @@ -2551,37 +2683,37 @@ Versuch die Filter anzupassen für neue Lieder. Tomahawk::Query - + and und - + You Du - + you du - + and und - + %n other(s) %n anderer%n andere - + %1 people %1 Leute - + loved this track liebte dieses Lied @@ -2597,7 +2729,7 @@ Versuch die Filter anzupassen für neue Lieder. Tomahawk::ShortenedLinkParser - + Network error parsing shortened link! Konnte den Kurzlink nicht auflösen! @@ -2605,36 +2737,46 @@ Versuch die Filter anzupassen für neue Lieder. Tomahawk::Source - - + + Scanning (%L1 tracks) Scanne (%L1 Stücke) - + Scanning Scanne - + Checking Überprüfe - + Fetching Sammle - + Parsing Parse - + Saving (%1%) Speichere (%1%) + + + Online + + + + + Offline + + Tomahawk::SpotifyParser @@ -2655,7 +2797,7 @@ Versuch die Filter anzupassen für neue Lieder. TomahawkApp - + My Collection Meine Sammlung @@ -2678,39 +2820,48 @@ Tomahawk auf Twitter's Website authentifiziert hast: TomahawkTrayIcon - - + &Stop Playback after current Track Wiedergabe nach diesem Lied &stoppen - - + + Hide Tomahawk Window Tomahawk verbergen - + Show Tomahawk Window Tomahawk anzeigen - + Currently not playing. Derzeit wird nichts gespielt. - + Play Abspielen - + Pause Pause - + + &Love + + + + + Un-&Love + + + + &Continue Playback after current Track Wiedergabe nach diesem Lied &fortsetzen @@ -2854,7 +3005,7 @@ Tomahawk auf Twitter's Website authentifiziert hast: - + Play Abspielen @@ -2873,163 +3024,173 @@ Tomahawk auf Twitter's Website authentifiziert hast: Next Weiter - - - Back - - - - - Go back one page - - - - - Forward - - - - - Go forward one page - - + Back + Zurück + + + + Go back one page + Gehe eine Seite zurück + + + + Forward + Vorwärts + + + + Go forward one page + Gehe eine Seite vorwärts + + + Global Search... Globale Suche... - - + + Check For Updates... Nach Updates suchen... - - - + + + Connect To Peer Mit anderem Tomahawk verbinden - + Enter peer address: Gib die Adresse der Gegenstelle ein: - + Enter peer port: Gib den Port der Gegenstelle ein: - + Enter peer key: Gib den Schlüssel der Gegenstelle ein: - + XSPF Error XSPF-Fehler - + This is not a valid XSPF playlist. Dies ist keine gültige XSPF-Playliste. - + Failed to save tracks Konnte Stücke nicht abspeichern - + Some tracks in the playlist do not contain an artist and a title. They will be ignored. Einige Stücke in der Playliste enthalten weder Künstler noch Titel. Diese werden ignoriert. - + Sorry, there is a problem accessing your audio device or the desired track, current track will be skipped. Make sure you have a suitable Phonon backend and required plugins installed. Es tut uns leid, Tomahawk kann auf dein Audio-Gerät oder das gewünschte Stück nicht zugreifen und überspringt es deshalb. Vergewisser dich, dass ein geignetes Phonon-Backend mitsamt benötigten Plugins installiert ist. - + Sorry, there is a problem accessing your audio device or the desired track, current track will be skipped. Es tut uns leid, Tomahawk kann auf dein Audio-Gerät oder das gewünschte Stück nicht zugreifen und überspringt es deshalb. - + + Station + + + + Create New Station Neue Station erstellen - + Name: Name: - - New Station - Neue Station + + Playlist + - - New Playlist - Neue Playliste + + Automatic Playlist + - + Pause Pause - + Go &offline Verbindung &trennen - + Go &online &Verbindung herstellen - + Authentication Error Authentifizierungsfehler - + Error connecting to SIP: Authentication failed! - + %1 by %2 track, artist name %1 von %2 - + %1 - %2 current track, some window title %1 - %2 - + <h2><b>Tomahawk %1<br/>(%2)</h2> <h2><b>Tomahawk %1<br/>(%2)</h2> - + <h2><b>Tomahawk %1</h2> <h2><b>Tomahawk %1</h2> - - Copyright 2010 - 2012<br/>Christian Muehlhaeuser &lt;muesli@tomahawk-player.org&gt;<br/><br/>Thanks to: Leo Franchi, Jeff Mitchell, Dominik Schmidt, Jason Herskowitz, Alejandro Wainzinger, Hugo Lindstr&ouml;m, Michael Zanetti, Harald Sitter and Steve Robertson - Copyright 2010 - 2012<br/>Christian Muehlhaeuser &lt;muesli@tomahawk-player.org&gt;<br/><br/>Danke an: Leo Franchi, Jeff Mitchell, Dominik Schmidt, Jason Herskowitz, Alejandro Wainzinger, Hugo Lindstr&ouml;m, Michael Zanetti, Harald Sitter und Steve Robertson + + Copyright 2010 - 2012 + - + + Thanks to: + + + + About Tomahawk Über Tomahawk @@ -3100,7 +3261,7 @@ Tomahawk auf Twitter's Website authentifiziert hast: TopTracksContext - + Top Hits Top Hits @@ -3113,143 +3274,70 @@ Tomahawk auf Twitter's Website authentifiziert hast: Formular - + Cover Cover - + Track Lied - - by - von - - - + Artist Künstler - - from - auf - - - + Album Album - + Statistics Statistiken - - Lyrics - - - - + Similar Tracks Ähnliche Lieder + + + Sorry, but we could not find similar tracks for this song! + + - + You've listened to this track %n time(s). Du hast dieses Lied einmal gehört.Du hast dieses Lied %n mal gehört. - + You've never listened to this track before. - + Du hast dieses Lied noch nie angehört. - + You first listened to it on %1. - + Du hast dieses Lied zum ersten mal am %1 gehört. - + You've listened to %1 %n time(s). - + Du hast %1 einmal angehört.Du hast %1 %n mal angehört. - + You've never listened to %1 before. - - - - - TrackModel - - - Artist - Künstler - - - - Title - Titel - - - - Album - Album - - - - Track - Titel - - - - Duration - Spieldauer - - - - Bitrate - Bitrate - - - - Age - Alter - - - - Year - Jahr - - - - Size - Größe - - - - Origin - Quelle - - - - Score - Wertung - - - - Composer - Komponist + Du hast %1 vorher noch nie gehört. TrackView - + Sorry, your filter '%1' did not match any results. Entschuldige, dein Filter '%1' erzeugte keine Ergebnisse. @@ -3278,63 +3366,31 @@ Tomahawk auf Twitter's Website authentifiziert hast: TreeModel - - Name - Name - - - - Duration - Dauer - - - - Bitrate - Bitrate - - - - Age - Alter - - - - Year - Jahr - - - - Size - Größe - - - - Origin - Quelle - - - - Composer - Komponist - - - + All Artists Alle Künstler - - + + My Collection Meine Sammlung - - + + Collection of %1 Sammlung von %1 + + TreeView + + + Sorry, your filter '%1' did not match any results. + + + TwitterConfigWidget @@ -3406,29 +3462,39 @@ You can re-send a sync message at any time simply by sending another tweet using ViewManager - + + After you have scanned your music collection you will find your tracks right here. + + + + + This collection is empty. + + + + SuperCollection SuperCollection - + Combined libraries of all your online friends Kombinierte Sammlung all deiner Freunde - + All available albums Alle verfügbaren Alben - + Recently Played Tracks - + Zuletzt gehörte Lieder - + Recently played tracks from all your friends - + Zuletzt gehörte Lieder all deiner Freunde @@ -3449,12 +3515,12 @@ You can re-send a sync message at any time simply by sending another tweet using Kürzlich gehörte Lieder - + No recently created playlists in your network. Es gibt keine kürzlich erstellten Playlisten in deinem Netzwerk. - + Welcome to Tomahawk Willkommen bei Tomahawk @@ -3462,7 +3528,7 @@ You can re-send a sync message at any time simply by sending another tweet using WhatsHotWidget - + Charts Charts @@ -3696,107 +3762,107 @@ Lyrics for "%1" by %2: XmppSipPlugin - + User Interaction Nutzer Interaktion - + Host is unknown Host ist unbekannt - + Item not found Eintrag nicht gefunden - + Authorization Error Authentifizierungs Fehler - + Remote Stream Error - + Remote Connection failed - + Internal Server Error Interner Server Fehler - + System shutdown - + Conflict Konflikt - + Unknown Unbekannt - + No Compression Support Keine Kompressions Option - + No Encryption Support Keine Verschluesselungs Option - + No Authorization Support Keine Authorisierungs Option - + No Supported Feature Keine unterstuetzte Faehigkeit - + Add Friend Freund hinzufügen... - + Enter Xmpp ID: XMPP-Benutzer: - + Add Friend... Freund hinzufügen... - + XML Console... XML-Konsole... - + I'm sorry -- I'm just an automatic presence used by Tomahawk Player (http://gettomahawk.com). If you are getting this message, the person you are trying to reach is probably not signed on, so please try again later! - + Authorize User Authorisiere Nutzer - + Do you want to grant <b>%1</b> access to your Collection? Willst du <b>%1</b> Zugriff auf deine Sammlung gewähren? diff --git a/lang/tomahawk_en.ts b/lang/tomahawk_en.ts index 2d9b5acf8..931320c8e 100644 --- a/lang/tomahawk_en.ts +++ b/lang/tomahawk_en.ts @@ -2,17 +2,17 @@ AccountFactoryWrapper - + Dialog Dialog - + Description goes here Description goes here - + Add Account Add Account @@ -20,17 +20,17 @@ AccountFactoryWrapperDelegate - + Online Online - + Connecting... Connecting... - + Offline Offline @@ -134,7 +134,17 @@ connect and stream from you? Other Albums by Artist - + + Sorry, we could not find any other albums for this artist! + Sorry, we could not find any other albums for this artist! + + + + Sorry, we could not find any tracks for this album! + Sorry, we could not find any tracks for this album! + + + Other Albums by %1 Other Albums by %1 @@ -142,35 +152,17 @@ connect and stream from you? AlbumModel - - Album - Album - - - - + + All albums from %1 All albums from %1 - + All albums All albums - - AlbumView - - - After you have scanned your music collection you will find your latest album additions right here. - After you have scanned your music collection you will find your latest album additions right here. - - - - This collection doesn't have any recent albums. - This collection doesn't have any recent albums. - - ArtistInfoWidget @@ -179,12 +171,12 @@ connect and stream from you? Form - + Top Hits Top Hits - + Related Artists Related Artists @@ -193,23 +185,25 @@ connect and stream from you? Albums Albums - - - ArtistView - - After you have scanned your music collection you will find your tracks right here. - After you have scanned your music collection you will find your tracks right here. + + Cover + Cover - - This collection is currently empty. - This collection is currently empty. + + Sorry, we could not find any albums for this artist! + Sorry, we could not find any albums for this artist! - - Sorry, your filter '%1' did not match any results. - Sorry, your filter '%1' did not match any results. + + Sorry, we could not find any related artists! + Sorry, we could not find any related artists! + + + + Sorry, we could not find any top hits for this artist! + Sorry, we could not find any top hits for this artist! @@ -235,57 +229,57 @@ connect and stream from you? Next - + Artist Artist - + Album Album - + Owner Owner - + social social - + love love - + Time Time - + Time Left Time Left - + Shuffle Shuffle - + Repeat Repeat - + Low Low - + High High @@ -294,22 +288,25 @@ connect and stream from you? CategoryAddItem - - New Playlist - New Playlist + Create new Playlist + Create new Playlist - - - - + + Create new Station + Create new Station + + + + + New Station New Station - - - + + + %1 Station %1 Station @@ -335,27 +332,6 @@ connect and stream from you? Clear - - CollectionFlatModel - - - My Collection - My Collection - - - - Collection of %1 - Collection of %1 - - - - CollectionView - - - This collection is empty. - This collection is empty. - - ContextWidget @@ -365,12 +341,12 @@ connect and stream from you? - + Show Footnotes Show Footnotes - + Hide Footnotes Hide Footnotes @@ -384,8 +360,8 @@ connect and stream from you? - <html><head/><body><p><span style=" font-weight:600;">Sorry!</span> Tomahawk crashed. Please tell us about it! Tomahawk has created an error report for you that can help improve the stability in the future. You can now send the this report directly to the Tomahawk developers.</p></body></html> - <html><head/><body><p><span style=" font-weight:600;">Sorry!</span> Tomahawk crashed. Please tell us about it! Tomahawk has created an error report for you that can help improve the stability in the future. You can now send the this report directly to the Tomahawk developers.</p></body></html> + <html><head/><body><p><span style=" font-weight:600;">Sorry!</span> Tomahawk crashed. Please tell us about it! Tomahawk 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 Tomahawk developers.</p></body></html> + <html><head/><body><p><span style=" font-weight:600;">Sorry!</span> Tomahawk crashed. Please tell us about it! Tomahawk 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 Tomahawk developers.</p></body></html> @@ -440,17 +416,17 @@ connect and stream from you? DelegateConfigWrapper - + About About - + Delete Account Delete Account - + About this Account About this Account @@ -463,24 +439,11 @@ connect and stream from you? Tomahawk Diagnostics - - Update - Update - - - + Copy to Clipboard Copy to Clipboard - - DropJob - - - No tracks found for given %1 - No tracks found for given %1 - - GlobalSearchWidget @@ -505,56 +468,43 @@ connect and stream from you? InfoBar - + Filter... Filter... - - JobStatusView - - - Searching For - Searching For - - - - Pending - Pending - - - - Idle - Idle - - LastFmConfig - + Form Form - + Scrobble tracks to Last.fm Scrobble tracks to Last.fm - + Username: Username: - + Password: Password: - + Test Login Test Login + + + Import Playback History + Import Playback History + LastfmContext @@ -657,11 +607,80 @@ connect and stream from you? NewReleasesWidget - + New Releases New Releases + + PlayableModel + + + Artist + Artist + + + + Title + Title + + + + Composer + Composer + + + + Album + Album + + + + Track + Track + + + + Duration + Duration + + + + Bitrate + Bitrate + + + + Age + Age + + + + Year + Year + + + + Size + Size + + + + Origin + Origin + + + + Score + Score + + + + + Name + Name + + PlaylistItemDelegate @@ -678,17 +697,17 @@ connect and stream from you? PlaylistLargeItemDelegate - + played %1 by you played %1 by you - + played %1 by %2 played %1 by %2 - + added %1 added %1 @@ -696,12 +715,12 @@ connect and stream from you? PlaylistModel - + A playlist by %1, created %2 A playlist by %1, created %2 - + you you @@ -757,7 +776,12 @@ connect and stream from you? PlaylistView - + + This playlist is currently empty. + This playlist is currently empty. + + + This playlist is currently empty. Add some tracks to it and enjoy the music! This playlist is currently empty. Add some tracks to it and enjoy the music! @@ -825,67 +849,67 @@ connect and stream from you? QObject - + %n year(s) ago %n year ago%n years ago - + %n year(s) %n year%n years - + %n month(s) ago %n month ago%n months ago - + %n month(s) %n month%n months - + %n week(s) ago %n week ago%n weeks ago - + %n week(s) %n week%n weeks - + %n day(s) ago %n day ago%n days ago - + %n day(s) %n day%n days - + %n hour(s) ago %n hour ago%n hours ago - + %n hour(s) %n hour%n hours - + %1 minutes ago %1 minutes ago - + %1 minutes %1 minutes - + just now just now @@ -922,20 +946,25 @@ connect and stream from you? - - Show Queue - Show Queue + + Open Queue + Open Queue + + + + Open Queue - %n item(s) + Open Queue - %n item(s)Open Queue - %n item(s) - - Hide Queue - Hide Queue + + Close Queue + Close Queue RelatedArtistsContext - + Related Artists Related Artists @@ -1058,17 +1087,22 @@ connect and stream from you? TextLabel - - Listening to "%1" by %2 and loving it! %3 - Listening to "%1" by %2 and loving it! %3 + + Tweet + Tweet - - Listening to "%1" by %2 on "%3" and loving it! %4 - Listening to "%1" by %2 on "%3" and loving it! %4 + + Listening to "%1" by %2. %3 + Listening to "%1" by %2. %3 - + + Listening to "%1" by %2 on "%3". %4 + Listening to "%1" by %2 on "%3". %4 + + + %1 characters left %1 characters left @@ -1101,29 +1135,19 @@ connect and stream from you? Top 10 - - Offline - Offline - - - + All available tracks All available tracks - - Online - Online - - - - + + Show Show - - + + Hide Hide @@ -1146,17 +1170,17 @@ connect and stream from you? Recently Played Tracks - + New Additions New Additions - + My recent activity My recent activity - + Recent activity from %1 Recent activity from %1 @@ -1164,81 +1188,138 @@ connect and stream from you? SourceItem - + Collection Collection - - + + Latest Additions Latest Additions - + Recently Played Recently Played - + Loved Tracks Loved Tracks - + SuperCollection SuperCollection - + + Sorry, we could not find any loved tracks! + Sorry, we could not find any loved tracks! + + + Latest additions to your collection Latest additions to your collection - + Latest additions to %1's collection Latest additions to %1's collection - + + Sorry, we could not find any recent additions! + Sorry, we could not find any recent additions! + + + Recently Played Tracks Recently Played Tracks - + Your recently played tracks Your recently played tracks - + %1's recently played tracks %1's recently played tracks + + + Sorry, we could not find any recent plays! + Sorry, we could not find any recent plays! + SourceTreeView - + &Copy Link &Copy Link - + &Delete %1 &Delete %1 - + + Add to my Playlists + Add to my Playlists + + + + Add to my Automatic Playlists + Add to my Automatic Playlists + + + + Add to my Stations + Add to my Stations + + + &Export Playlist &Export Playlist - + + playlist + playlist + + + + automatic playlist + automatic playlist + + + + station + station + + + + Delete %1? + playlist/station/... + Delete %1? + + + + Would you like to delete the %1 <b>"%2"</b>? + e.g. Would you like to delete the playlist named Foobar? + Would you like to delete the %1 <b>"%2"</b>? + + + Save XSPF Save XSPF - + Playlists (*.xspf) Playlists (*.xspf) @@ -1271,52 +1352,52 @@ connect and stream from you? Station - + Browse Browse - + Search History Search History - + My Music My Music - + SuperCollection SuperCollection - + Top Loved Tracks Top Loved Tracks - + Dashboard Dashboard - + Recently Played Recently Played - + Charts Charts - + New Releases New Releases - + Friends Friends @@ -1324,52 +1405,52 @@ connect and stream from you? SpotifyConfig - + Form Form - + Configure your Spotify account Configure your Spotify account - + Username or Facebook Email Username or Facebook Email - + Log In Log In - + Right click on any Tomahawk playlist to sync it to Spotify. Right click on any Tomahawk playlist to sync it to Spotify. - + High Quality Streams High Quality Streams - + Spotify playlists to keep in sync: Spotify playlists to keep in sync: - + Delete Tomahawk playlist when removing synchronization Delete Tomahawk playlist when removing synchronization - + Username: Username: - + Password: Password: @@ -1377,12 +1458,12 @@ connect and stream from you? SpotifyPlaylistUpdater - + Delete in Spotify? Delete in Spotify? - + Would you like to delete the corresponding Spotify playlist as well? Would you like to delete the corresponding Spotify playlist as well? @@ -1519,32 +1600,32 @@ connect and stream from you? Tomahawk::Accounts::AccountDelegate - + Add Account Add Account - - Remove Account - Remove Account + + Remove + Remove - + %1 downloads %1 downloads - + Online Online - + Connecting... Connecting... - + Offline Offline @@ -1552,14 +1633,14 @@ connect and stream from you? Tomahawk::Accounts::AccountModel - + Manual Install Required Manual Install Required - - Unfortunately, automatic installation of this resolver is not yet available on Linux.<br /><br />Please use "Install from file" above, by fetching it from your distribution or compiling it yourself. Further instructions can be found here:<br /><br />http://www.tomahawk-player.org/resolvers/%1 - Unfortunately, automatic installation of this resolver is not yet available on Linux.<br /><br />Please use "Install from file" above, by fetching it from your distribution or compiling it yourself. Further instructions can be found here:<br /><br />http://www.tomahawk-player.org/resolvers/%1 + + Unfortunately, automatic installation of this resolver is not available or disabled for your platform.<br /><br />Please use "Install from file" above, by fetching it from your distribution or compiling it yourself. Further instructions can be found here:<br /><br />http://www.tomahawk-player.org/resolvers/%1 + Unfortunately, automatic installation of this resolver is not available or disabled for your platform.<br /><br />Please use "Install from file" above, by fetching it from your distribution or compiling it yourself. Further instructions can be found here:<br /><br />http://www.tomahawk-player.org/resolvers/%1 @@ -1609,7 +1690,7 @@ connect and stream from you? Tomahawk::Accounts::LastFmAccountFactory - + Scrobble your tracks to last.fm, and find freely downloadable tracks to play Scrobble your tracks to last.fm, and find freely downloadable tracks to play @@ -1617,23 +1698,49 @@ connect and stream from you? Tomahawk::Accounts::LastFmConfig - + + Testing... + Testing... + + + Test Login Test Login - - + + Importing %1 + e.g. Importing 2012/01/01 + Importing %1 + + + + Importing History... + Importing History... + + + + History Incomplete. Resume + History Incomplete. Resume + + + + Playback History Imported + Playback History Imported + + + + Failed Failed - + Success Success - + Could not contact server Could not contact server @@ -1641,12 +1748,17 @@ connect and stream from you? Tomahawk::Accounts::SpotifyAccount - + Sync with Spotify Sync with Spotify - + + Re-enable syncing with Spotify + Re-enable syncing with Spotify + + + Stop syncing with Spotify Stop syncing with Spotify @@ -1654,22 +1766,22 @@ connect and stream from you? Tomahawk::Accounts::SpotifyAccountConfig - + Logging in... Logging in... - + Logged in! Logged in! - + Failed: %1 Failed: %1 - + Log In Log In @@ -1677,7 +1789,7 @@ connect and stream from you? Tomahawk::Accounts::SpotifyAccountFactory - + Play music from and sync your playlists with Spotify Premium Play music from and sync your playlists with Spotify Premium @@ -1830,7 +1942,7 @@ You may wish to try re-authenticating. Tomahawk::Accounts::ZeroconfFactory - + Automatically connect to Tomahawks on the local network Automatically connect to Tomahawks on the local network @@ -1844,29 +1956,29 @@ You may wish to try re-authenticating. - - + + Add to &Queue Add to &Queue - + &Love &Love - + &Copy Track Link &Copy Track Link - + Un-&Love Un-&Love - + &Delete Items &Delete Items @@ -1881,22 +1993,22 @@ You may wish to try re-authenticating. &Stop Playback after this Track - + &Show Track Page &Show Track Page - + &Delete Item &Delete Item - + &Show Album Page &Show Album Page - + &Show Artist Page &Show Artist Page @@ -1937,12 +2049,32 @@ You may wish to try re-authenticating. Tomahawk::DropJobNotifier - + + playlist + playlist + + + + artist + artist + + + + track + track + + + + album + album + + + Fetching %1 from database Fetching %1 from database - + Parsing %1 %2 Parsing %1 %2 @@ -1989,17 +2121,17 @@ Please change the filters or try again. Tomahawk::DynamicView - + Add some filters above to seed this station! Add some filters above to seed this station! - + Press Generate to get started! Press Generate to get started! - + Add some filters above, and press Generate to get started! Add some filters above, and press Generate to get started! @@ -2007,7 +2139,7 @@ Please change the filters or try again. Tomahawk::DynamicWidget - + Station ran out of tracks! Try tweaking the filters for a new set of songs to play. @@ -2326,92 +2458,92 @@ Try tweaking the filters for a new set of songs to play. Steer this station: - + Much less Much less - + Less Less - + A bit less A bit less - + Keep at current Keep at current - + A bit more A bit more - + More More - + Much more Much more - + Tempo Tempo - + Loudness Loudness - + Danceability Danceability - + Energy Energy - + Song Hotttnesss Song Hotttnesss - + Artist Hotttnesss Artist Hotttnesss - + Artist Familiarity Artist Familiarity - + By Description By Description - + Enter a description Enter a description - + Apply steering command Apply steering command - + Reset all steering commands Reset all steering commands @@ -2427,22 +2559,22 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::InfoSystem::ChartsPlugin - + Top Overall Top Overall - + Artists Artists - + Albums Albums - + Tracks Tracks @@ -2463,27 +2595,27 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::InfoSystem::LastFmInfoPlugin - + Top Tracks Top Tracks - + Loved Tracks Loved Tracks - + Hyped Tracks Hyped Tracks - + Top Artists Top Artists - + Hyped Artists Hyped Artists @@ -2491,7 +2623,7 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::InfoSystem::NewReleasesPlugin - + Albums Albums @@ -2499,7 +2631,7 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::InfoSystem::TwitterInfoPlugin - + Listening to "%1" by %2 and loving it! %3 Listening to "%1" by %2 and loving it! %3 @@ -2557,37 +2689,37 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::Query - + and and - + You You - + you you - + and and - + %n other(s) %n other%n others - + %1 people %1 people - + loved this track loved this track @@ -2603,7 +2735,7 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::ShortenedLinkParser - + Network error parsing shortened link! Network error parsing shortened link! @@ -2611,36 +2743,46 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::Source - - + + Scanning (%L1 tracks) Scanning (%L1 tracks) - + Scanning Scanning - + Checking Checking - + Fetching Fetching - + Parsing Parsing - + Saving (%1%) Saving (%1%) + + + Online + Online + + + + Offline + Offline + Tomahawk::SpotifyParser @@ -2661,7 +2803,7 @@ Try tweaking the filters for a new set of songs to play. TomahawkApp - + My Collection My Collection @@ -2684,39 +2826,48 @@ enter the displayed PIN number here: TomahawkTrayIcon - - + &Stop Playback after current Track &Stop Playback after current Track - - + + Hide Tomahawk Window Hide Tomahawk Window - + Show Tomahawk Window Show Tomahawk Window - + Currently not playing. Currently not playing. - + Play Play - + Pause Pause - + + &Love + &Love + + + + Un-&Love + Un-&Love + + + &Continue Playback after current Track &Continue Playback after current Track @@ -2860,7 +3011,7 @@ enter the displayed PIN number here: - + Play Play @@ -2880,162 +3031,172 @@ enter the displayed PIN number here: Next - + Back Back - + Go back one page Go back one page - + Forward Forward - + Go forward one page Go forward one page - + Global Search... Global Search... - - + + Check For Updates... Check For Updates... - - - + + + Connect To Peer Connect To Peer - + Enter peer address: Enter peer address: - + Enter peer port: Enter peer port: - + Enter peer key: Enter peer key: - + XSPF Error XSPF Error - + This is not a valid XSPF playlist. This is not a valid XSPF playlist. - + Failed to save tracks Failed to save tracks - + Some tracks in the playlist do not contain an artist and a title. They will be ignored. Some tracks in the playlist do not contain an artist and a title. They will be ignored. - + Sorry, there is a problem accessing your audio device or the desired track, current track will be skipped. Make sure you have a suitable Phonon backend and required plugins installed. Sorry, there is a problem accessing your audio device or the desired track, current track will be skipped. Make sure you have a suitable Phonon backend and required plugins installed. - + Sorry, there is a problem accessing your audio device or the desired track, current track will be skipped. Sorry, there is a problem accessing your audio device or the desired track, current track will be skipped. - + + Station + Station + + + Create New Station Create New Station - + Name: Name: - - New Station - New Station + + Playlist + Playlist - - New Playlist - New Playlist + + Automatic Playlist + Automatic Playlist - + Pause Pause - + Go &offline Go &offline - + Go &online Go &online - + Authentication Error Authentication Error - + Error connecting to SIP: Authentication failed! Error connecting to SIP: Authentication failed! - + %1 by %2 track, artist name %1 by %2 - + %1 - %2 current track, some window title %1 - %2 - + <h2><b>Tomahawk %1<br/>(%2)</h2> <h2><b>Tomahawk %1<br/>(%2)</h2> - + <h2><b>Tomahawk %1</h2> <h2><b>Tomahawk %1</h2> - - Copyright 2010 - 2012<br/>Christian Muehlhaeuser &lt;muesli@tomahawk-player.org&gt;<br/><br/>Thanks to: Leo Franchi, Jeff Mitchell, Dominik Schmidt, Jason Herskowitz, Alejandro Wainzinger, Hugo Lindstr&ouml;m, Michael Zanetti, Harald Sitter and Steve Robertson - Copyright 2010 - 2012<br/>Christian Muehlhaeuser &lt;muesli@tomahawk-player.org&gt;<br/><br/>Thanks to: Leo Franchi, Jeff Mitchell, Dominik Schmidt, Jason Herskowitz, Alejandro Wainzinger, Hugo Lindstr&ouml;m, Michael Zanetti, Harald Sitter and Steve Robertson + + Copyright 2010 - 2012 + Copyright 2010 - 2012 - + + Thanks to: + Thanks to: + + + About Tomahawk About Tomahawk @@ -3106,7 +3267,7 @@ enter the displayed PIN number here: TopTracksContext - + Top Hits Top Hits @@ -3119,143 +3280,70 @@ enter the displayed PIN number here: Form - + Cover Cover - + Track Track - - by - by - - - + Artist Artist - - from - from - - - + Album Album - + Statistics Statistics - - Lyrics - Lyrics - - - + Similar Tracks Similar Tracks + + + Sorry, but we could not find similar tracks for this song! + Sorry, but we could not find similar tracks for this song! + - + You've listened to this track %n time(s). You've listened to this track %n time(s).You've listened to this track %n time(s). - + You've never listened to this track before. You've never listened to this track before. - + You first listened to it on %1. You first listened to it on %1. - + You've listened to %1 %n time(s). You've listened to %1 %n time(s).You've listened to %1 %n time(s). - + You've never listened to %1 before. You've never listened to %1 before. - - TrackModel - - - Artist - Artist - - - - Title - Title - - - - Album - Album - - - - Track - Track - - - - Duration - Duration - - - - Bitrate - Bitrate - - - - Age - Age - - - - Year - Year - - - - Size - Size - - - - Origin - Origin - - - - Score - Score - - - - Composer - Composer - - TrackView - + Sorry, your filter '%1' did not match any results. Sorry, your filter '%1' did not match any results. @@ -3284,63 +3372,31 @@ enter the displayed PIN number here: TreeModel - - Name - Name - - - - Duration - Duration - - - - Bitrate - Bitrate - - - - Age - Age - - - - Year - Year - - - - Size - Size - - - - Origin - Origin - - - - Composer - Composer - - - + All Artists All Artists - - + + My Collection My Collection - - + + Collection of %1 Collection of %1 + + TreeView + + + Sorry, your filter '%1' did not match any results. + Sorry, your filter '%1' did not match any results. + + TwitterConfigWidget @@ -3417,27 +3473,37 @@ You can re-send a sync message at any time simply by sending another tweet using ViewManager - + + After you have scanned your music collection you will find your tracks right here. + After you have scanned your music collection you will find your tracks right here. + + + + This collection is empty. + This collection is empty. + + + SuperCollection SuperCollection - + Combined libraries of all your online friends Combined libraries of all your online friends - + All available albums All available albums - + Recently Played Tracks Recently Played Tracks - + Recently played tracks from all your friends Recently played tracks from all your friends @@ -3460,12 +3526,12 @@ You can re-send a sync message at any time simply by sending another tweet using Recently Played Tracks - + No recently created playlists in your network. No recently created playlists in your network. - + Welcome to Tomahawk Welcome to Tomahawk @@ -3473,7 +3539,7 @@ You can re-send a sync message at any time simply by sending another tweet using WhatsHotWidget - + Charts Charts @@ -3712,107 +3778,107 @@ Lyrics for "%1" by %2: XmppSipPlugin - + User Interaction User Interaction - + Host is unknown Host is unknown - + Item not found Item not found - + Authorization Error Authorization Error - + Remote Stream Error Remote Stream Error - + Remote Connection failed Remote Connection failed - + Internal Server Error Internal Server Error - + System shutdown System shutdown - + Conflict Conflict - + Unknown Unknown - + No Compression Support No Compression Support - + No Encryption Support No Encryption Support - + No Authorization Support No Authorization Support - + No Supported Feature No Supported Feature - + Add Friend Add Friend - + Enter Xmpp ID: Enter Xmpp ID: - + Add Friend... Add Friend... - + XML Console... XML Console... - + I'm sorry -- I'm just an automatic presence used by Tomahawk Player (http://gettomahawk.com). If you are getting this message, the person you are trying to reach is probably not signed on, so please try again later! I'm sorry -- I'm just an automatic presence used by Tomahawk Player (http://gettomahawk.com). If you are getting this message, the person you are trying to reach is probably not signed on, so please try again later! - + Authorize User Authorize User - + Do you want to grant <b>%1</b> access to your Collection? Do you want to grant <b>%1</b> access to your Collection? diff --git a/lang/tomahawk_es.ts b/lang/tomahawk_es.ts index 797b84c42..804bc8eb5 100644 --- a/lang/tomahawk_es.ts +++ b/lang/tomahawk_es.ts @@ -2,17 +2,17 @@ AccountFactoryWrapper - + Dialog Diálogo - + Description goes here Descripción - + Add Account Añadir Cuenta @@ -20,17 +20,17 @@ AccountFactoryWrapperDelegate - + Online Conectado - + Connecting... Conectando... - + Offline Desconectado @@ -133,7 +133,17 @@ connect and stream from you? Otros álbumes por el artista - + + Sorry, we could not find any other albums for this artist! + + + + + Sorry, we could not find any tracks for this album! + + + + Other Albums by %1 Otros álbumes por %1 @@ -141,35 +151,17 @@ connect and stream from you? AlbumModel - - Album - Álbum - - - - + + All albums from %1 Todos los álbumes de %1 - + All albums Todos los álbumes - - AlbumView - - - After you have scanned your music collection you will find your latest album additions right here. - Tras haber escaneado su colección aquí encontrará los últimos álbumes añadidos. - - - - This collection doesn't have any recent albums. - Esta colección no tiene álbumes recientes. - - ArtistInfoWidget @@ -178,12 +170,12 @@ connect and stream from you? Formulario - + Top Hits Grandes éxitos - + Related Artists Artistas relacionados @@ -192,23 +184,25 @@ connect and stream from you? Albums Álbumes - - - ArtistView - - After you have scanned your music collection you will find your tracks right here. - Tras haber escaneado su colección aquí encontrará las últimas pistas añadidas. + + Cover + - - This collection is currently empty. - Esta colección está vacía. + + Sorry, we could not find any albums for this artist! + - - Sorry, your filter '%1' did not match any results. - Tu filtro '%1' no reportó ningún resultado. + + Sorry, we could not find any related artists! + + + + + Sorry, we could not find any top hits for this artist! + @@ -234,57 +228,57 @@ connect and stream from you? Siguiente - + Artist Artista - + Album Álbum - + Owner Propietario - + social social - + love favorita - + Time Duración - + Time Left Tiempo restante - + Shuffle Aleatorio - + Repeat Repetir - + Low Bajar volumen - + High Subir volumen @@ -293,22 +287,25 @@ connect and stream from you? CategoryAddItem - - New Playlist - Nueva lista de reproducción + Create new Playlist + - - - - + + Create new Station + + + + + + New Station Nueva estación - - - + + + %1 Station %1 estación @@ -334,27 +331,6 @@ connect and stream from you? Limpiar - - CollectionFlatModel - - - My Collection - Mi colección - - - - Collection of %1 - Colección de %1 - - - - CollectionView - - - This collection is empty. - Esta colección está vacía. - - ContextWidget @@ -364,12 +340,12 @@ connect and stream from you? - + Show Footnotes Mostrar información de contexto - + Hide Footnotes Ocultar información de contexto @@ -383,7 +359,7 @@ connect and stream from you? - <html><head/><body><p><span style=" font-weight:600;">Sorry!</span> Tomahawk crashed. Please tell us about it! Tomahawk has created an error report for you that can help improve the stability in the future. You can now send the this report directly to the Tomahawk developers.</p></body></html> + <html><head/><body><p><span style=" font-weight:600;">Sorry!</span> Tomahawk crashed. Please tell us about it! Tomahawk 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 Tomahawk developers.</p></body></html> @@ -439,17 +415,17 @@ connect and stream from you? DelegateConfigWrapper - + About Acerca de - + Delete Account Eliminar Cuenta - + About this Account Acerca de esta Cuenta @@ -462,24 +438,11 @@ connect and stream from you? Diagnósticos de Tomahawk - - Update - Actualizar - - - + Copy to Clipboard Copiar al portapapeles - - DropJob - - - No tracks found for given %1 - Ninguna pista fue encontrada para %1 - - GlobalSearchWidget @@ -504,56 +467,43 @@ connect and stream from you? Barra de información - + Filter... Filtro... - - JobStatusView - - - Searching For - Buscando por - - - - Pending - Pendiente - - - - Idle - Ocupado - - LastFmConfig - + Form Formulario - + Scrobble tracks to Last.fm Hacer scrobble a las pistas en Last.fm - + Username: Usuario: - + Password: Contraseña: - + Test Login Probar conexión + + + Import Playback History + + LastfmContext @@ -656,11 +606,80 @@ connect and stream from you? NewReleasesWidget - + New Releases Últimas novedades + + PlayableModel + + + Artist + + + + + Title + + + + + Composer + + + + + Album + + + + + Track + + + + + Duration + + + + + Bitrate + + + + + Age + + + + + Year + + + + + Size + + + + + Origin + + + + + Score + + + + + + Name + + + PlaylistItemDelegate @@ -677,17 +696,17 @@ connect and stream from you? PlaylistLargeItemDelegate - + played %1 by you %1 reproducido por usted - + played %1 by %2 %1 reproducido por %2 - + added %1 añadio %1 @@ -695,12 +714,12 @@ connect and stream from you? PlaylistModel - + A playlist by %1, created %2 Una lista de reproducción de %1, creada %2 - + you usted @@ -756,7 +775,12 @@ connect and stream from you? PlaylistView - + + This playlist is currently empty. + + + + This playlist is currently empty. Add some tracks to it and enjoy the music! Esta lista de reproducción está vacía. ¡Añada algunas pistas y disfrute de la música! @@ -823,67 +847,67 @@ connect and stream from you? QObject - + %n year(s) ago hace %n añohace%n años - + %n year(s) %n año%n años - + %n month(s) ago hace %n meshace %n meses - + %n month(s) %n mes%n meses - + %n week(s) ago hace %n semanahace %n semanas - + %n week(s) %n semana%n semanas - + %n day(s) ago hace %n díahace %n días - + %n day(s) %n día%n días - + %n hour(s) ago hace %n horahace %n horas - + %n hour(s) %n hora%n horas - + %1 minutes ago hace %1 minutos - + %1 minutes %1 minutos - + just now justo ahora @@ -920,20 +944,25 @@ connect and stream from you? - - Show Queue - Mostrar cola + + Open Queue + + + + + Open Queue - %n item(s) + - - Hide Queue - Ocultar cola + + Close Queue + RelatedArtistsContext - + Related Artists Artistas relacionados @@ -1056,17 +1085,22 @@ connect and stream from you? TextLabel - - Listening to "%1" by %2 and loving it! %3 - Escuchando "%1" de %2 y me encanta! %3 + + Tweet + - - Listening to "%1" by %2 on "%3" and loving it! %4 - Escuchando "%1" de %2 en "%3" y me encanta! %4 + + Listening to "%1" by %2. %3 + - + + Listening to "%1" by %2 on "%3". %4 + + + + %1 characters left %1 caracteres restantes @@ -1099,29 +1133,19 @@ connect and stream from you? Top 10 - - Offline - Desconectado - - - + All available tracks Todas las pistas disponibles - - Online - Conectado - - - - + + Show Mostrar - - + + Hide Ocultar @@ -1144,17 +1168,17 @@ connect and stream from you? Pistas reproducidas recientemente - + New Additions Nuevas adiciones - + My recent activity Mi actividad reciente - + Recent activity from %1 Actividad reciente de %1 @@ -1162,81 +1186,138 @@ connect and stream from you? SourceItem - + Collection Colección - - + + Latest Additions Añadidos recientemente - + Recently Played Reproducido recientemente - + Loved Tracks Pistas favoritas - + SuperCollection SuperColección - + + Sorry, we could not find any loved tracks! + + + + Latest additions to your collection Últimas novedades en mi colección - + Latest additions to %1's collection Últimas novedadoes en la colección de %1 - + + Sorry, we could not find any recent additions! + + + + Recently Played Tracks Temas Escuchados Recientemente - + Your recently played tracks Mis canciones escuchadas recientemente - + %1's recently played tracks Las canciones escuchadas recientemente por %1 + + + Sorry, we could not find any recent plays! + + SourceTreeView - + &Copy Link &Copiar enlace - + &Delete %1 &Eliminar %1 - + + Add to my Playlists + + + + + Add to my Automatic Playlists + + + + + Add to my Stations + + + + &Export Playlist &Exportar lista de reproducción - + + playlist + + + + + automatic playlist + + + + + station + + + + + Delete %1? + playlist/station/... + + + + + Would you like to delete the %1 <b>"%2"</b>? + e.g. Would you like to delete the playlist named Foobar? + + + + Save XSPF Guardar XSPF - + Playlists (*.xspf) Listas de reproducción (*.xspf) @@ -1269,52 +1350,52 @@ connect and stream from you? Estación - + Browse Buscar - + Search History Historial de Búsqueda - + My Music Mi Musica - + SuperCollection SuperColección - + Top Loved Tracks Pistas favoritas - + Dashboard Panel de inicio - + Recently Played Reproducido recientemente - + Charts Listas - + New Releases Últimas novedades - + Friends Amigos @@ -1322,52 +1403,52 @@ connect and stream from you? SpotifyConfig - + Form Formulario - + Configure your Spotify account Configura tu cuenta de Spotify - + Username or Facebook Email Usurio o dirección de correo de Facebook - + Log In Inciar Sesión - + Right click on any Tomahawk playlist to sync it to Spotify. Click derecho en cualquier lista de Tomahawk para sincronizar con Spotify. - + High Quality Streams Streams de Alta Calidad - + Spotify playlists to keep in sync: Listas de Spotify a mantener sincronizadas: - + Delete Tomahawk playlist when removing synchronization Borra las listas de Tomahawk cuando se quiten de la sincronización - + Username: Usuario: - + Password: Contraseña: @@ -1375,12 +1456,12 @@ connect and stream from you? SpotifyPlaylistUpdater - + Delete in Spotify? ¿Borrar en Spotify? - + Would you like to delete the corresponding Spotify playlist as well? Quieres eliminar la lista de Spotify correspondiente, también? @@ -1517,32 +1598,32 @@ y estaciones basadas en sus gustos personales. Tomahawk::Accounts::AccountDelegate - + Add Account Añadir Cuenta - - Remove Account - Eliminar Cuenta + + Remove + - + %1 downloads %1 descargas - + Online Conectado - + Connecting... Conectando... - + Offline Desconectado @@ -1550,13 +1631,13 @@ y estaciones basadas en sus gustos personales. Tomahawk::Accounts::AccountModel - + Manual Install Required - - Unfortunately, automatic installation of this resolver is not yet available on Linux.<br /><br />Please use "Install from file" above, by fetching it from your distribution or compiling it yourself. Further instructions can be found here:<br /><br />http://www.tomahawk-player.org/resolvers/%1 + + Unfortunately, automatic installation of this resolver is not available or disabled for your platform.<br /><br />Please use "Install from file" above, by fetching it from your distribution or compiling it yourself. Further instructions can be found here:<br /><br />http://www.tomahawk-player.org/resolvers/%1 @@ -1607,7 +1688,7 @@ y estaciones basadas en sus gustos personales. Tomahawk::Accounts::LastFmAccountFactory - + Scrobble your tracks to last.fm, and find freely downloadable tracks to play Hacer Scrobble de mis temas a last.fm y encontrar canciones gratuitas para reproducirlas @@ -1615,23 +1696,49 @@ y estaciones basadas en sus gustos personales. Tomahawk::Accounts::LastFmConfig - + + Testing... + + + + Test Login Comprobar Inicio de Sesión - - + + Importing %1 + e.g. Importing 2012/01/01 + + + + + Importing History... + + + + + History Incomplete. Resume + + + + + Playback History Imported + + + + + Failed Fallo - + Success Éxito - + Could not contact server No se pudo contactar el servidor @@ -1639,12 +1746,17 @@ y estaciones basadas en sus gustos personales. Tomahawk::Accounts::SpotifyAccount - + Sync with Spotify Sincronizar con Spotify - + + Re-enable syncing with Spotify + + + + Stop syncing with Spotify Dejar de sincronizar con Spotify @@ -1652,22 +1764,22 @@ y estaciones basadas en sus gustos personales. Tomahawk::Accounts::SpotifyAccountConfig - + Logging in... Inciando sesión... - + Logged in! Sesión iniciada! - + Failed: %1 Fallo: %1 - + Log In Iniciar Sesión @@ -1675,7 +1787,7 @@ y estaciones basadas en sus gustos personales. Tomahawk::Accounts::SpotifyAccountFactory - + Play music from and sync your playlists with Spotify Premium Reproduce música de Spotofy Premium y sincroniza las listas de reprodución @@ -1828,7 +1940,7 @@ Hay que volverse a autenticar. Tomahawk::Accounts::ZeroconfFactory - + Automatically connect to Tomahawks on the local network Conectarse automáticament a los Tomahawks de la red local @@ -1842,29 +1954,29 @@ Hay que volverse a autenticar. - - + + Add to &Queue Añadir a la &cola - + &Love &Favorito - + &Copy Track Link &Copiar enlace del Tema - + Un-&Love Quitar de &Favoritos - + &Delete Items &Eliminar de la cola @@ -1879,22 +1991,22 @@ Hay que volverse a autenticar. &Para la Reproducción después de este Tema - + &Show Track Page - + &Delete Item &Eliminar de la cola - + &Show Album Page - + &Show Artist Page @@ -1935,12 +2047,32 @@ Hay que volverse a autenticar. Tomahawk::DropJobNotifier - + + playlist + + + + + artist + + + + + track + + + + + album + + + + Fetching %1 from database Obteniendo %1 de la base de datos - + Parsing %1 %2 Analizando %1 %2 @@ -1987,17 +2119,17 @@ Por favor, cambie los filtros o inténtelo de nuevo. Tomahawk::DynamicView - + Add some filters above to seed this station! ¡Añada algunos filtros para la estación! - + Press Generate to get started! ¡Seleccione Generar para comenzar! - + Add some filters above, and press Generate to get started! ¡Añada algunos filtros, y seleccione Generar para comenzar! @@ -2005,7 +2137,7 @@ Por favor, cambie los filtros o inténtelo de nuevo. Tomahawk::DynamicWidget - + Station ran out of tracks! Try tweaking the filters for a new set of songs to play. @@ -2324,92 +2456,92 @@ Intente ajustar los filtros para reproducir nuevas canciones. Dirigir esta estación: - + Much less Mucho menos - + Less Menos - + A bit less Un poco menos - + Keep at current Mantener en el actual - + A bit more Un poco más - + More Más - + Much more Mucho más - + Tempo Tempo - + Loudness Volumen - + Danceability Bailabilidad - + Energy Energía - + Song Hotttnesss Popularidad de la pista - + Artist Hotttnesss Popularidad del artista - + Artist Familiarity Familiaridad del artista - + By Description Por descripción - + Enter a description Introducir una descripción - + Apply steering command Aplicar comando - + Reset all steering commands Resetear todos los comandos @@ -2425,22 +2557,22 @@ Intente ajustar los filtros para reproducir nuevas canciones. Tomahawk::InfoSystem::ChartsPlugin - + Top Overall Top total - + Artists Artistas - + Albums Álbumes - + Tracks Pistas @@ -2461,27 +2593,27 @@ Intente ajustar los filtros para reproducir nuevas canciones. Tomahawk::InfoSystem::LastFmInfoPlugin - + Top Tracks Temas más escuchados - + Loved Tracks Temas Favoritos - + Hyped Tracks Temas a la alza - + Top Artists Artistas más escuchados - + Hyped Artists Artistas a la alza @@ -2489,7 +2621,7 @@ Intente ajustar los filtros para reproducir nuevas canciones. Tomahawk::InfoSystem::NewReleasesPlugin - + Albums Álbumes @@ -2497,7 +2629,7 @@ Intente ajustar los filtros para reproducir nuevas canciones. Tomahawk::InfoSystem::TwitterInfoPlugin - + Listening to "%1" by %2 and loving it! %3 Escuchando "%1" de %2 y me encanta! %3 @@ -2555,37 +2687,37 @@ Intente ajustar los filtros para reproducir nuevas canciones. Tomahawk::Query - + and y - + You usted - + you usted - + and y - + %n other(s) %n más%n más - + %1 people %1 personas - + loved this track han añadido este tema a Favoritos @@ -2601,7 +2733,7 @@ Intente ajustar los filtros para reproducir nuevas canciones. Tomahawk::ShortenedLinkParser - + Network error parsing shortened link! Error en la red al analizar el enlace acortado! @@ -2609,36 +2741,46 @@ Intente ajustar los filtros para reproducir nuevas canciones. Tomahawk::Source - - + + Scanning (%L1 tracks) Escaneando (%L1 pistas) - + Scanning Escaneando - + Checking Comprobando - + Fetching Obteniendo - + Parsing Analizando - + Saving (%1%) Guardando (%1%) + + + Online + + + + + Offline + + Tomahawk::SpotifyParser @@ -2659,7 +2801,7 @@ Intente ajustar los filtros para reproducir nuevas canciones. TomahawkApp - + My Collection Mi colección @@ -2682,39 +2824,48 @@ introduzca su número PIN aquí: TomahawkTrayIcon - - + &Stop Playback after current Track &Para la Reproducción después de este Tema - - + + Hide Tomahawk Window Ocultar ventana de Tomahawk - + Show Tomahawk Window Mostrar ventana de Tomahawk - + Currently not playing. Ninguna pista en reproducción. - + Play Reproducir - + Pause Pausar - + + &Love + + + + + Un-&Love + + + + &Continue Playback after current Track &Continuar la Reproducción después de este Tema @@ -2858,7 +3009,7 @@ introduzca su número PIN aquí: - + Play Reproducir @@ -2878,162 +3029,172 @@ introduzca su número PIN aquí: Siguiente - + Back - + Go back one page - + Forward - + Go forward one page - + Global Search... Búsqueda global... - - + + Check For Updates... Buscar actualizaciones... - - - + + + Connect To Peer Conectar a un par - + Enter peer address: Introducir dirección del par: - + Enter peer port: Introducir puerto del par: - + Enter peer key: Introducir contraseña del par: - + XSPF Error Error XSPF - + This is not a valid XSPF playlist. Esta no es una lista de reproducción XSPF válida. - + Failed to save tracks Fallo al guardar pistas - + Some tracks in the playlist do not contain an artist and a title. They will be ignored. Algunas pistas en la lista de reproducción no contienen artista ni título. Serán ignoradas. - + Sorry, there is a problem accessing your audio device or the desired track, current track will be skipped. Make sure you have a suitable Phonon backend and required plugins installed. Se ha producido un error al acceder al dispostivo de audio o al tema deseado y se va saltar. Asegúrese de que ha instalado un backend de Phonon adecuado y los plugins necesarios. - + Sorry, there is a problem accessing your audio device or the desired track, current track will be skipped. Se ha producido un error al acceder al dispostivo de audio o al tema deseado y se va saltar. - + + Station + + + + Create New Station Crear nueva estación - + Name: Nombre: - - New Station - Nueva estación + + Playlist + - - New Playlist - Nueva lista de reproducción + + Automatic Playlist + - + Pause Pausar - + Go &offline &Desconectarse - + Go &online &Conectarse - + Authentication Error Error de autenticación - + Error connecting to SIP: Authentication failed! - + %1 by %2 track, artist name %1 por %2 - + %1 - %2 current track, some window title %1 - %2 - + <h2><b>Tomahawk %1<br/>(%2)</h2> <h2><b>Tomahawk %1<br/>(%2)</h2> - + <h2><b>Tomahawk %1</h2> <h2><b>Tomahawk %1</h2> - - Copyright 2010 - 2012<br/>Christian Muehlhaeuser &lt;muesli@tomahawk-player.org&gt;<br/><br/>Thanks to: Leo Franchi, Jeff Mitchell, Dominik Schmidt, Jason Herskowitz, Alejandro Wainzinger, Hugo Lindstr&ouml;m, Michael Zanetti, Harald Sitter and Steve Robertson - Copyright 2010 - 2012<br/>Christian Muehlhaeuser &lt;muesli@tomahawk-player.org&gt;<br/><br/>Gracias a: Leo Franchi, Jeff Mitchell, Dominik Schmidt, Jason Herskowitz, Alejandro Wainzinger, Hugo Lindstr&ouml;m, Michael Zanetti, Harald Sitter y Steve Robertson + + Copyright 2010 - 2012 + - + + Thanks to: + + + + About Tomahawk Acerca de Tomahawk @@ -3104,7 +3265,7 @@ introduzca su número PIN aquí: TopTracksContext - + Top Hits Grandes éxitos @@ -3117,143 +3278,70 @@ introduzca su número PIN aquí: Formulario - + Cover Portada - + Track Tema - - by - de - - - + Artist Artista - - from - en - - - + Album Álbum - + Statistics Estadísticas - - Lyrics - - - - + Similar Tracks Temas Similares + + + Sorry, but we could not find similar tracks for this song! + + - + You've listened to this track %n time(s). Ha escuchado esta canción %n vez.Ha escuchado esta canción %n veces. - + You've never listened to this track before. Nunca ha escuchado este tema antes. - + You first listened to it on %1. Escuchó este tema pro primera vez en %1. - + You've listened to %1 %n time(s). Ha escuchado %1 %n vez.Ha escuchado %1 %n veces. - + You've never listened to %1 before. Nunca ha escuchado %1 antes. - - TrackModel - - - Artist - Artista - - - - Title - Título - - - - Album - Álbum - - - - Track - Tema - - - - Duration - Duración - - - - Bitrate - Bitrate - - - - Age - Edad - - - - Year - Año - - - - Size - Tamaño - - - - Origin - Origen - - - - Score - Puntuación - - - - Composer - Compositor - - TrackView - + Sorry, your filter '%1' did not match any results. Lo siento, tu filtro '%1' no ha encontrado resultados. @@ -3282,63 +3370,31 @@ introduzca su número PIN aquí: TreeModel - - Name - Nombre - - - - Duration - Duración - - - - Bitrate - Bitrate - - - - Age - Edad - - - - Year - Año - - - - Size - Tamaño - - - - Origin - Origen - - - - Composer - Compositor - - - + All Artists Todos los artistas - - + + My Collection Mi colección - - + + Collection of %1 Colección de %1 + + TreeView + + + Sorry, your filter '%1' did not match any results. + + + TwitterConfigWidget @@ -3415,27 +3471,37 @@ Puede reenviar el mensaje de sincronización en cualquier momento simplemente en ViewManager - + + After you have scanned your music collection you will find your tracks right here. + + + + + This collection is empty. + + + + SuperCollection SuperColección - + Combined libraries of all your online friends Bibliotecas combinadas de todos tus amigos conectados - + All available albums Todos los álbumes disponibles - + Recently Played Tracks Temas Escuchados Recientemente - + Recently played tracks from all your friends Temas escuchados recientemente por mis amigos @@ -3458,12 +3524,12 @@ Puede reenviar el mensaje de sincronización en cualquier momento simplemente en Pistas reproducidas recientemente - + No recently created playlists in your network. No hay listas de reproducción recientemente creadas en su red. - + Welcome to Tomahawk Bienvenido a Tomahawk @@ -3471,7 +3537,7 @@ Puede reenviar el mensaje de sincronización en cualquier momento simplemente en WhatsHotWidget - + Charts Listas de éxitos @@ -3709,107 +3775,107 @@ Letras de "%1" por %2: XmppSipPlugin - + User Interaction Interacción de usuario - + Host is unknown Máquina desconocida - + Item not found Elemento no encontrado - + Authorization Error Error de Autorización - + Remote Stream Error Error de Stream Remoto - + Remote Connection failed Fallo en la Conexión Remota - + Internal Server Error Error de Servidor Interno - + System shutdown Sistema apagado - + Conflict Conflicto - + Unknown Desconocido - + No Compression Support Compresión no sportada - + No Encryption Support Encriptación no soportada - + No Authorization Support Autorización no soportada - + No Supported Feature Característica no soportada - + Add Friend Añadir Amigo - + Enter Xmpp ID: Introducir ID XMPP: - + Add Friend... Añadir Amigo... - + XML Console... Consola XML... - + I'm sorry -- I'm just an automatic presence used by Tomahawk Player (http://gettomahawk.com). If you are getting this message, the person you are trying to reach is probably not signed on, so please try again later! Lo siento -- soy una presencia automática usada por el Reproductor Tomahawk (http://gettomahawk.com). Si recibe este mensaje, la persona con quién intenta contactar no esté contectada probablemente. Inténtelo más tarde! - + Authorize User Autorizar Usuario - + Do you want to grant <b>%1</b> access to your Collection? ¿Quiere permitir que <b>%1</b> acceda a su Colección? diff --git a/lang/tomahawk_fr.ts b/lang/tomahawk_fr.ts index 85d926132..d7cddaf12 100644 --- a/lang/tomahawk_fr.ts +++ b/lang/tomahawk_fr.ts @@ -2,17 +2,17 @@ AccountFactoryWrapper - + Dialog Dialog - + Description goes here ici la description - + Add Account Ajouter un compte @@ -20,17 +20,17 @@ AccountFactoryWrapperDelegate - + Online En Ligne - + Connecting... Connexion en cours... - + Offline Hors ligne @@ -134,43 +134,35 @@ se connecter et streamer depuis chez vous ? Tous les albums par cet artiste - + + Sorry, we could not find any other albums for this artist! + Désolé, aucun autre album n'a pu être trouvé pour cet artiste ! + + + + Sorry, we could not find any tracks for this album! + Désolé, on a pas pu trouver aucune pistes pour cet album! + + + Other Albums by %1 - Autres albums par %1 + Autres albums de %1 AlbumModel - - Album - Album - - - - + + All albums from %1 Tous les albums de %1 - + All albums Tous les albums - - AlbumView - - - After you have scanned your music collection you will find your latest album additions right here. - Après avoir scanné votre collection musicale, vous trouverez les derniers albums ajoutés ici. - - - - This collection doesn't have any recent albums. - Cette collection n'a pas d'albums récents - - ArtistInfoWidget @@ -179,12 +171,12 @@ se connecter et streamer depuis chez vous ? Form - + Top Hits Top Hits - + Related Artists Artistes similaires @@ -193,23 +185,25 @@ se connecter et streamer depuis chez vous ? Albums Albums - - - ArtistView - - After you have scanned your music collection you will find your tracks right here. - Après avoir scanné votre collection musicale, vous trouverez vos pistes ici. + + Cover + - - This collection is currently empty. - La collection est vide actuellement. + + Sorry, we could not find any albums for this artist! + Désolé, on a pas pu trouver aucun album pour cet artiste! - - Sorry, your filter '%1' did not match any results. - Désolé, votre filtre '%1' ne correspond à aucun résultat + + Sorry, we could not find any related artists! + Désolé, on a rien trouvé par rapport a cet artite! + + + + Sorry, we could not find any top hits for this artist! + Désolé, on a pas pu trouver aucun top hit pour cet artiste! @@ -235,57 +229,57 @@ se connecter et streamer depuis chez vous ? Suivant - + Artist Artiste - + Album Album - + Owner Propriétaire - + social social - + love love - + Time Durée - + Time Left Durée restante - + Shuffle Lecture Aléatoire - + Repeat Répéter - + Low Bas - + High Haut @@ -294,22 +288,25 @@ se connecter et streamer depuis chez vous ? CategoryAddItem - - New Playlist - Nouvelle liste de lecture + Create new Playlist + Créer une nouvelle liste de lecture - - - - + + Create new Station + Créer une nouvelle station + + + + + New Station Nouvelle Station - - - + + + %1 Station Station %1 @@ -335,27 +332,6 @@ se connecter et streamer depuis chez vous ? Vider - - CollectionFlatModel - - - My Collection - Ma Collection - - - - Collection of %1 - Collection de %1 - - - - CollectionView - - - This collection is empty. - La collection est vide. - - ContextWidget @@ -365,12 +341,12 @@ se connecter et streamer depuis chez vous ? - + Show Footnotes Afficher les notes - + Hide Footnotes Masquer les notes @@ -384,18 +360,18 @@ se connecter et streamer depuis chez vous ? - <html><head/><body><p><span style=" font-weight:600;">Sorry!</span> Tomahawk crashed. Please tell us about it! Tomahawk has created an error report for you that can help improve the stability in the future. You can now send the this report directly to the Tomahawk developers.</p></body></html> - + <html><head/><body><p><span style=" font-weight:600;">Sorry!</span> Tomahawk crashed. Please tell us about it! Tomahawk 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 Tomahawk developers.</p></body></html> + <html><head/><body><p><span style=" font-weight:600;">Désolé !</span>&nbsp;Tomahawk a planté. Dites-nous ce qui ne va pas ! Tomahawk a créé un rapport d'erreur qui sera utile pour améliorer la stabilité des prochaines versions. Vous pouvez dès maintenant envoyer ce rapport aux développeurs de Tomahawk.</p></body></html> Send this report - + Envoyer le rapport Don't send - + Ne pas envoyer @@ -426,7 +402,7 @@ se connecter et streamer depuis chez vous ? Failed to send crash info. - Échec de l'envoi des informations de plantage + Échec de l'envoi des informations de plantage. @@ -440,17 +416,17 @@ se connecter et streamer depuis chez vous ? DelegateConfigWrapper - + About A propos - + Delete Account Supprimer le compte - + About this Account A propos de ce compte @@ -463,24 +439,11 @@ se connecter et streamer depuis chez vous ? Diagnostics de Tomahawk - - Update - Mettre à jour - - - + Copy to Clipboard Copier dans le presse papier - - DropJob - - - No tracks found for given %1 - Aucune piste trouvée pour %1 - - GlobalSearchWidget @@ -505,56 +468,43 @@ se connecter et streamer depuis chez vous ? Barre d'information - + Filter... Filtre... - - JobStatusView - - - Searching For - Recherche de - - - - Pending - En suspens - - - - Idle - Pas d'activité - - LastFmConfig - + Form Form - + Scrobble tracks to Last.fm - Scrobbler les pistes sur Last.fm + Scrobbler les titres sur Last.fm - + Username: Nom d'utilisateur : - + Password: Mot de passe : - + Test Login Login test + + + Import Playback History + Importer l'historique + LastfmContext @@ -569,7 +519,7 @@ se connecter et streamer depuis chez vous ? %1 is listening along to you! - %1 écoute avec vous + %1 écoute avec vous! @@ -623,7 +573,7 @@ se connecter et streamer depuis chez vous ? Saved tracks - Pistes sauvegardés + Titres sauvegardés @@ -631,7 +581,7 @@ se connecter et streamer depuis chez vous ? Enter a title for the new playlist: - Entrer un titre pour la nouvelle liste de lecture + Entrer un titre pour la nouvelle liste de lecture: @@ -657,11 +607,80 @@ se connecter et streamer depuis chez vous ? NewReleasesWidget - + New Releases Nouveautés + + PlayableModel + + + Artist + Artiste + + + + Title + Titre + + + + Composer + Compositeur + + + + Album + Album + + + + Track + Piste + + + + Duration + Durée + + + + Bitrate + Bitrate + + + + Age + Age + + + + Year + Année + + + + Size + Taille + + + + Origin + Origine + + + + Score + Score + + + + + Name + Nom + + PlaylistItemDelegate @@ -678,17 +697,17 @@ se connecter et streamer depuis chez vous ? PlaylistLargeItemDelegate - + played %1 by you joué %1 par vous - + played %1 by %2 joué %1 par %2 - + added %1 ajouté par %1 @@ -696,24 +715,24 @@ se connecter et streamer depuis chez vous ? PlaylistModel - + A playlist by %1, created %2 Une liste de lecture par %1, créée %2 - + you vous All tracks by %1 on album %2 - Toutes les pistes par %1 sur l'album %2 + Tous les titres de %1 sur l'album %2 All tracks by %1 - Toutes les pistes par %1 + Tous les titres de %1 @@ -726,12 +745,12 @@ se connecter et streamer depuis chez vous ? Just a regular old playlist... Give it a name, drag in some tracks, and go! - Juste une liste de lecture normale... Donnez lui un nom, faites glisser quelques pistes et c'est parti ! + Une liste de lecture toute simple... Donnez lui un nom, faites glisser quelques pistes et c'est parti ! Don't know exactly what you want? Give Tomahawk a few pointers and let it build a playlist for you! - Vous ne savez pas ce que vous voulez exactement ? Donnez quelques idées à Tomahawk et laissez le créer une liste de lecture pour vous. + Vous ne savez pas ce que vous voulez exactement ? Donnez quelques idées à Tomahawk et laissez le créer une liste de lecture pour vous ! @@ -746,18 +765,23 @@ se connecter et streamer depuis chez vous ? Create Manual Playlist - Créer une liste de lecture manuellement + Liste de lecture manuelle Create Automatic Playlist - Créer une liste de lecture automatiquement + Liste de lecture automatique PlaylistView - + + This playlist is currently empty. + La collection est vide actuellement. + + + This playlist is currently empty. Add some tracks to it and enjoy the music! La liste de lecture est vide. Ajoutez des pistes et profitez de la musique ! @@ -825,67 +849,67 @@ se connecter et streamer depuis chez vous ? QObject - + %n year(s) ago il y a %n anil y a %n ans - + %n year(s) %n an%n ans - + %n month(s) ago il y a %n moisil y a %n mois - + %n month(s) %n mois%n mois - + %n week(s) ago il y a %n semaineil y a %n semaines - + %n week(s) %n semaine%n semaines - + %n day(s) ago il y a %n jouril y a %n jours - + %n day(s) %n jour%n jours - + %n hour(s) ago il y a %n heureil y a %n heures - + %n hour(s) %n heure%n heures - + %1 minutes ago il y a %1 minutes - + %1 minutes %1 minutes - + just now à l'instant @@ -922,20 +946,25 @@ se connecter et streamer depuis chez vous ? - - Show Queue - Afficher la file d'attente + + Open Queue + Ouvrir la file d'attente + + + + Open Queue - %n item(s) + Ouvrir la file d'attente - %n élémentOuvrir la file d'attente - %n éléments - - Hide Queue - Masquer la file d'attente + + Close Queue + Fermer la file d'attente RelatedArtistsContext - + Related Artists Artistes similaires @@ -1027,7 +1056,7 @@ se connecter et streamer depuis chez vous ? Most Played Tracks You Don't Have - Pistes les plus joués que vous n'avez pas + Titres les plus joués que vous n'avez pas @@ -1058,17 +1087,22 @@ se connecter et streamer depuis chez vous ? TextLabel - - Listening to "%1" by %2 and loving it! %3 - J'écoute "%1" par %2 et j'adore ! %3 + + Tweet + Tweet - - Listening to "%1" by %2 on "%3" and loving it! %4 - J'écoute "%1" par %2 sur "%3" et j'adore ! %4 + + Listening to "%1" by %2. %3 + J'écoute "%1" par %2. %3 - + + Listening to "%1" by %2 on "%3". %4 + J'écoute "%1" par %2 sur "%3". %4 + + + %1 characters left %1 caractères restants @@ -1101,29 +1135,19 @@ se connecter et streamer depuis chez vous ? Top 10 - - Offline - Hors ligne - - - + All available tracks - Toutes les pistes disponibles + Tous les titres disponibles - - Online - En Ligne - - - - + + Show Afficher - - + + Hide Masquer @@ -1143,20 +1167,20 @@ se connecter et streamer depuis chez vous ? Recently Played Tracks - Dernières pistes jouées + Dernières titres joués - + New Additions Nouveaux ajouts - + My recent activity Mon activité récente - + Recent activity from %1 Activité récente de %1 @@ -1164,81 +1188,138 @@ se connecter et streamer depuis chez vous ? SourceItem - + Collection Collection - - + + Latest Additions Derniers ajouts - + Recently Played Joués récemment - + Loved Tracks - Pistes favorites + Titres favoris - + SuperCollection SuperCollection - + + Sorry, we could not find any loved tracks! + Désolé, on a pas pu trouver aucune piste favoris! + + + Latest additions to your collection Derniers ajouts à votre collection - + Latest additions to %1's collection - Derniers à la collection de %1 + Derniers ajouts à la collection de %1 - + + Sorry, we could not find any recent additions! + Désolé, on a pas pu trouver des dernier ajouts! + + + Recently Played Tracks - Dernières pistes jouées + Derniers titres joués - + Your recently played tracks - Vos dernières pistes jouées + Les derniers titres que vous avez joués - + %1's recently played tracks - Dernières pistes jouées par %1 + Derniers titres joués par %1 + + + + Sorry, we could not find any recent plays! + Désolé, on a pas pu trouver aucune piste récement joués! SourceTreeView - + &Copy Link &Copier le lien - + &Delete %1 &Supprimer %1 - + + Add to my Playlists + Ajoute a mes listes de lecture + + + + Add to my Automatic Playlists + Ajoute a mes listes de lecture automatique + + + + Add to my Stations + Ajouter à mes stations + + + &Export Playlist &Exporter la liste de lecture - + + playlist + liste de lecture + + + + automatic playlist + liste de lecture automatique + + + + station + station + + + + Delete %1? + playlist/station/... + Supprimer %1? + + + + Would you like to delete the %1 <b>"%2"</b>? + e.g. Would you like to delete the playlist named Foobar? + Voulez-vous supprimer la %1 <b>"%2"</b>? + + + Save XSPF Enregistrer XSPF - + Playlists (*.xspf) Listes de lecture (*.xspf) @@ -1271,52 +1352,52 @@ se connecter et streamer depuis chez vous ? Station - + Browse Parcourir - + Search History Chercher dans l'historique - + My Music Ma Musique - + SuperCollection SuperCollection - + Top Loved Tracks - Top des pistes favorites + Top des titres favoris - + Dashboard Tableau de bord - + Recently Played Joués récemment - + Charts Charts - + New Releases Nouveautés - + Friends Amis @@ -1324,52 +1405,52 @@ se connecter et streamer depuis chez vous ? SpotifyConfig - + Form Form - + Configure your Spotify account Configurer votre compte Spotify - + Username or Facebook Email Nom d'utilisateur ou email Facebook - + Log In Connexion - + Right click on any Tomahawk playlist to sync it to Spotify. Clic droit pour synchroniser une liste de lecture Tomahawk vers Spotify. - + High Quality Streams Streaming haute qualité - + Spotify playlists to keep in sync: Liste de lecture Spotify à synchroniser : - + Delete Tomahawk playlist when removing synchronization Supprimer la liste de lecture de Tomahawk à la suppression de la synchronisation - + Username: Nom d'utilisateur : - + Password: Mot de passe : @@ -1377,12 +1458,12 @@ se connecter et streamer depuis chez vous ? SpotifyPlaylistUpdater - + Delete in Spotify? Supprimer dans Spotify ? - + Would you like to delete the corresponding Spotify playlist as well? Voulez-vous aussi supprimer la liste de lecture correspondante dans Spotify ? @@ -1411,9 +1492,9 @@ se connecter et streamer depuis chez vous ? will allow you (and all your friends) to create automatic playlists and stations based on your personal taste profile. The Echo Nest peut garder les métadonnées de votre catalogue -et l'utiliser pour créer des radios personnalisées. En activant cette option +et les utiliser pour créer des radios personnalisées. En activant cette option vous (et vos amis) pourrez créer des listes de lecture automatiquement -et des stations basés sur vos goûts. +et des stations basées sur vos goûts. @@ -1483,7 +1564,7 @@ et des stations basés sur vos goûts. Filter by capability: - Filtrer par capacité : + Filtrer par fonctionnalité : @@ -1508,43 +1589,43 @@ et des stations basés sur vos goûts. Send reports after Tomahawk crashed - Envoyer un rapport apès un crash de Tomahawk + Envoyer un rapport après un crash de Tomahawk Allow web browsers to interact with Tomahawk (recommended) - Permettrre aux navigateurs web pour intéragir avec Tomahawk (recommandé) + Permettre aux navigateurs web d’interagir avec Tomahawk (recommandé) Tomahawk::Accounts::AccountDelegate - + Add Account Ajouter un compte - - Remove Account - Supprimer le compte + + Remove + Supprimer - + %1 downloads %1 téléchargements - + Online En Ligne - + Connecting... Connexion en cours... - + Offline Hors ligne @@ -1552,14 +1633,14 @@ et des stations basés sur vos goûts. Tomahawk::Accounts::AccountModel - + Manual Install Required - + Installation manuelle requise - - Unfortunately, automatic installation of this resolver is not yet available on Linux.<br /><br />Please use "Install from file" above, by fetching it from your distribution or compiling it yourself. Further instructions can be found here:<br /><br />http://www.tomahawk-player.org/resolvers/%1 - + + Unfortunately, automatic installation of this resolver is not available or disabled for your platform.<br /><br />Please use "Install from file" above, by fetching it from your distribution or compiling it yourself. Further instructions can be found here:<br /><br />http://www.tomahawk-player.org/resolvers/%1 + Malheureusement, l'installation automatique de ce script de résolution n'est pas disponible ou a été désactivé sur votre plateforme.<br /><br />Utiliser "Installer depuis un fichier" ci-dessus et téléchargez le fichier pour votre distribution, ou compilez-le. D'autres instructions sont disponibles ici :<br /><br />http://www.tomahawk-player.org/resolvers/%1 @@ -1609,7 +1690,7 @@ et des stations basés sur vos goûts. Tomahawk::Accounts::LastFmAccountFactory - + Scrobble your tracks to last.fm, and find freely downloadable tracks to play Scrobbler vos écoutes sur Last.fm et trouver des morceaux téléchargeables gratuitement @@ -1617,23 +1698,49 @@ et des stations basés sur vos goûts. Tomahawk::Accounts::LastFmConfig - + + Testing... + Test... + + + Test Login Test de connexion - - + + Importing %1 + e.g. Importing 2012/01/01 + Importation %1 + + + + Importing History... + Import de l'historique... + + + + History Incomplete. Resume + Historique incomplet. Reprendre + + + + Playback History Imported + Historique de lecture importé + + + + Failed Échec - + Success Succès - + Could not contact server Impossible de contacter le serveur @@ -1641,12 +1748,17 @@ et des stations basés sur vos goûts. Tomahawk::Accounts::SpotifyAccount - + Sync with Spotify Synchroniser avec Spotify - + + Re-enable syncing with Spotify + Réactiver la synchronisation avec Spotify + + + Stop syncing with Spotify Stopper la synchronisation avec Spotify @@ -1654,22 +1766,22 @@ et des stations basés sur vos goûts. Tomahawk::Accounts::SpotifyAccountConfig - + Logging in... Connexion... - + Logged in! Connecté ! - + Failed: %1 Echec : %1 - + Log In Connexion @@ -1677,7 +1789,7 @@ et des stations basés sur vos goûts. Tomahawk::Accounts::SpotifyAccountFactory - + Play music from and sync your playlists with Spotify Premium Jouer la musique et synchroniser vos listes avec Spotify Premium @@ -1687,7 +1799,7 @@ et des stations basés sur vos goûts. Connect to your Twitter followers. - Se connecter à votre followers sur Twitter + Se connecter à vos followers sur Twitter. @@ -1824,13 +1936,13 @@ Essayez de vous authentifier de nouveau. Log on to your Jabber/XMPP account to connect to your friends - Connectez vous à votre compte Jabber/XMPP pour vous connecter avec vos amis + Connectez vous à votre compte Jabber/XMPP pour retrouver vos amis Tomahawk::Accounts::ZeroconfFactory - + Automatically connect to Tomahawks on the local network Se connecter automatiquement aux Tomahawks sur le réseau local @@ -1844,29 +1956,29 @@ Essayez de vous authentifier de nouveau. - - + + Add to &Queue &Ajouter à la file d'attente - + &Love &Favori - + &Copy Track Link &Copier le lien de la piste - + Un-&Love - Supprimer des Favoris + &Supprimer des Favoris - + &Delete Items &Supprimer les éléments @@ -1881,24 +1993,24 @@ Essayez de vous authentifier de nouveau. &Stopper la lecture après cette piste - + &Show Track Page - + &Afficher la page de la piste - + &Delete Item &Supprimer l'élément - + &Show Album Page - + &Afficher la page de l'album - + &Show Artist Page - + &Afficher la page artiste @@ -1906,43 +2018,63 @@ Essayez de vous authentifier de nouveau. Top Loved Tracks - Top des pistes favorites + Top des titres favoris Your loved tracks - Vos pistes favorites + Vos titres favoris %1's loved tracks - Pistes favorites de %1 + Titres favoris de %1 The most loved tracks from all your friends - Les pistes favorites de tous vos amis + Les titres favoris de vos amis All of your loved tracks - Toutes vos pistes favorites + Tous vos titres favoris All of %1's loved tracks - Toutes les pistes favorites de %1 + Tous les titres favoris de %1 Tomahawk::DropJobNotifier - + + playlist + liste de lecture + + + + artist + artiste + + + + track + titre + + + + album + album + + + Fetching %1 from database Chargement de %1 depuis la base de données - + Parsing %1 %2 Décodage %1 %2 @@ -1989,17 +2121,17 @@ Veuillez changer les filtres et essayez de nouveau. Tomahawk::DynamicView - + Add some filters above to seed this station! Ajoutez des filtres ci dessus pour commencer une station ! - + Press Generate to get started! Appuyez sur Générer pour commencer ! - + Add some filters above, and press Generate to get started! Ajoutez des filtres ci dessus et appuyez sur "Générer" pour commencer ! @@ -2007,11 +2139,11 @@ Veuillez changer les filtres et essayez de nouveau. Tomahawk::DynamicWidget - + Station ran out of tracks! Try tweaking the filters for a new set of songs to play. - Il n'y a plus de pistes dans la station ! + Il n'y a plus de chansons dans la station ! Essayez de changer les filtres pour avoir de nouveaux morceaux à jouer. @@ -2037,7 +2169,7 @@ Essayez de changer les filtres pour avoir de nouveaux morceaux à jouer. No users with Echo Nest Catalogs enabled. Try enabling option in Collection settings - Aucun utilisateur avec un Catalogue The Echo Nest actif. Essayez d'activer l'option dans les préférences de Collection. + Aucun utilisateur avec un Catalogue The Echo Nest actif. Essayez d'activer l'option dans les préférences de Collection @@ -2323,95 +2455,95 @@ Essayez de changer les filtres pour avoir de nouveaux morceaux à jouer. Steer this station: - Direction de cette station : + Modifier cette station : - + Much less Beaucoup moins - + Less Moins - + A bit less Un peu moins - + Keep at current Garder le même - + A bit more Un peu plus - + More Plus - + Much more Beaucoup plus - + Tempo Tempo - + Loudness Intensité - + Danceability Dansabilité - + Energy Energie - + Song Hotttnesss Hotttnesss du morceau - + Artist Hotttnesss Hotttnesss de l'artiste - + Artist Familiarity Familiarité de l'artiste - + By Description Par description - + Enter a description Entrer une description - + Apply steering command Appliquer la commande de direction - + Reset all steering commands Annuler les commandes de direction @@ -2427,22 +2559,22 @@ Essayez de changer les filtres pour avoir de nouveaux morceaux à jouer. Tomahawk::InfoSystem::ChartsPlugin - + Top Overall Top global - + Artists Artistes - + Albums Albums - + Tracks Pistes @@ -2463,27 +2595,27 @@ Essayez de changer les filtres pour avoir de nouveaux morceaux à jouer. Tomahawk::InfoSystem::LastFmInfoPlugin - + Top Tracks - Top des pistes + Top des titres - + Loved Tracks - Pistes favorites + Titres favoris - + Hyped Tracks - Pistes Hype + Titres Hype - + Top Artists Top Artistes - + Hyped Artists Artistes Hype @@ -2491,7 +2623,7 @@ Essayez de changer les filtres pour avoir de nouveaux morceaux à jouer. Tomahawk::InfoSystem::NewReleasesPlugin - + Albums Albums @@ -2499,7 +2631,7 @@ Essayez de changer les filtres pour avoir de nouveaux morceaux à jouer. Tomahawk::InfoSystem::TwitterInfoPlugin - + Listening to "%1" by %2 and loving it! %3 J'écoute "%1" par %2 et j'adore ! %3 @@ -2509,7 +2641,7 @@ Essayez de changer les filtres pour avoir de nouveaux morceaux à jouer. Error fetching iTunes information from the network! - Échec du chargement des informations iTunes depuis le réseau! + Échec du chargement des informations iTunes depuis le réseau ! @@ -2557,39 +2689,39 @@ Essayez de changer les filtres pour avoir de nouveaux morceaux à jouer. Tomahawk::Query - + and et - + You Vous - + you vous - + and et - + %n other(s) %n autre%n autres - + %1 people %1 personnes - + loved this track - a mis cette piste en favoris + a enregistré cette piste dans ses favoris @@ -2603,7 +2735,7 @@ Essayez de changer les filtres pour avoir de nouveaux morceaux à jouer. Tomahawk::ShortenedLinkParser - + Network error parsing shortened link! Erreur réseau lors du décodage de l'URL courte! @@ -2611,36 +2743,46 @@ Essayez de changer les filtres pour avoir de nouveaux morceaux à jouer. Tomahawk::Source - - + + Scanning (%L1 tracks) - Scan en cours (%L1 pistes) + Scan en cours (%L1 titres) - + Scanning Scan en cours - + Checking Vérification - + Fetching Chargement - + Parsing Décodage - + Saving (%1%) Enregistrement (%1%) + + + Online + En Ligne + + + + Offline + Hors ligne + Tomahawk::SpotifyParser @@ -2661,7 +2803,7 @@ Essayez de changer les filtres pour avoir de nouveaux morceaux à jouer. TomahawkApp - + My Collection Ma Collection @@ -2677,46 +2819,55 @@ Essayez de changer les filtres pour avoir de nouveaux morceaux à jouer. After authenticating on Twitter's web site, enter the displayed PIN number here: - Après vous être authentifier sur le site de Twitter, + Après vous être authentifié sur le site de Twitter, saisissez le numéro PIN ici : TomahawkTrayIcon - - + &Stop Playback after current Track &Stopper la lecture après cette piste - - + + Hide Tomahawk Window Masquer la fenêtre Tomahawk - + Show Tomahawk Window Afficher la fenêtre Tomahawk - + Currently not playing. - Pas de lecture en cours + Pas de lecture en cours. - + Play Lecture - + Pause Pause - + + &Love + &Favori + + + + Un-&Love + &Supprimer des Favoris + + + &Continue Playback after current Track &Continuer la lecture après cette piste @@ -2791,7 +2942,7 @@ saisissez le numéro PIN ici : Load &XSPF... - Charger &XSPF + Charger &XSPF... @@ -2801,12 +2952,12 @@ saisissez le numéro PIN ici : About &Tomahawk... - A propos de &Tomahawk + A propos de &Tomahawk... Create New &Automatic Playlist - Créer une nouvelle liste de lecture automatique + Créer une nouvelle liste de lecture &automatique @@ -2860,7 +3011,7 @@ saisissez le numéro PIN ici : - + Play Lecture @@ -2879,163 +3030,173 @@ saisissez le numéro PIN ici : Next Suivant - - - Back - - - - - Go back one page - - - - - Forward - - - - - Go forward one page - - + Back + Retour + + + + Go back one page + Reculer d'une page + + + + Forward + Avancer + + + + Go forward one page + Avancer d'une page + + + Global Search... Recherche Globale... - - + + Check For Updates... Rechercher une mise à jour... - - - + + + Connect To Peer Connexion à un pair - + Enter peer address: Adresse du pair : - + Enter peer port: Port du pair : - + Enter peer key: Clé du pair : - + XSPF Error Erreur XSPF - + This is not a valid XSPF playlist. Ceci n'est pas une liste de lecture XSPF valide. - + Failed to save tracks Échec de la sauvegarde des pistes - + Some tracks in the playlist do not contain an artist and a title. They will be ignored. Certaines pistes dans la liste de lecture ne contiennent pas d'artiste ou de titre. Elles seront ignorées. - + Sorry, there is a problem accessing your audio device or the desired track, current track will be skipped. Make sure you have a suitable Phonon backend and required plugins installed. - Désolé, il y a un problème d'accès à votre matériel audio ou la piste en cours va être sauter. Vérifiez que vous avez un backend Phonon et les plugins requis installés. + Désolé, il y a un problème d'accès à votre matériel audio ou la piste en cours va être sautée. Vérifiez que vous avez un backend Phonon et les plugins requis installés. - + Sorry, there is a problem accessing your audio device or the desired track, current track will be skipped. Désolé, il y a un problème d'accès à votre matériel audio ou la piste en cours va être sauter. - + + Station + Station + + + Create New Station Créer une nouvelle station - + Name: Nom : - - New Station - Nouvelle station + + Playlist + Liste de lecture - - New Playlist - Nouvelle liste de lecture + + Automatic Playlist + Liste de lecture automatique - + Pause Pause - + Go &offline Se &déconnecter - + Go &online Se c&onnecter - + Authentication Error Erreur d'authentification - + Error connecting to SIP: Authentication failed! - + Erreur de connexion SIP : échec de l'authentification ! - + %1 by %2 track, artist name %1 par %2 - + %1 - %2 current track, some window title %1 - %2 - + <h2><b>Tomahawk %1<br/>(%2)</h2> <h2><b>Tomahawk %1<br/>(%2)</h2> - + <h2><b>Tomahawk %1</h2> <h2><b>Tomahawk %1</h2> - - Copyright 2010 - 2012<br/>Christian Muehlhaeuser &lt;muesli@tomahawk-player.org&gt;<br/><br/>Thanks to: Leo Franchi, Jeff Mitchell, Dominik Schmidt, Jason Herskowitz, Alejandro Wainzinger, Hugo Lindstr&ouml;m, Michael Zanetti, Harald Sitter and Steve Robertson - Copyright 2010 - 2012<br/>Christian Muehlhaeuser &lt;muesli@tomahawk-player.org&gt;<br/><br/>Merci à : Leo Franchi, Jeff Mitchell, Dominik Schmidt, Jason Herskowitz, Alejandro Wainzinger, Hugo Lindstr&ouml;m, Michael Zanetti, Harald Sitter and Steve Robertson + + Copyright 2010 - 2012 + Droit d'auteur 2010 - 2012 - + + Thanks to: + Merci a: + + + About Tomahawk A propos de Tomahawk @@ -3106,7 +3267,7 @@ saisissez le numéro PIN ici : TopTracksContext - + Top Hits Top Hits @@ -3119,145 +3280,72 @@ saisissez le numéro PIN ici : Form - + Cover Pochette - + Track Piste - - by - par - - - + Artist Artiste - - from - de - - - + Album Album - + Statistics Statistiques - - Lyrics - - - - + Similar Tracks Piste similaire + + + Sorry, but we could not find similar tracks for this song! + Désolé, on a pas pu trouver aucune pistes pour cette chanson! + - + You've listened to this track %n time(s). Vous avez écouté cette piste %n fois.Vous avez écouté cette piste %n fois. - + You've never listened to this track before. Vous n'avez encore jamais écouté cette piste. - + You first listened to it on %1. Vous l'avez écouté pour la première fois le %1. - + You've listened to %1 %n time(s). Vous avez écouté %1 %n fois.Vous avez écouté %1 %n fois. - + You've never listened to %1 before. Vous n'avez encore jamais écouté %1. - - TrackModel - - - Artist - Artiste - - - - Title - Titre - - - - Album - Album - - - - Track - Piste - - - - Duration - Durée - - - - Bitrate - Bitrate - - - - Age - Age - - - - Year - Année - - - - Size - Taille - - - - Origin - Origine - - - - Score - Score - - - - Composer - Compositeur - - TrackView - + Sorry, your filter '%1' did not match any results. - Désolé, votre filtre '%1' ne correspond à aucun résultat + Désolé, votre filtre '%1' ne correspond à aucun résultat. @@ -3284,63 +3372,31 @@ saisissez le numéro PIN ici : TreeModel - - Name - Nom - - - - Duration - Durée - - - - Bitrate - Bitrate - - - - Age - Age - - - - Year - Année - - - - Size - Taille - - - - Origin - Origine - - - - Composer - Compositeur - - - + All Artists Tous les artistes - - + + My Collection Ma Collection - - + + Collection of %1 Collection de %1 + + TreeView + + + Sorry, your filter '%1' did not match any results. + Désolé, votre filtre '%1' ne correspond à aucun résultat. + + TwitterConfigWidget @@ -3351,7 +3407,7 @@ saisissez le numéro PIN ici : The Twitter plugin allows you to discover and play music from your Twitter friends running Tomahawk and post messages to your account. - Le plugin Twitter vous permet de découvrir et jouer de la musique de vos amis Twitter qui utilisent Tomahawk et de poster des messages sur votre compte. + Le plugin Twitter vous permet de découvrir et jouer la musique de vos amis Twitter utilisant Tomahawk et de publier des messages sur votre compte. @@ -3417,29 +3473,39 @@ Vous pouvez envoyer un message de synchronisation quand vous le souhaitez en env ViewManager - + + After you have scanned your music collection you will find your tracks right here. + Après avoir scanné votre collection musicale, vous trouverez tous vos titres ici. + + + + This collection is empty. + La collection est vide. + + + SuperCollection SuperCollection - + Combined libraries of all your online friends Collections regroupant toutes celles de vos amis en ligne - + All available albums Tous les albums disponibles - + Recently Played Tracks - Dernières pistes jouées + Derniers titres joués - + Recently played tracks from all your friends - Dernières pistes jouées par vos amis + Derniers titres joués par vos amis @@ -3452,7 +3518,7 @@ Vous pouvez envoyer un message de synchronisation quand vous le souhaitez en env Newest Stations & Playlists - Dernières stations & listes de lecture + Dernières stations et listes de lecture @@ -3460,12 +3526,12 @@ Vous pouvez envoyer un message de synchronisation quand vous le souhaitez en env Joués récemment - + No recently created playlists in your network. Pas de liste de lecture créée récemment sur votre réseau. - + Welcome to Tomahawk Bienvenue dans Tomahawk @@ -3473,7 +3539,7 @@ Vous pouvez envoyer un message de synchronisation quand vous le souhaitez en env WhatsHotWidget - + Charts Charts @@ -3544,7 +3610,7 @@ Paroles de "%1" par %2 : Some playlist entries were found without artist and track name, they will be omitted - Certaines entrées de la liste de lecture n'ont pas d'artiste ou de titre, elles seront omises. + Certaines entrées de la liste de lecture n'ont pas d'artiste ou de titre, elles seront omises @@ -3656,7 +3722,7 @@ Paroles de "%1" par %2 : Login Information - Information de login + Informations de connexion @@ -3712,107 +3778,107 @@ Paroles de "%1" par %2 : XmppSipPlugin - + User Interaction Interaction utilisateur - + Host is unknown L'hôte est inconnu - + Item not found Objet non trouvé - + Authorization Error Erreur d'autorisation - + Remote Stream Error Erreur de lecture à distance - + Remote Connection failed Erreur de connexion à distance - + Internal Server Error Erreur interne du serveur - + System shutdown Arrêt du système - + Conflict Conflit - + Unknown - Ajouter un &ami... + Inconnu - + No Compression Support Pas de support de la compression - + No Encryption Support Pas de support du chiffrement - + No Authorization Support Pas de support de l'authorization - + No Supported Feature Fonctionnalité non supportée - + Add Friend Ajouter un ami - + Enter Xmpp ID: - Entrer l'ID XMPP + Entrer l'ID XMPP: - + Add Friend... Ajouter un ami... - + XML Console... Console XML... - + I'm sorry -- I'm just an automatic presence used by Tomahawk Player (http://gettomahawk.com). If you are getting this message, the person you are trying to reach is probably not signed on, so please try again later! Désolé -- Je suis une présence automatique utilisé par le lecteur Tomahawk (http://gettomahawk.com). Si vous lisez ce message, la personne que vous essayez de joindre n'est probablement pas connecter, donc essayez plus tard ! Merci ! - + Authorize User Autoriser l'utilisateur - + Do you want to grant <b>%1</b> access to your Collection? Voulez vous donner accès à votre collection à %1 ? diff --git a/lang/tomahawk_i18n.qrc b/lang/tomahawk_i18n.qrc index 575f8b9e1..f01815d68 100644 --- a/lang/tomahawk_i18n.qrc +++ b/lang/tomahawk_i18n.qrc @@ -10,5 +10,6 @@ tomahawk_es.qm tomahawk_sv.qm tomahawk_ja.qm +tomahawk_ar.qm diff --git a/lang/tomahawk_ja.ts b/lang/tomahawk_ja.ts index b976c2a9b..3251b8be7 100644 --- a/lang/tomahawk_ja.ts +++ b/lang/tomahawk_ja.ts @@ -2,17 +2,17 @@ AccountFactoryWrapper - + Dialog ダイアログ - + Description goes here - + Add Account アカウントを追加 @@ -20,17 +20,17 @@ AccountFactoryWrapperDelegate - + Online オンライン - + Connecting... 接続中... - + Offline オフライン @@ -40,14 +40,14 @@ Error displaying ACL info - + エラーが発生したため、ACLの情報を表示できません Allow %1 to connect and stream from you? - + %1と接続して、音楽配信を許可しますか? @@ -71,13 +71,13 @@ connect and stream from you? &Listen Privately - + 非公開で聴く &Listen Publicly - + 公開で聴く @@ -107,12 +107,12 @@ connect and stream from you? &Previous Track - + 前のトラック &Next Track - + 次のトラック @@ -125,65 +125,57 @@ connect and stream from you? Form - + フォーム Other Albums by Artist + 他のアルバム + + + + Sorry, we could not find any other albums for this artist! - - Other Albums by %1 + + Sorry, we could not find any tracks for this album! + + + Other Albums by %1 + %1の他のアルバム + AlbumModel - - Album - アルバム - - - - + + All albums from %1 - + %1のすべてのアルバム - + All albums 全アルバム - - AlbumView - - - After you have scanned your music collection you will find your latest album additions right here. - - - - - This collection doesn't have any recent albums. - - - ArtistInfoWidget Form - + フォーム - + Top Hits 大ヒット曲 - + Related Artists 似たアーティスト @@ -192,22 +184,24 @@ connect and stream from you? Albums アルバム - - - ArtistView - - After you have scanned your music collection you will find your tracks right here. + + Cover - - This collection is currently empty. - このコレクションは現在空です。 + + Sorry, we could not find any albums for this artist! + このアーティストのアルバムは見つかりませんでした。 - - Sorry, your filter '%1' did not match any results. + + Sorry, we could not find any related artists! + + + + + Sorry, we could not find any top hits for this artist! @@ -234,83 +228,86 @@ connect and stream from you? 次へ - + Artist アーティスト - + Album アルバム - + Owner - + social - + ソーシャル - + love Love - + Time 時間 - + Time Left 残り時間 - + Shuffle シャッフル - + Repeat リピート - + Low - + - + High - + CategoryAddItem - - New Playlist - 新規プレイリスト + Create new Playlist + 新規プレイリストを作成 - - - - + + Create new Station + 新規ステーションを作成 + + + + + New Station 新規ステーション - - - + + + %1 Station - + %1 ステーション @@ -334,42 +331,21 @@ connect and stream from you? クリアー - - CollectionFlatModel - - - My Collection - - - - - Collection of %1 - %1のコレクション - - - - CollectionView - - - This collection is empty. - このコレクションは空です。 - - ContextWidget InfoBar - + インフォメーションバー - + Show Footnotes 脚注を表示 - + Hide Footnotes 脚注を隠す @@ -379,37 +355,38 @@ connect and stream from you? Tomahawk Crash Reporter - + Tomahawkの問題のレポート - <html><head/><body><p><span style=" font-weight:600;">Sorry!</span> Tomahawk crashed. Please tell us about it! Tomahawk has created an error report for you that can help improve the stability in the future. You can now send the this report directly to the Tomahawk developers.</p></body></html> - + <html><head/><body><p><span style=" font-weight:600;">Sorry!</span> Tomahawk crashed. Please tell us about it! Tomahawk 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 Tomahawk developers.</p></body></html> + <html><head/><body><p>Tomahawkがクラッシュしました。その情報をTomahawkに送信してください。安定した機能に改善するためにエラーレポートを用意しています。このレポートはTomahawkの開発者に直接送られます。</p></body></html> Send this report - + レポートを送信 Don't send - + 送信しない Abort - アボート + 中止する You can disable sending crash reports in the configuration dialog. - + 設定ダイアログでクラッシュレポートの送信を無効にすることができます。 + Uploaded %L1 of %L2 KB. - + %L1/%L2 KB アップロード完了 @@ -420,12 +397,12 @@ connect and stream from you? Sent! <b>Many thanks</b>. - + 送信完了! <b>ありがとうございます!</b> Failed to send crash info. - + クラッシュ情報の送信に失敗しました。 @@ -439,19 +416,19 @@ connect and stream from you? DelegateConfigWrapper - + About - + Delete Account - + アカウントを削除 - + About this Account - + このアカウントについて @@ -459,33 +436,20 @@ connect and stream from you? Tomahawk Diagnostics - + Tomahawkの診断 - - Update - 更新 - - - + Copy to Clipboard クリップボードにコピーする - - DropJob - - - No tracks found for given %1 - - - GlobalSearchWidget Form - + フォーム @@ -493,7 +457,7 @@ connect and stream from you? Indexing database - + データベースのインデックスを作成中 @@ -501,58 +465,45 @@ connect and stream from you? InfoBar - + インフォメーションバー - + Filter... フィルター... - - JobStatusView - - - Searching For - 検索中 - - - - Pending - 保留中 - - - - Idle - 待機中 - - LastFmConfig - + Form - + フォーム - + Scrobble tracks to Last.fm - + Last.fmにトラックをscrobbleする - + Username: ユーザー名: - + Password: パスワード: - + Test Login - + ログインを確認する + + + + Import Playback History + 再生履歴をインポートする @@ -568,7 +519,7 @@ connect and stream from you? %1 is listening along to you! - + %1と一緒に聴いています! @@ -604,12 +555,12 @@ connect and stream from you? Load XSPF File - + XSPFファイルを読み込む XSPF Files (*.xspf) - + XSPFファイル (*.xspf) @@ -622,7 +573,7 @@ connect and stream from you? Saved tracks - + トラックを保存する @@ -630,17 +581,17 @@ connect and stream from you? Enter a title for the new playlist: - + 新規プレイリストのタイトルを入力: Tomahawk offers a variety of ways to help you create playlists and find music you enjoy! - + Tomahawkは新規プレイリストを作成したり、好きな曲を見つける様々な方法を提供しています! Just enter a genre or tag name and Tomahawk will suggest a few songs to get you started with your new playlist: - + ジャンルやタグ名を入力すると、Tomahawkが新しいプレイリストに曲を推薦します: @@ -656,9 +607,78 @@ connect and stream from you? NewReleasesWidget - + New Releases - + ニューリリース + + + + PlayableModel + + + Artist + アーティスト + + + + Title + タイトル + + + + Composer + 作曲者 + + + + Album + アルバム + + + + Track + トラック + + + + Duration + 時間 + + + + Bitrate + ビットレート + + + + Age + 変更日 + + + + Year + + + + + Size + サイズ + + + + Origin + 音源 + + + + Score + スコア + + + + + Name + 名前 @@ -666,53 +686,53 @@ connect and stream from you? played %1 by you - + %1を再生しました。 played %1 by %2 - + %2が%1を再生しました。 PlaylistLargeItemDelegate - + played %1 by you - + %1を再生しました。 - + played %1 by %2 - + %2が%1を再生しました。 - + added %1 - + %1を追加しました。 PlaylistModel - + A playlist by %1, created %2 - + %2に作成した%1のプレイリスト - + you - + あなた All tracks by %1 on album %2 - + %1のアルバム%2のトラック All tracks by %1 - + %1のトラック @@ -720,7 +740,7 @@ connect and stream from you? New Playlist - + 新規プレイリスト @@ -735,30 +755,35 @@ connect and stream from you? Name: - + 名前: New Playlist... - + 新規プレイリスト... Create Manual Playlist - + 自分でプレイリストを作成する Create Automatic Playlist - + 自動でプレイリストを作成する PlaylistView - + + This playlist is currently empty. + このプレイリストには何も入っていません。 + + + This playlist is currently empty. Add some tracks to it and enjoy the music! - + プレイリストには何も入っていません。トラックを追加して、音楽を楽しみましょう! @@ -771,7 +796,7 @@ connect and stream from you? Hostname of proxy server - + プロキシサーバのホスト @@ -786,123 +811,122 @@ connect and stream from you? Proxy login - + プロキシのログインネーム User - + ユーザー Password - + パスワード Proxy password - + プロキシのパスワード No Proxy Hosts: (Overrides system proxy) - + 優先プロキシ: +(システムプロキシより優先されます) localhost *.example.com (space separated) - + localhost *.example.com (スペースで区切られます) Use proxy for DNS lookups? - + 正引きDNSにプロキシを使用しますか? QObject - + %n year(s) ago - one: %n年前 - -other: %n年前 + %n年前 - + %n year(s) - + %n年 - + %n month(s) ago - + %nヶ月前 - + %n month(s) - + %nヶ月 - + %n week(s) ago - + %n週間前 - + %n week(s) - + %n週間 - + %n day(s) ago - + %n日前 - + %n day(s) - + %n日 - + %n hour(s) ago - + %n時間前 - + %n hour(s) - + %n時間 - + %1 minutes ago %1分前 - + %1 minutes %1分 - + just now - 只今 + たった今 Friend Finders - + 友達を探す Music Finders - + 音楽を探す Status Updaters - + ステータスを更新 @@ -910,7 +934,7 @@ other: %n年前 ZIP/UNZIP API error %1 - + ZIP/UNZIP API error %1 @@ -918,26 +942,31 @@ other: %n年前 InfoBar - + インフォメーションバー - - Show Queue - + + Open Queue + キューを表示 + + + + Open Queue - %n item(s) + キューを表示 - %n項目 - - Hide Queue - + + Close Queue + キューを隠す RelatedArtistsContext - + Related Artists - + 似たアーティスト @@ -945,12 +974,12 @@ other: %n年前 Not found: %1 - + 見つかりません: %1 Failed to load: %1 - + ロードに失敗しました: %1 @@ -966,12 +995,12 @@ other: %n年前 Search: %1 - + 検索: %1 Results for '%1' - + '%1'の結果 @@ -979,32 +1008,32 @@ other: %n年前 Collection - + コレクション Advanced - + 詳細 All - + すべて Some changed settings will not take effect until Tomahawk is restarted - + Tomahawkを再起動すると設定変更が反映されます Services - + サービス Install resolver from file - + ファイルからリゾルバをインストールする @@ -1022,7 +1051,7 @@ other: %n年前 Most Played Playlists - + 最も再生しているプレイリスト @@ -1058,17 +1087,22 @@ other: %n年前 - - Listening to "%1" by %2 and loving it! %3 + + Tweet - - Listening to "%1" by %2 on "%3" and loving it! %4 + + Listening to "%1" by %2. %3 - + + Listening to "%1" by %2 on "%3". %4 + + + + %1 characters left @@ -1078,17 +1112,17 @@ other: %n年前 Track - + トラック Album - + アルバム Artist - + アーティスト @@ -1101,29 +1135,19 @@ other: %n年前 - - Offline - - - - + All available tracks - - Online - - - - - + + Show - - + + Hide @@ -1146,17 +1170,17 @@ other: %n年前 - + New Additions - + My recent activity - + Recent activity from %1 @@ -1164,81 +1188,138 @@ other: %n年前 SourceItem - + Collection - + コレクション - - + + Latest Additions - + Recently Played - + Loved Tracks - + SuperCollection スーパーコレクション - + + Sorry, we could not find any loved tracks! + + + + Latest additions to your collection - + Latest additions to %1's collection - + + Sorry, we could not find any recent additions! + + + + Recently Played Tracks - + Your recently played tracks - + %1's recently played tracks + + + Sorry, we could not find any recent plays! + + SourceTreeView - + &Copy Link リンクをコピー - + &Delete %1 - + + Add to my Playlists + + + + + Add to my Automatic Playlists + + + + + Add to my Stations + + + + &Export Playlist - + + playlist + + + + + automatic playlist + + + + + station + + + + + Delete %1? + playlist/station/... + + + + + Would you like to delete the %1 <b>"%2"</b>? + e.g. Would you like to delete the playlist named Foobar? + + + + Save XSPF XSPFを保存する - + Playlists (*.xspf) @@ -1271,52 +1352,52 @@ other: %n年前 ステーション - + Browse - + Search History - + My Music マイミュージック - + SuperCollection スーパーコレクション - + Top Loved Tracks - + Dashboard ダッシュボード - + Recently Played 最近聴いたトラック - + Charts - + New Releases - + Friends @@ -1324,52 +1405,52 @@ other: %n年前 SpotifyConfig - + Form - + フォーム - + Configure your Spotify account - + Username or Facebook Email - + Log In - + ログイン - + Right click on any Tomahawk playlist to sync it to Spotify. - + High Quality Streams - + Spotify playlists to keep in sync: - + Delete Tomahawk playlist when removing synchronization - + Username: - + Password: @@ -1377,12 +1458,12 @@ other: %n年前 SpotifyPlaylistUpdater - + Delete in Spotify? - + Would you like to delete the corresponding Spotify playlist as well? @@ -1455,7 +1536,7 @@ other: %n年前 Set this to your external IP address or host name. Make sure to forward the port to this host! - + フォーム @@ -1516,46 +1597,46 @@ other: %n年前 Tomahawk::Accounts::AccountDelegate - + Add Account + アカウントを追加 + + + + Remove - - Remove Account - - - - + %1 downloads - + Online - + オンライン - + Connecting... - + Offline - + ・オフライン Tomahawk::Accounts::AccountModel - + Manual Install Required - - Unfortunately, automatic installation of this resolver is not yet available on Linux.<br /><br />Please use "Install from file" above, by fetching it from your distribution or compiling it yourself. Further instructions can be found here:<br /><br />http://www.tomahawk-player.org/resolvers/%1 + + Unfortunately, automatic installation of this resolver is not available or disabled for your platform.<br /><br />Please use "Install from file" above, by fetching it from your distribution or compiling it yourself. Further instructions can be found here:<br /><br />http://www.tomahawk-player.org/resolvers/%1 @@ -1606,7 +1687,7 @@ other: %n年前 Tomahawk::Accounts::LastFmAccountFactory - + Scrobble your tracks to last.fm, and find freely downloadable tracks to play @@ -1614,23 +1695,49 @@ other: %n年前 Tomahawk::Accounts::LastFmConfig - + + Testing... + + + + Test Login - - + + Importing %1 + e.g. Importing 2012/01/01 + + + + + Importing History... + + + + + History Incomplete. Resume + + + + + Playback History Imported + + + + + Failed - + Success - + Could not contact server @@ -1638,12 +1745,17 @@ other: %n年前 Tomahawk::Accounts::SpotifyAccount - + Sync with Spotify - + + Re-enable syncing with Spotify + + + + Stop syncing with Spotify @@ -1651,30 +1763,30 @@ other: %n年前 Tomahawk::Accounts::SpotifyAccountConfig - + Logging in... - + ログイン中... - + Logged in! - + ログインしました! - + Failed: %1 - + Log In - + ログイン Tomahawk::Accounts::SpotifyAccountFactory - + Play music from and sync your playlists with Spotify Premium @@ -1694,20 +1806,20 @@ other: %n年前 Tweet! - + ツイート! Status: No saved credentials - + ステータス: 保存された認証情報がありません Authenticate - + 認証 @@ -1756,17 +1868,17 @@ You may wish to try re-authenticating. Send Message! - メッセージを送信! + メッセージを送信! @Mention - + @メンション Send Mention! - + メンションを送信! @@ -1824,7 +1936,7 @@ You may wish to try re-authenticating. Tomahawk::Accounts::ZeroconfFactory - + Automatically connect to Tomahawks on the local network @@ -1838,29 +1950,29 @@ You may wish to try re-authenticating. - - + + Add to &Queue - + &Love &Love - + &Copy Track Link - + Un-&Love Loveじゃないトラック - + &Delete Items 項目を削除 @@ -1875,22 +1987,22 @@ You may wish to try re-authenticating. - + &Show Track Page - + &Delete Item 項目を削除 - + &Show Album Page - + &Show Artist Page @@ -1931,12 +2043,32 @@ You may wish to try re-authenticating. Tomahawk::DropJobNotifier - + + playlist + プレイリスト + + + + artist + アーティスト + + + + track + トラック + + + + album + アルバム + + + Fetching %1 from database - + Parsing %1 %2 @@ -1970,7 +2102,7 @@ Please change the filters or try again. Type: - + 入力: @@ -1981,17 +2113,17 @@ Please change the filters or try again. Tomahawk::DynamicView - + Add some filters above to seed this station! - + Press Generate to get started! - + Add some filters above, and press Generate to get started! @@ -1999,7 +2131,7 @@ Please change the filters or try again. Tomahawk::DynamicWidget - + Station ran out of tracks! Try tweaking the filters for a new set of songs to play. @@ -2316,92 +2448,92 @@ Try tweaking the filters for a new set of songs to play. - + Much less - + Less - + A bit less - + Keep at current - + A bit more - + More - + Much more - + Tempo - + Loudness - + Danceability - + Energy - + Song Hotttnesss - + Artist Hotttnesss - + Artist Familiarity - + By Description - + Enter a description - + Apply steering command - + Reset all steering commands @@ -2417,24 +2549,24 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::InfoSystem::ChartsPlugin - + Top Overall - + Artists - + アーティスト - + Albums - + アルバム - + Tracks - + トラック @@ -2453,27 +2585,27 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::InfoSystem::LastFmInfoPlugin - + Top Tracks - + Loved Tracks - + Hyped Tracks - + Top Artists - + Hyped Artists @@ -2481,15 +2613,15 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::InfoSystem::NewReleasesPlugin - + Albums - + アルバム Tomahawk::InfoSystem::TwitterInfoPlugin - + Listening to "%1" by %2 and loving it! %3 @@ -2547,37 +2679,37 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::Query - + and - + You - + you - + and - + %n other(s) - + %1 people - + loved this track @@ -2593,7 +2725,7 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::ShortenedLinkParser - + Network error parsing shortened link! @@ -2601,36 +2733,46 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::Source - - + + Scanning (%L1 tracks) - + Scanning 走査中 - + Checking - + Fetching 取得中 - + Parsing 解析中 - + Saving (%1%) + + + Online + + + + + Offline + + Tomahawk::SpotifyParser @@ -2651,7 +2793,7 @@ Try tweaking the filters for a new set of songs to play. TomahawkApp - + My Collection @@ -2673,39 +2815,48 @@ enter the displayed PIN number here: TomahawkTrayIcon - - + &Stop Playback after current Track - - + + Hide Tomahawk Window Tomahawkのウインドウを隠す - + Show Tomahawk Window Tomahawkのウインドウを表示 - + Currently not playing. - + Play 再生 - + Pause 一時停止 - + + &Love + + + + + Un-&Love + + + + &Continue Playback after current Track @@ -2725,7 +2876,7 @@ enter the displayed PIN number here: &Controls - + &制御 @@ -2750,7 +2901,7 @@ enter the displayed PIN number here: Ctrl+Q - + Ctrl+Q @@ -2815,12 +2966,12 @@ enter the displayed PIN number here: Minimize - 最小か + 最小化 Ctrl+M - + Ctrl+M @@ -2830,7 +2981,8 @@ enter the displayed PIN number here: Meta+Ctrl+Z - + +Meta+Ctrl+Z @@ -2849,9 +3001,9 @@ enter the displayed PIN number here: - + Play - + 再生 @@ -2861,172 +3013,182 @@ enter the displayed PIN number here: Previous - + 前へ Next - + 次へ - + Back - + プレイリスト - + Go back one page - + Forward - + Go forward one page - + Global Search... - - + + Check For Updates... - - - + + + Connect To Peer - + Enter peer address: - + Enter peer port: - + Enter peer key: - + XSPF Error - + This is not a valid XSPF playlist. - + Failed to save tracks - + Some tracks in the playlist do not contain an artist and a title. They will be ignored. - + Sorry, there is a problem accessing your audio device or the desired track, current track will be skipped. Make sure you have a suitable Phonon backend and required plugins installed. - + Sorry, there is a problem accessing your audio device or the desired track, current track will be skipped. - + + Station + ステーション + + + Create New Station 新規ステーションを作成 - + Name: + 名前: + + + + Playlist + プレイリスト + + + + Automatic Playlist - - New Station - - - - - New Playlist - - - - + Pause - + 一時停止 - + Go &offline - + Go &online - + Authentication Error - + Error connecting to SIP: Authentication failed! - + %1 by %2 track, artist name - + %1 by %2 - + %1 - %2 current track, some window title - + %1 - %2 - + <h2><b>Tomahawk %1<br/>(%2)</h2> - + <h2><b>Tomahawk %1<br/>(%2)</h2> - + <h2><b>Tomahawk %1</h2> - + <h2><b>Tomahawk %1</h2> - - Copyright 2010 - 2012<br/>Christian Muehlhaeuser &lt;muesli@tomahawk-player.org&gt;<br/><br/>Thanks to: Leo Franchi, Jeff Mitchell, Dominik Schmidt, Jason Herskowitz, Alejandro Wainzinger, Hugo Lindstr&ouml;m, Michael Zanetti, Harald Sitter and Steve Robertson - + + Copyright 2010 - 2012 + Copyright 2010 - 2012 - + + Thanks to: + Thanks to: + + + About Tomahawk - + Tomahawkについて @@ -3034,27 +3196,27 @@ enter the displayed PIN number here: Form - + フォーム 0 Sources - + ソースがありません。 0 Tracks - + トラックがありません 0 Artists - + アーティストがいません。 0 Shown - + 何もありません。 @@ -3074,30 +3236,30 @@ enter the displayed PIN number here: Artist View - + アーティストビュー Flat View - + フラットビュー Sources - + ソース Shown - + 項目 TopTracksContext - + Top Hits - + TOP HITS @@ -3105,146 +3267,73 @@ enter the displayed PIN number here: Form - + フォーム - + Cover - + カバー - + Track - + トラック - - by - - - - + Artist - + アーティスト - - from - - - - + Album - + アルバム - + Statistics - + 統計 - - Lyrics - - - - + Similar Tracks - + 似ているトラック + + + + Sorry, but we could not find similar tracks for this song! + この曲に似ているトラックが見つかりませんでした。 - + You've listened to this track %n time(s). - + このトラックは%n回聴いています。 - + You've never listened to this track before. - + このトラックを一度も聴いていません。 - + You first listened to it on %1. - + 初めてこの曲を聴いたのは、%1です。 - + You've listened to %1 %n time(s). - + %1を%n回聴いています。 - + You've never listened to %1 before. - - - - - TrackModel - - - Artist - - - - - Title - - - - - Album - - - - - Track - - - - - Duration - - - - - Bitrate - - - - - Age - - - - - Year - - - - - Size - - - - - Origin - - - - - Score - - - - - Composer - + %1を一度も聴いていません。 TrackView - + Sorry, your filter '%1' did not match any results. @@ -3254,12 +3343,12 @@ enter the displayed PIN number here: from - + から to - + まで @@ -3267,67 +3356,35 @@ enter the displayed PIN number here: Unknown - + 不明 TreeModel - - Name - - - - - Duration - - - - - Bitrate - - - - - Age - - - - - Year - - - - - Size - - - - - Origin - - - - - Composer - - - - + All Artists - + すべてのアーティスト - - + + My Collection - + マイコレクション - - + + Collection of %1 - + %1のコレクション + + + + TreeView + + + Sorry, your filter '%1' did not match any results. + %1に一致する結果は見つかりませんでした。 @@ -3335,27 +3392,27 @@ enter the displayed PIN number here: Configure this Twitter account - + このTwitterアカウントを設定する The Twitter plugin allows you to discover and play music from your Twitter friends running Tomahawk and post messages to your account. - + TwitterプラグインはTomahawkを使っているTwitterの友達があなたの曲を見つけて再生したり、あなたにメッセージを投稿することを許可します。 Status: No saved credentials - + ステータス: 保存された認証情報がありません Authenticate with Twitter - + Twitterで認証する Twitter Connections - + Twitter接続 @@ -3365,65 +3422,81 @@ If you only want to post tweets, you're done. If you want to connect Tomahawk to your friends using Twitter, select the type of tweet and press the button below to send a sync message. You must both be following each other as Direct Messages are used. Then be (very) patient -- it can take several minutes! You can re-send a sync message at any time simply by sending another tweet using the button. - + +ツイートするだけなら、これで設定は完了です。 + +Twitterを使っている友達にTomahawkを接続したいなら、ツイートの種類を選択し、以下のボタンを押してメッセージを送信して下さい。ダイレクトメッセージを使用するためにお互いのフォローが必要です。時間がかかる場合がありますので、しばらくお待ち下さい。 + +ボタンを押してもう一度ツイートを送信すると、メッセージをいつでも再送信できます。 Select the kind of tweet you would like, then press the button to post it: - + ツイートの種類を選択し、ボタンを押して投稿してください: Global Tweet - + ツイートする @Mention - + @メンション Direct Message - + ダイレクトメッセージ e.g. @tomahawk - + (例) @tomahawk Send Message - + メッセージを送信 ViewManager - + + After you have scanned your music collection you will find your tracks right here. + コレクションのスキャンが完了したら、トラックはここに表示されます。 + + + + This collection is empty. + このコレクションには何も入っていません。 + + + SuperCollection - + スーパーコレクション - + Combined libraries of all your online friends - + オンラインの友達全員のライブラリ - + All available albums - + すべてのアルバム + - + Recently Played Tracks - + 最近再生したトラック - + Recently played tracks from all your friends - + 友達の最近再生したトラック @@ -3431,35 +3504,35 @@ You can re-send a sync message at any time simply by sending another tweet using Recent Additions - + 最近追加した項目 Newest Stations & Playlists - + 最新のステーション & プレイリスト Recently Played Tracks - + 最近再生したトラック - + No recently created playlists in your network. - + ネットワークに最近作成したプレイリストはありません。 - + Welcome to Tomahawk - + Tomahawkへようこそ WhatsHotWidget - + Charts - + チャート @@ -3467,7 +3540,7 @@ You can re-send a sync message at any time simply by sending another tweet using Wikipedia - + ウィキペディア @@ -3477,12 +3550,14 @@ You can re-send a sync message at any time simply by sending another tweet using Terms for %1: - + +%1の語句: + No terms found, sorry. - + 語句と一致する結果は見つかりませんでした。 @@ -3528,7 +3603,7 @@ Lyrics for "%1" by %2: New Playlist - + 新規プレイリスト @@ -3542,32 +3617,32 @@ Lyrics for "%1" by %2: Filter - + フィルター Save log - + ログを保存 Disabled - + 無効 By JID - + JIDの順に分類する By namespace uri - + ネームスペースのURIの順に分類する By all attributes - + すべての属性の順に分類する @@ -3582,32 +3657,32 @@ Lyrics for "%1" by %2: Message - + メッセージ Presence - + 状態 Custom - + カスタム Close - + 閉じる Save XMPP log to file - + XMPPのログをファイルに保存する OpenDocument Format (*.odf);;HTML file (*.html);;Plain text (*.txt) - + OpenDocument Format (*.odf);;HTML file (*.html);;Plain text (*.txt) @@ -3615,178 +3690,178 @@ Lyrics for "%1" by %2: Xmpp Configuration - + XMPP設定 Configure this Xmpp account - + XMPPアカウントを設定 Enter your Xmpp login to connect with your friends using Tomahawk! - + Tomahawkを使っている友達とつながるためにXMPPログインを入力してください。 Login Information - + ログイン情報 Xmpp ID: - + XMPP ID: e.g. user@example.com - + (例) user@example.com Password: - + パスワード: An account with this name already exists! - + この名前のアカウントは既に存在しています! Advanced Xmpp Settings - + XMPPの詳細設定 Server: - + サーバー: Port: - + ポート: Lots of servers don't support this (e.g. GTalk, jabber.org) - + 多くのサーバで対応していません(例: GTalk, jabber.org) Publish currently playing track - + 今現在再生しているトラックを公開する Enforce secure connection - + 安全な接続を強制する XmppSipPlugin - + User Interaction - + ユーザインタラクション - + Host is unknown - + 不明なホスト - + Item not found - + 項目が見つかりません - + Authorization Error - + 認証エラー - + Remote Stream Error - + 配信エラー - + Remote Connection failed - + 接続に失敗しました - + Internal Server Error - + サーバ内部エラー - + System shutdown - + システム終了 - + Conflict - - - - - Unknown - + コンフリクト + Unknown + 不明 + + + No Compression Support - + 圧縮に対応していません - + No Encryption Support - + 暗号化に対応していません - + No Authorization Support - + Authorizationに対応していません - + No Supported Feature - + 未対応昨機能 - + Add Friend - + 友達を追加 - + Enter Xmpp ID: - + XMPP IDを入力: - + Add Friend... - + 友達を追加... - + XML Console... - + XMLコンソール... - + I'm sorry -- I'm just an automatic presence used by Tomahawk Player (http://gettomahawk.com). If you are getting this message, the person you are trying to reach is probably not signed on, so please try again later! - + Authorize User - + Do you want to grant <b>%1</b> access to your Collection? @@ -3796,7 +3871,7 @@ Lyrics for "%1" by %2: Form - + フォーム diff --git a/lang/tomahawk_pl.ts b/lang/tomahawk_pl.ts index 7722edbde..07723711e 100644 --- a/lang/tomahawk_pl.ts +++ b/lang/tomahawk_pl.ts @@ -2,17 +2,17 @@ AccountFactoryWrapper - + Dialog - + Description goes here Tutaj pojawi się opis - + Add Account Dodaj Konto @@ -20,17 +20,17 @@ AccountFactoryWrapperDelegate - + Online Online - + Connecting... Łączenie... - + Offline Offline @@ -133,7 +133,17 @@ connect and stream from you? Inne albumy artysty - + + Sorry, we could not find any other albums for this artist! + + + + + Sorry, we could not find any tracks for this album! + + + + Other Albums by %1 Inne albumy %1 @@ -141,35 +151,17 @@ connect and stream from you? AlbumModel - - Album - Album - - - - + + All albums from %1 Wszystkie albumy %1 - + All albums Wszystkie albumy - - AlbumView - - - After you have scanned your music collection you will find your latest album additions right here. - Po zeskanowaniu swojej kolekcji muzycznej w tym miejscu znajdziesz ostatnio dodane albumy. - - - - This collection doesn't have any recent albums. - Ta kolekcja nie zawiera żadnych nowo dodanych albumów. - - ArtistInfoWidget @@ -178,12 +170,12 @@ connect and stream from you? Formularz - + Top Hits Hity na Topie - + Related Artists Powiązani artyści @@ -192,23 +184,25 @@ connect and stream from you? Albums Albumy - - - ArtistView - - After you have scanned your music collection you will find your tracks right here. - Po zeskanowaniu swojej kolekcji muzycznej utwory znajdziesz w tym miejscu. + + Cover + - - This collection is currently empty. - Ta kolekcja jest aktualnie pusta. + + Sorry, we could not find any albums for this artist! + - - Sorry, your filter '%1' did not match any results. - Przepraszamy, twój filtr '%1' nie pasuje do żadnych wyników. + + Sorry, we could not find any related artists! + + + + + Sorry, we could not find any top hits for this artist! + @@ -234,57 +228,57 @@ connect and stream from you? Następny - + Artist Artysta - + Album Album - + Owner Właściciel - + social - + love ulubione - + Time Czas - + Time Left Pozostały czas - + Shuffle Losowo - + Repeat Powtarzaj - + Low Nisko - + High Wysoko @@ -293,22 +287,25 @@ connect and stream from you? CategoryAddItem - - New Playlist - Nowa lista + Create new Playlist + - - - - + + Create new Station + + + + + + New Station Nowa stacja - - - + + + %1 Station Stacja %1 @@ -334,27 +331,6 @@ connect and stream from you? Wyczyść - - CollectionFlatModel - - - My Collection - Moja Kolekcja - - - - Collection of %1 - Kolekcja %1 - - - - CollectionView - - - This collection is empty. - Ta kolekcja jest pusta. - - ContextWidget @@ -364,12 +340,12 @@ connect and stream from you? - + Show Footnotes Pokaż przypisy - + Hide Footnotes Schowaj przypisy @@ -383,7 +359,7 @@ connect and stream from you? - <html><head/><body><p><span style=" font-weight:600;">Sorry!</span> Tomahawk crashed. Please tell us about it! Tomahawk has created an error report for you that can help improve the stability in the future. You can now send the this report directly to the Tomahawk developers.</p></body></html> + <html><head/><body><p><span style=" font-weight:600;">Sorry!</span> Tomahawk crashed. Please tell us about it! Tomahawk 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 Tomahawk developers.</p></body></html> @@ -439,17 +415,17 @@ connect and stream from you? DelegateConfigWrapper - + About - + Delete Account Usuń Konto - + About this Account @@ -462,24 +438,11 @@ connect and stream from you? Diagnostyka Tomahawk - - Update - Aktualizuj - - - + Copy to Clipboard Skopiuj do schowka - - DropJob - - - No tracks found for given %1 - - - GlobalSearchWidget @@ -504,56 +467,43 @@ connect and stream from you? Informacje - + Filter... Filtruj... - - JobStatusView - - - Searching For - Szukanie - - - - Pending - w trakcie - - - - Idle - Bezczynny - - LastFmConfig - + Form - + Scrobble tracks to Last.fm Skrobluj utwory do Last.fm - + Username: Użytkownik: - + Password: Hasło: - + Test Login Test logowania + + + Import Playback History + + LastfmContext @@ -656,11 +606,80 @@ connect and stream from you? NewReleasesWidget - + New Releases Nowe Wydania + + PlayableModel + + + Artist + + + + + Title + + + + + Composer + + + + + Album + + + + + Track + + + + + Duration + + + + + Bitrate + + + + + Age + + + + + Year + + + + + Size + + + + + Origin + + + + + Score + + + + + + Name + + + PlaylistItemDelegate @@ -677,17 +696,17 @@ connect and stream from you? PlaylistLargeItemDelegate - + played %1 by you odtworzone %1 przez ciebie - + played %1 by %2 - + added %1 dodano %1 @@ -695,12 +714,12 @@ connect and stream from you? PlaylistModel - + A playlist by %1, created %2 %1 lista, utworzona %2 - + you Twoja @@ -756,7 +775,12 @@ connect and stream from you? PlaylistView - + + This playlist is currently empty. + + + + This playlist is currently empty. Add some tracks to it and enjoy the music! Ta lista jest aktualnie pusta. Dodaj do niej trochę piosenek i ciesz się muzyką! @@ -823,67 +847,67 @@ connect and stream from you? QObject - + %n year(s) ago %n rok temu%n lata temu%n lat temu - + %n year(s) %n rok%n lata%n lat - + %n month(s) ago %n miesiąc temu%n miesiące temu%n miesięcy temu - + %n month(s) %n miesiąc%n miesiące%n miesięcy - + %n week(s) ago %n tydzień temu%n tygodnie temu%n tygodni temu - + %n week(s) %n tydzień%n tygodnie%n tygodni - + %n day(s) ago %n dzień temu%n dni temu%n dni temu - + %n day(s) %n dzień%n dni%n dni - + %n hour(s) ago %n godzinę temu%n godziny temu%n godzin temu - + %n hour(s) %n godzinę%n godziny%n godzin - + %1 minutes ago %1 minut temu - + %1 minutes %1 minut - + just now przed chwilą @@ -920,20 +944,25 @@ connect and stream from you? - - Show Queue - Pokaż Kolejkę + + Open Queue + + + + + Open Queue - %n item(s) + - - Hide Queue - Ukryj Kolejkę + + Close Queue + RelatedArtistsContext - + Related Artists Podobni Artyści @@ -1056,17 +1085,22 @@ connect and stream from you? - - Listening to "%1" by %2 and loving it! %3 + + Tweet - - Listening to "%1" by %2 on "%3" and loving it! %4 + + Listening to "%1" by %2. %3 - + + Listening to "%1" by %2 on "%3". %4 + + + + %1 characters left pozostało znaków: %1 @@ -1099,29 +1133,19 @@ connect and stream from you? Top 10 - - Offline - Offline - - - + All available tracks Wszystkie dostępne utwory - - Online - Online - - - - + + Show Pokaż - - + + Hide Ukryj @@ -1144,17 +1168,17 @@ connect and stream from you? Ostatnio Odtwarzane Utwory - + New Additions Nowo dodane - + My recent activity Moja ostatnia aktywność - + Recent activity from %1 Ostatnia aktywność %1 @@ -1162,81 +1186,138 @@ connect and stream from you? SourceItem - + Collection Kolekcja - - + + Latest Additions Ostatnio Dodane - + Recently Played Ostatnio Odtworzone - + Loved Tracks Ulubione Utwory - + SuperCollection Superkolekcja - + + Sorry, we could not find any loved tracks! + + + + Latest additions to your collection - + Latest additions to %1's collection - + + Sorry, we could not find any recent additions! + + + + Recently Played Tracks - + Your recently played tracks - + %1's recently played tracks + + + Sorry, we could not find any recent plays! + + SourceTreeView - + &Copy Link &Kopiuj Link - + &Delete %1 &Usuń %1 - + + Add to my Playlists + + + + + Add to my Automatic Playlists + + + + + Add to my Stations + + + + &Export Playlist &Eksportuj Listę - + + playlist + + + + + automatic playlist + + + + + station + + + + + Delete %1? + playlist/station/... + + + + + Would you like to delete the %1 <b>"%2"</b>? + e.g. Would you like to delete the playlist named Foobar? + + + + Save XSPF Zapisz XSPF - + Playlists (*.xspf) Listy (*.xspf) @@ -1269,52 +1350,52 @@ connect and stream from you? Stacja - + Browse Przeglądaj - + Search History Historia wyszukiwania - + My Music Moja Muzyka - + SuperCollection Superkolekcja - + Top Loved Tracks - + Dashboard - + Recently Played Ostatnio Odtworzone - + Charts Listy Przebojów - + New Releases Nowe Wydania - + Friends Znajomi @@ -1322,52 +1403,52 @@ connect and stream from you? SpotifyConfig - + Form - + Configure your Spotify account - + Username or Facebook Email - + Log In - + Right click on any Tomahawk playlist to sync it to Spotify. - + High Quality Streams - + Spotify playlists to keep in sync: - + Delete Tomahawk playlist when removing synchronization - + Username: Użytkownik: - + Password: Hasło: @@ -1375,12 +1456,12 @@ connect and stream from you? SpotifyPlaylistUpdater - + Delete in Spotify? - + Would you like to delete the corresponding Spotify playlist as well? @@ -1518,32 +1599,32 @@ indywidualnego profilu gustu. Tomahawk::Accounts::AccountDelegate - + Add Account Dodaj Konto - - Remove Account - Usuń Konto + + Remove + - + %1 downloads pobrań: %1 - + Online Online - + Connecting... Łączenie... - + Offline Offline @@ -1551,13 +1632,13 @@ indywidualnego profilu gustu. Tomahawk::Accounts::AccountModel - + Manual Install Required - - Unfortunately, automatic installation of this resolver is not yet available on Linux.<br /><br />Please use "Install from file" above, by fetching it from your distribution or compiling it yourself. Further instructions can be found here:<br /><br />http://www.tomahawk-player.org/resolvers/%1 + + Unfortunately, automatic installation of this resolver is not available or disabled for your platform.<br /><br />Please use "Install from file" above, by fetching it from your distribution or compiling it yourself. Further instructions can be found here:<br /><br />http://www.tomahawk-player.org/resolvers/%1 @@ -1608,7 +1689,7 @@ indywidualnego profilu gustu. Tomahawk::Accounts::LastFmAccountFactory - + Scrobble your tracks to last.fm, and find freely downloadable tracks to play @@ -1616,23 +1697,49 @@ indywidualnego profilu gustu. Tomahawk::Accounts::LastFmConfig - + + Testing... + + + + Test Login - - + + Importing %1 + e.g. Importing 2012/01/01 + + + + + Importing History... + + + + + History Incomplete. Resume + + + + + Playback History Imported + + + + + Failed - + Success - + Could not contact server @@ -1640,12 +1747,17 @@ indywidualnego profilu gustu. Tomahawk::Accounts::SpotifyAccount - + Sync with Spotify - + + Re-enable syncing with Spotify + + + + Stop syncing with Spotify @@ -1653,22 +1765,22 @@ indywidualnego profilu gustu. Tomahawk::Accounts::SpotifyAccountConfig - + Logging in... - + Logged in! - + Failed: %1 - + Log In @@ -1676,7 +1788,7 @@ indywidualnego profilu gustu. Tomahawk::Accounts::SpotifyAccountFactory - + Play music from and sync your playlists with Spotify Premium @@ -1826,7 +1938,7 @@ You may wish to try re-authenticating. Tomahawk::Accounts::ZeroconfFactory - + Automatically connect to Tomahawks on the local network @@ -1840,29 +1952,29 @@ You may wish to try re-authenticating. - - + + Add to &Queue Dodaj do &kolejki - + &Love &Uwielbiam - + &Copy Track Link - + Un-&Love - + &Delete Items &Usuń pozycje @@ -1877,22 +1989,22 @@ You may wish to try re-authenticating. &Zatrzymaj odtwarzanie po tym utworze - + &Show Track Page - + &Delete Item &Usuń pozycję - + &Show Album Page - + &Show Artist Page @@ -1933,12 +2045,32 @@ You may wish to try re-authenticating. Tomahawk::DropJobNotifier - + + playlist + + + + + artist + + + + + track + + + + + album + + + + Fetching %1 from database Wydobywanie %1 z bazy danych - + Parsing %1 %2 Analizowanie %1 %2 @@ -1985,17 +2117,17 @@ Proszę zmienić filtry lub spróbować ponownie. Tomahawk::DynamicView - + Add some filters above to seed this station! Dodaj powyżej trochę filtrów, a Tomahawk utworzy stację z podobną muzyką! - + Press Generate to get started! Naciśnij Generuj aby zacząć! - + Add some filters above, and press Generate to get started! Dodaj powyżej trochę filtrów i naciśnij Generuj aby zacząć! @@ -2003,7 +2135,7 @@ Proszę zmienić filtry lub spróbować ponownie. Tomahawk::DynamicWidget - + Station ran out of tracks! Try tweaking the filters for a new set of songs to play. @@ -2320,92 +2452,92 @@ Try tweaking the filters for a new set of songs to play. Steruj tą stacją: - + Much less Dużo mniej - + Less Mniej - + A bit less Trochę mniej - + Keep at current Pozostaw jak jest - + A bit more Trochę więcej - + More Więcej - + Much more Dużo więcej - + Tempo Tempo - + Loudness Głośność - + Danceability Taneczność - + Energy Energiczność - + Song Hotttnesss - + Artist Hotttnesss - + Artist Familiarity Znajomość Artysty - + By Description Po Opisie - + Enter a description Wprowadź opis - + Apply steering command Zastosuj komendę sterowania - + Reset all steering commands Zresetuj wszystkie komendy sterowania @@ -2421,22 +2553,22 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::InfoSystem::ChartsPlugin - + Top Overall Top Wszechczasów - + Artists Artyści - + Albums Albumy - + Tracks Utwory @@ -2457,27 +2589,27 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::InfoSystem::LastFmInfoPlugin - + Top Tracks - + Loved Tracks - + Hyped Tracks - + Top Artists - + Hyped Artists @@ -2485,7 +2617,7 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::InfoSystem::NewReleasesPlugin - + Albums Albumy @@ -2493,7 +2625,7 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::InfoSystem::TwitterInfoPlugin - + Listening to "%1" by %2 and loving it! %3 @@ -2551,37 +2683,37 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::Query - + and i - + You Ty - + you ty - + and i - + %n other(s) %n inny%n inne%n innych - + %1 people - + loved this track @@ -2597,7 +2729,7 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::ShortenedLinkParser - + Network error parsing shortened link! @@ -2605,36 +2737,46 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::Source - - + + Scanning (%L1 tracks) Skanowanie (%L1 utworów) - + Scanning Skanowanie - + Checking Sprawdzanie - + Fetching Pobieranie - + Parsing Analizowanie - + Saving (%1%) Zapisywanie (%1%) + + + Online + + + + + Offline + + Tomahawk::SpotifyParser @@ -2655,7 +2797,7 @@ Try tweaking the filters for a new set of songs to play. TomahawkApp - + My Collection Moja Kolekcja @@ -2678,39 +2820,48 @@ wprowadź pokazany numer PIN tutaj: TomahawkTrayIcon - - + &Stop Playback after current Track - - + + Hide Tomahawk Window Ukryj Okno Tomahawka - + Show Tomahawk Window Pokaż Okno Tomahawka - + Currently not playing. Aktualnie nie odtwarza. - + Play Odtwarzaj - + Pause Pauza - + + &Love + + + + + Un-&Love + + + + &Continue Playback after current Track @@ -2854,7 +3005,7 @@ wprowadź pokazany numer PIN tutaj: - + Play Odtwarzaj @@ -2874,162 +3025,172 @@ wprowadź pokazany numer PIN tutaj: Następny - + Back - + Go back one page - + Forward - + Go forward one page - + Global Search... Globalne Wyszukiwanie... - - + + Check For Updates... Sprawdź uaktualnienia... - - - + + + Connect To Peer - + Enter peer address: - + Enter peer port: - + Enter peer key: - + XSPF Error Błąd XSPF - + This is not a valid XSPF playlist. To nie jest poprawna lista XSPF. - + Failed to save tracks Nie udało się zapisać utworów - + Some tracks in the playlist do not contain an artist and a title. They will be ignored. Niektóre utwory na liście nie zawierają artysty i tytułu. Zostaną one zignorowane. - + Sorry, there is a problem accessing your audio device or the desired track, current track will be skipped. Make sure you have a suitable Phonon backend and required plugins installed. - + Sorry, there is a problem accessing your audio device or the desired track, current track will be skipped. - + + Station + + + + Create New Station Utwórz Nową Stację - + Name: Nazwa: - - New Station - Nowa stacja + + Playlist + - - New Playlist - Nowa Lista + + Automatic Playlist + - + Pause Pauza - + Go &offline Przejdź do trybu &offline - + Go &online Przejdź do trybu &online - + Authentication Error Błąd uwierzytelniania - + Error connecting to SIP: Authentication failed! - + %1 by %2 track, artist name %1 wykonawcy %2 - + %1 - %2 current track, some window title %1 - %2 - + <h2><b>Tomahawk %1<br/>(%2)</h2> - + <h2><b>Tomahawk %1</h2> - - Copyright 2010 - 2012<br/>Christian Muehlhaeuser &lt;muesli@tomahawk-player.org&gt;<br/><br/>Thanks to: Leo Franchi, Jeff Mitchell, Dominik Schmidt, Jason Herskowitz, Alejandro Wainzinger, Hugo Lindstr&ouml;m, Michael Zanetti, Harald Sitter and Steve Robertson + + Copyright 2010 - 2012 - + + Thanks to: + + + + About Tomahawk @@ -3100,7 +3261,7 @@ wprowadź pokazany numer PIN tutaj: TopTracksContext - + Top Hits Hity na Topie @@ -3113,143 +3274,70 @@ wprowadź pokazany numer PIN tutaj: - + Cover - + Track - - by - - - - + Artist - - from - - - - + Album - + Statistics - - Lyrics - - - - + Similar Tracks + + + Sorry, but we could not find similar tracks for this song! + + - + You've listened to this track %n time(s). - + You've never listened to this track before. - + You first listened to it on %1. - + You've listened to %1 %n time(s). - + You've never listened to %1 before. - - TrackModel - - - Artist - Artysta - - - - Title - Tytuł - - - - Album - Album - - - - Track - Utwór - - - - Duration - Czas trwania - - - - Bitrate - Bitrate - - - - Age - Wiek - - - - Year - Rok - - - - Size - Rozmiar - - - - Origin - Pochodzenie - - - - Score - Punktacja - - - - Composer - Kompozytor - - TrackView - + Sorry, your filter '%1' did not match any results. Przepraszamy, twój filtr '%1' nie dopasował żadnych wyników. @@ -3278,63 +3366,31 @@ wprowadź pokazany numer PIN tutaj: TreeModel - - Name - Nazwa - - - - Duration - Czas trwania - - - - Bitrate - Bitrate - - - - Age - Wiek - - - - Year - Rok - - - - Size - Rozmiar - - - - Origin - Pochodzenie - - - - Composer - Kompozytor - - - + All Artists Wszyscy Artyści - - + + My Collection Moja Kolekcja - - + + Collection of %1 Kolekcja %1 + + TreeView + + + Sorry, your filter '%1' did not match any results. + + + TwitterConfigWidget @@ -3411,27 +3467,37 @@ Zawsze możesz ponownie wysłać wiadomość synchronizacyjną - po prostu wyśl ViewManager - + + After you have scanned your music collection you will find your tracks right here. + + + + + This collection is empty. + + + + SuperCollection SuperKolekcja - + Combined libraries of all your online friends Połączone biblioteki wszystkich twoich znajomych online - + All available albums Wszystkie dostępne albumy - + Recently Played Tracks - + Recently played tracks from all your friends @@ -3454,12 +3520,12 @@ Zawsze możesz ponownie wysłać wiadomość synchronizacyjną - po prostu wyśl Ostatnio Odtworzone Utwory - + No recently created playlists in your network. Brak ostatnio utworzonych list w twojej sieci. - + Welcome to Tomahawk Witaj w Tomahawk @@ -3467,7 +3533,7 @@ Zawsze możesz ponownie wysłać wiadomość synchronizacyjną - po prostu wyśl WhatsHotWidget - + Charts Listy przebojów @@ -3702,107 +3768,107 @@ Tekst dla "%1" wykonawcy %2: XmppSipPlugin - + User Interaction - + Host is unknown Nieznany Host - + Item not found - + Authorization Error - + Remote Stream Error - + Remote Connection failed Połączenie sieciowe się nie powiodło - + Internal Server Error Wewnętrzny błąd serwera - + System shutdown Wyłączenie systemu - + Conflict Konflikt - + Unknown Nieznany - + No Compression Support Brak obsługi kompresji - + No Encryption Support Brak obsługi szyfrowania - + No Authorization Support Brak obsługi autoryzacji - + No Supported Feature Brak obsługi danej funkcji - + Add Friend Dodaj Znajomego - + Enter Xmpp ID: - + Add Friend... Dodaj Znajomego... - + XML Console... Konsola XML... - + I'm sorry -- I'm just an automatic presence used by Tomahawk Player (http://gettomahawk.com). If you are getting this message, the person you are trying to reach is probably not signed on, so please try again later! - + Authorize User Autoryzuj Użytkownika - + Do you want to grant <b>%1</b> access to your Collection? Czy chcesz udzielić dostępu do swojej kolekcji <b>%1</b>? diff --git a/lang/tomahawk_pt_BR.ts b/lang/tomahawk_pt_BR.ts index 659d0c6bf..16bccd17e 100644 --- a/lang/tomahawk_pt_BR.ts +++ b/lang/tomahawk_pt_BR.ts @@ -2,17 +2,17 @@ AccountFactoryWrapper - + Dialog - + Description goes here - + Add Account Adicionar Conta @@ -20,17 +20,17 @@ AccountFactoryWrapperDelegate - + Online - + Connecting... Conectando... - + Offline @@ -133,7 +133,17 @@ connect and stream from you? Outros álbuns do artista - + + Sorry, we could not find any other albums for this artist! + + + + + Sorry, we could not find any tracks for this album! + + + + Other Albums by %1 Outros álbuns por %1 @@ -141,35 +151,17 @@ connect and stream from you? AlbumModel - - Album - Álbum - - - - + + All albums from %1 Todos os álbuns de %1 - + All albums Todos os álbuns - - AlbumView - - - After you have scanned your music collection you will find your latest album additions right here. - Depois que você escanear a sua biblioteca musical você encontrará aqui o último álbum adicionado. - - - - This collection doesn't have any recent albums. - Essa biblioteca não tem nenhum álbum recente. - - ArtistInfoWidget @@ -178,12 +170,12 @@ connect and stream from you? Formulário - + Top Hits Maiores sucessos - + Related Artists Artistas relacionados @@ -192,23 +184,25 @@ connect and stream from you? Albums Álbuns - - - ArtistView - - After you have scanned your music collection you will find your tracks right here. - Depois que você escanear a sua biblioteca musical você encontrará aqui as suas faixas. + + Cover + - - This collection is currently empty. - Essa biblioteca está vazia. + + Sorry, we could not find any albums for this artist! + - - Sorry, your filter '%1' did not match any results. - Desculpe, o seu filtro '%1' não encontreou nenhum resultado. + + Sorry, we could not find any related artists! + + + + + Sorry, we could not find any top hits for this artist! + @@ -234,57 +228,57 @@ connect and stream from you? Próxima - + Artist Artista - + Album Álbum - + Owner Proprietário - + social - + love Favorita - + Time Tempo - + Time Left Tempo restante - + Shuffle Embaralhar - + Repeat Repetir - + Low Diminuir - + High Aumentar @@ -293,22 +287,25 @@ connect and stream from you? CategoryAddItem - - New Playlist - Nova lista de reprodução + Create new Playlist + - - - - + + Create new Station + + + + + + New Station Nova estação - - - + + + %1 Station %1 Estação @@ -334,27 +331,6 @@ connect and stream from you? Limpar - - CollectionFlatModel - - - My Collection - Minha biblioteca - - - - Collection of %1 - Biblioteca de %1 - - - - CollectionView - - - This collection is empty. - Essa biblioteca está vazia. - - ContextWidget @@ -364,12 +340,12 @@ connect and stream from you? - + Show Footnotes Mostrar rodapé - + Hide Footnotes Ocultar rodapé @@ -383,7 +359,7 @@ connect and stream from you? - <html><head/><body><p><span style=" font-weight:600;">Sorry!</span> Tomahawk crashed. Please tell us about it! Tomahawk has created an error report for you that can help improve the stability in the future. You can now send the this report directly to the Tomahawk developers.</p></body></html> + <html><head/><body><p><span style=" font-weight:600;">Sorry!</span> Tomahawk crashed. Please tell us about it! Tomahawk 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 Tomahawk developers.</p></body></html> @@ -439,17 +415,17 @@ connect and stream from you? DelegateConfigWrapper - + About - + Delete Account Excluir Conta - + About this Account @@ -462,24 +438,11 @@ connect and stream from you? Diagnóstico do Tomahawk - - Update - Atualização - - - + Copy to Clipboard Copiar - - DropJob - - - No tracks found for given %1 - Nenhuma faixa encontrada para %1 - - GlobalSearchWidget @@ -504,56 +467,43 @@ connect and stream from you? Barra de informações - + Filter... Filtro... - - JobStatusView - - - Searching For - Buscando por - - - - Pending - Pendente - - - - Idle - Ocioso - - LastFmConfig - + Form - + Scrobble tracks to Last.fm - + Username: - + Password: Senha: - + Test Login + + + Import Playback History + + LastfmContext @@ -656,11 +606,80 @@ connect and stream from you? NewReleasesWidget - + New Releases + + PlayableModel + + + Artist + + + + + Title + + + + + Composer + + + + + Album + + + + + Track + + + + + Duration + + + + + Bitrate + + + + + Age + + + + + Year + + + + + Size + + + + + Origin + + + + + Score + + + + + + Name + + + PlaylistItemDelegate @@ -677,17 +696,17 @@ connect and stream from you? PlaylistLargeItemDelegate - + played %1 by you tocada %1 por você - + played %1 by %2 tocada %1 por %2 - + added %1 adicionou %1 @@ -695,12 +714,12 @@ connect and stream from you? PlaylistModel - + A playlist by %1, created %2 Uma lista de reprodução de %1, criada %2 - + you você @@ -756,7 +775,12 @@ connect and stream from you? PlaylistView - + + This playlist is currently empty. + + + + This playlist is currently empty. Add some tracks to it and enjoy the music! Esta lista de reprodução está vazia. Adicione algumas faixas para disfrutar de uma música! @@ -823,67 +847,67 @@ connect and stream from you? QObject - + %n year(s) ago %n year ago%n years ago - + %n year(s) %n year%n years - + %n month(s) ago %n month ago%n months ago - + %n month(s) %n month%n months - + %n week(s) ago %n week ago%n weeks ago - + %n week(s) %n week%n weeks - + %n day(s) ago %n day ago%n days ago - + %n day(s) %n day%n days - + %n hour(s) ago %n hour ago%n hours ago - + %n hour(s) %n hour%n hours - + %1 minutes ago %1 minutos atrás - + %1 minutes %1 minutos - + just now agora @@ -920,20 +944,25 @@ connect and stream from you? - - Show Queue - Mostrar fila + + Open Queue + + + + + Open Queue - %n item(s) + - - Hide Queue - Ocultar fila + + Close Queue + RelatedArtistsContext - + Related Artists Artistas relacionados @@ -1056,17 +1085,22 @@ connect and stream from you? - - Listening to "%1" by %2 and loving it! %3 + + Tweet - - Listening to "%1" by %2 on "%3" and loving it! %4 + + Listening to "%1" by %2. %3 - + + Listening to "%1" by %2 on "%3". %4 + + + + %1 characters left @@ -1099,29 +1133,19 @@ connect and stream from you? 10 Mais - - Offline - Desconectado - - - + All available tracks Todas as faixas disponíveis - - Online - Conectado - - - - + + Show Mostrar - - + + Hide Ocultar @@ -1144,17 +1168,17 @@ connect and stream from you? Faixas reproduzidas recentemente - + New Additions Novas adições - + My recent activity Minha atividade recentes - + Recent activity from %1 Atividade recente de %1 @@ -1162,81 +1186,138 @@ connect and stream from you? SourceItem - + Collection Biblioteca - - + + Latest Additions - + Recently Played - + Loved Tracks Faixas favoritas - + SuperCollection - + + Sorry, we could not find any loved tracks! + + + + Latest additions to your collection - + Latest additions to %1's collection - + + Sorry, we could not find any recent additions! + + + + Recently Played Tracks - + Your recently played tracks - + %1's recently played tracks + + + Sorry, we could not find any recent plays! + + SourceTreeView - + &Copy Link &Copiar link - + &Delete %1 &Eliminar %1 - + + Add to my Playlists + + + + + Add to my Automatic Playlists + + + + + Add to my Stations + + + + &Export Playlist &Exportar lista de reprodução - + + playlist + + + + + automatic playlist + + + + + station + + + + + Delete %1? + playlist/station/... + + + + + Would you like to delete the %1 <b>"%2"</b>? + e.g. Would you like to delete the playlist named Foobar? + + + + Save XSPF Salvar XSPF - + Playlists (*.xspf) Listas de reprodução (*.xspf) @@ -1269,52 +1350,52 @@ connect and stream from you? Estação - + Browse Navegar - + Search History Histórico de Busca - + My Music - + SuperCollection - + Top Loved Tracks Faixas favoritas - + Dashboard Painel - + Recently Played - + Charts Gráficos - + New Releases - + Friends Amigos @@ -1322,52 +1403,52 @@ connect and stream from you? SpotifyConfig - + Form - + Configure your Spotify account - + Username or Facebook Email - + Log In - + Right click on any Tomahawk playlist to sync it to Spotify. Clique com o botão direito em qualquer playlist do Tomahawk para sincronizá-la com o Spotify. - + High Quality Streams - + Spotify playlists to keep in sync: - + Delete Tomahawk playlist when removing synchronization - + Username: - + Password: Senha: @@ -1375,12 +1456,12 @@ connect and stream from you? SpotifyPlaylistUpdater - + Delete in Spotify? - + Would you like to delete the corresponding Spotify playlist as well? @@ -1517,32 +1598,32 @@ connect and stream from you? Tomahawk::Accounts::AccountDelegate - + Add Account Adicionar Conta - - Remove Account - Remover Conta + + Remove + - + %1 downloads - + Online - + Connecting... Conectando... - + Offline @@ -1550,13 +1631,13 @@ connect and stream from you? Tomahawk::Accounts::AccountModel - + Manual Install Required - - Unfortunately, automatic installation of this resolver is not yet available on Linux.<br /><br />Please use "Install from file" above, by fetching it from your distribution or compiling it yourself. Further instructions can be found here:<br /><br />http://www.tomahawk-player.org/resolvers/%1 + + Unfortunately, automatic installation of this resolver is not available or disabled for your platform.<br /><br />Please use "Install from file" above, by fetching it from your distribution or compiling it yourself. Further instructions can be found here:<br /><br />http://www.tomahawk-player.org/resolvers/%1 @@ -1607,7 +1688,7 @@ connect and stream from you? Tomahawk::Accounts::LastFmAccountFactory - + Scrobble your tracks to last.fm, and find freely downloadable tracks to play @@ -1615,23 +1696,49 @@ connect and stream from you? Tomahawk::Accounts::LastFmConfig - + + Testing... + + + + Test Login - - + + Importing %1 + e.g. Importing 2012/01/01 + + + + + Importing History... + + + + + History Incomplete. Resume + + + + + Playback History Imported + + + + + Failed Falhou - + Success Sucesso - + Could not contact server @@ -1639,12 +1746,17 @@ connect and stream from you? Tomahawk::Accounts::SpotifyAccount - + Sync with Spotify - + + Re-enable syncing with Spotify + + + + Stop syncing with Spotify @@ -1652,22 +1764,22 @@ connect and stream from you? Tomahawk::Accounts::SpotifyAccountConfig - + Logging in... - + Logged in! - + Failed: %1 - + Log In @@ -1675,7 +1787,7 @@ connect and stream from you? Tomahawk::Accounts::SpotifyAccountFactory - + Play music from and sync your playlists with Spotify Premium @@ -1825,7 +1937,7 @@ You may wish to try re-authenticating. Tomahawk::Accounts::ZeroconfFactory - + Automatically connect to Tomahawks on the local network @@ -1839,29 +1951,29 @@ You may wish to try re-authenticating. - - + + Add to &Queue Adicionar à &lista - + &Love - + &Copy Track Link - + Un-&Love - + &Delete Items &Eliminar itens @@ -1876,22 +1988,22 @@ You may wish to try re-authenticating. - + &Show Track Page - + &Delete Item &Eliminar item - + &Show Album Page - + &Show Artist Page @@ -1932,12 +2044,32 @@ You may wish to try re-authenticating. Tomahawk::DropJobNotifier - + + playlist + + + + + artist + + + + + track + + + + + album + + + + Fetching %1 from database Buscando %1 na base de dados - + Parsing %1 %2 Analisando %1 %2 @@ -1984,17 +2116,17 @@ Por favor, mude os filtros ou tente novamente. Tomahawk::DynamicView - + Add some filters above to seed this station! Adicione alguns filtros para alimentar essa estação! - + Press Generate to get started! Precione Criar para iniciar! - + Add some filters above, and press Generate to get started! Adicione alguns filtros acima e precione Criar para iniciar! @@ -2002,7 +2134,7 @@ Por favor, mude os filtros ou tente novamente. Tomahawk::DynamicWidget - + Station ran out of tracks! Try tweaking the filters for a new set of songs to play. @@ -2319,92 +2451,92 @@ Try tweaking the filters for a new set of songs to play. Conduzir essa estação: - + Much less Muito menos - + Less Menos - + A bit less Um pouco menos - + Keep at current Manter atual - + A bit more Um pouco mais - + More Mais - + Much more Muito mais - + Tempo Tempo - + Loudness Mais alto - + Danceability Habilidade de dança - + Energy Energia - + Song Hotttnesss Canções preferidas - + Artist Hotttnesss Artistas preferidos - + Artist Familiarity Familiaridade do artista - + By Description Por descrição - + Enter a description Coloque uma descrição - + Apply steering command Aplicar comando de condução - + Reset all steering commands Redefinir todos os comandos de direção @@ -2420,22 +2552,22 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::InfoSystem::ChartsPlugin - + Top Overall Classificação geral - + Artists Artistas - + Albums Álbuns - + Tracks Faixas @@ -2456,27 +2588,27 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::InfoSystem::LastFmInfoPlugin - + Top Tracks - + Loved Tracks - + Hyped Tracks - + Top Artists - + Hyped Artists @@ -2484,7 +2616,7 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::InfoSystem::NewReleasesPlugin - + Albums @@ -2492,7 +2624,7 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::InfoSystem::TwitterInfoPlugin - + Listening to "%1" by %2 and loving it! %3 @@ -2550,37 +2682,37 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::Query - + and e - + You - + you - + and e - + %n other(s) - + %1 people %1 pessoas - + loved this track @@ -2596,7 +2728,7 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::ShortenedLinkParser - + Network error parsing shortened link! @@ -2604,36 +2736,46 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::Source - - + + Scanning (%L1 tracks) Escaneando (%L1 faixas) - + Scanning Escaneando - + Checking Verificando - + Fetching Buscando - + Parsing Analisando - + Saving (%1%) Guardando (%1%) + + + Online + + + + + Offline + + Tomahawk::SpotifyParser @@ -2654,7 +2796,7 @@ Try tweaking the filters for a new set of songs to play. TomahawkApp - + My Collection Minha biblioteca @@ -2677,39 +2819,48 @@ colocar o número PIN mostrado aqui: TomahawkTrayIcon - - + &Stop Playback after current Track - - + + Hide Tomahawk Window Esconder janela do Tomahawk - + Show Tomahawk Window Mostrar janela do Tomahawk - + Currently not playing. Não reproduzindo nada. - + Play Reporduzir - + Pause Pausar - + + &Love + + + + + Un-&Love + + + + &Continue Playback after current Track @@ -2853,7 +3004,7 @@ colocar o número PIN mostrado aqui: - + Play Reporduzir @@ -2873,162 +3024,172 @@ colocar o número PIN mostrado aqui: Próximo - + Back - + Go back one page - + Forward - + Go forward one page - + Global Search... Busca global... - - + + Check For Updates... Buscar atualizações... - - - + + + Connect To Peer Conectar-se ao par - + Enter peer address: Coloque o endereço do par: - + Enter peer port: Coloque a porta do par: - + Enter peer key: Coloque a chave do par: - + XSPF Error Erro de XSPF - + This is not a valid XSPF playlist. Esta não é uma lista de reprodução XSPF válida. - + Failed to save tracks Falha ao salvar faixas - + Some tracks in the playlist do not contain an artist and a title. They will be ignored. Algumas faixas da lista de reprodução não contem artista e título. Estas serão ignoradas. - + Sorry, there is a problem accessing your audio device or the desired track, current track will be skipped. Make sure you have a suitable Phonon backend and required plugins installed. - + Sorry, there is a problem accessing your audio device or the desired track, current track will be skipped. - + + Station + + + + Create New Station Criar uma nova estação - + Name: Nome: - - New Station - Nova estação + + Playlist + - - New Playlist - Nova lista de reprodução + + Automatic Playlist + - + Pause Pausar - + Go &offline Desc&onectar - + Go &online C&onectar - + Authentication Error Erro de autenticação - + Error connecting to SIP: Authentication failed! - + %1 by %2 track, artist name %1 de %2 - + %1 - %2 current track, some window title %1 - %2 - + <h2><b>Tomahawk %1<br/>(%2)</h2> <h2><b>Tomahawk %1<br/>(%2)</h2> - + <h2><b>Tomahawk %1</h2> <h2><b>Tomahawk %1</h2> - - Copyright 2010 - 2012<br/>Christian Muehlhaeuser &lt;muesli@tomahawk-player.org&gt;<br/><br/>Thanks to: Leo Franchi, Jeff Mitchell, Dominik Schmidt, Jason Herskowitz, Alejandro Wainzinger, Hugo Lindstr&ouml;m, Michael Zanetti, Harald Sitter and Steve Robertson + + Copyright 2010 - 2012 - + + Thanks to: + + + + About Tomahawk Sobre o Tomahawk @@ -3099,7 +3260,7 @@ colocar o número PIN mostrado aqui: TopTracksContext - + Top Hits Maiores sucessos @@ -3112,143 +3273,70 @@ colocar o número PIN mostrado aqui: - + Cover - + Track - - by - - - - + Artist - - from - - - - + Album - + Statistics - - Lyrics - - - - + Similar Tracks + + + Sorry, but we could not find similar tracks for this song! + + - + You've listened to this track %n time(s). - + You've never listened to this track before. - + You first listened to it on %1. - + You've listened to %1 %n time(s). - + You've never listened to %1 before. - - TrackModel - - - Artist - Artista - - - - Title - Título - - - - Album - Álbum - - - - Track - Faixa - - - - Duration - Duração - - - - Bitrate - Taxa de bits - - - - Age - Idate - - - - Year - Ano - - - - Size - Tamanho - - - - Origin - Origem - - - - Score - Pontuação - - - - Composer - - - TrackView - + Sorry, your filter '%1' did not match any results. Desculpe, o seu filtro '%1' não encontreou nenhum resultado. @@ -3277,63 +3365,31 @@ colocar o número PIN mostrado aqui: TreeModel - - Name - Nome - - - - Duration - Duração - - - - Bitrate - Taxa de bits - - - - Age - Idate - - - - Year - Ano - - - - Size - Tamanho - - - - Origin - Origem - - - - Composer - - - - + All Artists Todos artistas - - + + My Collection Minha biblioteca - - + + Collection of %1 Biblioteca de %1 + + TreeView + + + Sorry, your filter '%1' did not match any results. + + + TwitterConfigWidget @@ -3410,27 +3466,37 @@ Você pode enviar uma outra mensagem de sincronia a qualquer momento simplesment ViewManager - + + After you have scanned your music collection you will find your tracks right here. + + + + + This collection is empty. + + + + SuperCollection - + Combined libraries of all your online friends - + All available albums Todos os álbuns disponíveis - + Recently Played Tracks - + Recently played tracks from all your friends @@ -3453,12 +3519,12 @@ Você pode enviar uma outra mensagem de sincronia a qualquer momento simplesment Faixas reproduzidas recentemente - + No recently created playlists in your network. Nenhuma lista de reprodução criada recentemente na sua rede. - + Welcome to Tomahawk Bem-vindo ao Tomahawk @@ -3466,7 +3532,7 @@ Você pode enviar uma outra mensagem de sincronia a qualquer momento simplesment WhatsHotWidget - + Charts Gráficos @@ -3702,107 +3768,107 @@ Letras de "%1" por %2: XmppSipPlugin - + User Interaction - + Host is unknown - + Item not found Item não encontrado - + Authorization Error - + Remote Stream Error - + Remote Connection failed Conexão Remota falhou - + Internal Server Error - + System shutdown - + Conflict - + Unknown Desconhecido - + No Compression Support - + No Encryption Support - + No Authorization Support - + No Supported Feature - + Add Friend Adicionar Amigo - + Enter Xmpp ID: - + Add Friend... Adicionar Amigo... - + XML Console... - + I'm sorry -- I'm just an automatic presence used by Tomahawk Player (http://gettomahawk.com). If you are getting this message, the person you are trying to reach is probably not signed on, so please try again later! - + Authorize User Autorizar Usuário - + Do you want to grant <b>%1</b> access to your Collection? diff --git a/lang/tomahawk_ru.ts b/lang/tomahawk_ru.ts index 3463de29b..cd6c2a1a8 100644 --- a/lang/tomahawk_ru.ts +++ b/lang/tomahawk_ru.ts @@ -2,17 +2,17 @@ AccountFactoryWrapper - + Dialog Диалог - + Description goes here Описание тут - + Add Account Добавить аккаунт @@ -20,17 +20,17 @@ AccountFactoryWrapperDelegate - + Online В сети - + Connecting... Соединяюсь... - + Offline Не в сети @@ -134,7 +134,17 @@ connect and stream from you? Другие альбомы артиста - + + Sorry, we could not find any other albums for this artist! + + + + + Sorry, we could not find any tracks for this album! + + + + Other Albums by %1 Другие альбомы %1 @@ -142,35 +152,17 @@ connect and stream from you? AlbumModel - - Album - Альбом - - - - + + All albums from %1 Все альбомы %1 - + All albums Все альбомы - - AlbumView - - - After you have scanned your music collection you will find your latest album additions right here. - После сканирования вашей музыкальной коллекции вы найдете свой альбомы тут. - - - - This collection doesn't have any recent albums. - Эта коллекция не имеет последних альбомов. - - ArtistInfoWidget @@ -179,12 +171,12 @@ connect and stream from you? Форма - + Top Hits Хиты - + Related Artists Похожие исполнители @@ -193,23 +185,25 @@ connect and stream from you? Albums Альбомы - - - ArtistView - - After you have scanned your music collection you will find your tracks right here. - После сканирования вашей музыкальной коллекции вы найдете свои песни тут. + + Cover + - - This collection is currently empty. - Коллекция пуста. + + Sorry, we could not find any albums for this artist! + - - Sorry, your filter '%1' did not match any results. - К сожалению, '%1' фильтр не найдено ни одного результата. + + Sorry, we could not find any related artists! + + + + + Sorry, we could not find any top hits for this artist! + @@ -235,57 +229,57 @@ connect and stream from you? Следующая - + Artist Исполнитель - + Album Альбом - + Owner Владелец - + social социальный - + love Любимая - + Time Прошло - + Time Left Осталось - + Shuffle Случаная - + Repeat Повторять - + Low Тише - + High Громче @@ -294,22 +288,25 @@ connect and stream from you? CategoryAddItem - - New Playlist - Новый плейлист + Create new Playlist + - - - - + + Create new Station + + + + + + New Station Новая станция - - - + + + %1 Station %1 Станция @@ -335,27 +332,6 @@ connect and stream from you? Очистить - - CollectionFlatModel - - - My Collection - Моя Коллекция - - - - Collection of %1 - Коллекция %1 - - - - CollectionView - - - This collection is empty. - Коллекция пуста. - - ContextWidget @@ -365,12 +341,12 @@ connect and stream from you? - + Show Footnotes Показать Информацию об Исполнителе - + Hide Footnotes Спрятать Информацию об Исполнителе @@ -384,7 +360,7 @@ connect and stream from you? - <html><head/><body><p><span style=" font-weight:600;">Sorry!</span> Tomahawk crashed. Please tell us about it! Tomahawk has created an error report for you that can help improve the stability in the future. You can now send the this report directly to the Tomahawk developers.</p></body></html> + <html><head/><body><p><span style=" font-weight:600;">Sorry!</span> Tomahawk crashed. Please tell us about it! Tomahawk 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 Tomahawk developers.</p></body></html> @@ -440,17 +416,17 @@ connect and stream from you? DelegateConfigWrapper - + About О - + Delete Account Удалить аккаунт - + About this Account Об этом аккаунте @@ -463,24 +439,11 @@ connect and stream from you? Диагностика - - Update - Обновить - - - + Copy to Clipboard Сохранить в буфер обмена - - DropJob - - - No tracks found for given %1 - Не найдено песен по %1 - - GlobalSearchWidget @@ -505,56 +468,43 @@ connect and stream from you? Информация - + Filter... Фильтр... - - JobStatusView - - - Searching For - Искать - - - - Pending - В ожидании - - - - Idle - Бездействие - - LastFmConfig - + Form Форма - + Scrobble tracks to Last.fm Скроблинг треков Last.fm - + Username: Имя пользователя: - + Password: Пароль: - + Test Login Проверить + + + Import Playback History + + LastfmContext @@ -657,11 +607,80 @@ connect and stream from you? NewReleasesWidget - + New Releases Новые релизы + + PlayableModel + + + Artist + + + + + Title + + + + + Composer + + + + + Album + + + + + Track + + + + + Duration + + + + + Bitrate + + + + + Age + + + + + Year + + + + + Size + + + + + Origin + + + + + Score + + + + + + Name + + + PlaylistItemDelegate @@ -678,17 +697,17 @@ connect and stream from you? PlaylistLargeItemDelegate - + played %1 by you Воспроизводилось %1 вами - + played %1 by %2 Воспроизводилось %1 %2 - + added %1 Добавлено %1 @@ -696,12 +715,12 @@ connect and stream from you? PlaylistModel - + A playlist by %1, created %2 Плейлист %1 создан %2 - + you Вы @@ -757,7 +776,12 @@ connect and stream from you? PlaylistView - + + This playlist is currently empty. + + + + This playlist is currently empty. Add some tracks to it and enjoy the music! Этот плейлист пустой. Добавьте какие-нибудь треки и наслаждайтесь музыкой! @@ -825,67 +849,67 @@ connect and stream from you? QObject - + %n year(s) ago %n год назад%n года назад%n лет назад - + %n year(s) %n год%n года%n лет - + %n month(s) ago %n месяц назад%n месяца назад%n месяцей назад - + %n month(s) %n месяц%n месяца%n месяцей - + %n week(s) ago %n неделю назад%n недели назад%n недель назад - + %n week(s) %n неделю%n недели%n недель - + %n day(s) ago %n день назад%n дня назад%n дней назад - + %n day(s) %n день%n дня%n дней - + %n hour(s) ago %n час назад%n часа назад%n часов назад - + %n hour(s) %n час%n часа%n часов - + %1 minutes ago %1 минут(ы) назад - + %1 minutes %1 минут(ы) - + just now только что @@ -922,20 +946,25 @@ connect and stream from you? - - Show Queue - Показать Очередь + + Open Queue + + + + + Open Queue - %n item(s) + - - Hide Queue - Скрыть Очередь + + Close Queue + RelatedArtistsContext - + Related Artists Похожие исполнители @@ -1058,17 +1087,22 @@ connect and stream from you? TextLabel - - Listening to "%1" by %2 and loving it! %3 + + Tweet - - Listening to "%1" by %2 on "%3" and loving it! %4 + + Listening to "%1" by %2. %3 - + + Listening to "%1" by %2 on "%3". %4 + + + + %1 characters left %1 символов осталось @@ -1101,29 +1135,19 @@ connect and stream from you? Топ 10 - - Offline - Не в сети - - - + All available tracks Доступные песни - - Online - В сети - - - - + + Show Показать - - + + Hide Спрятать @@ -1146,17 +1170,17 @@ connect and stream from you? Последние проигрыные песни - + New Additions Последние добавленые - + My recent activity Моя последняя активность - + Recent activity from %1 Последняя активно %1 @@ -1164,81 +1188,138 @@ connect and stream from you? SourceItem - + Collection Коллекция - - + + Latest Additions Последние добавленные - + Recently Played Последние воспроизводимые - + Loved Tracks Любимые песни - + SuperCollection Общая коллекция - + + Sorry, we could not find any loved tracks! + + + + Latest additions to your collection - + Latest additions to %1's collection - + + Sorry, we could not find any recent additions! + + + + Recently Played Tracks - + Your recently played tracks - + %1's recently played tracks + + + Sorry, we could not find any recent plays! + + SourceTreeView - + &Copy Link &Скопировать Cсылку - + &Delete %1 &Удалить %1 - + + Add to my Playlists + + + + + Add to my Automatic Playlists + + + + + Add to my Stations + + + + &Export Playlist &Экспорт Плейлиста - + + playlist + + + + + automatic playlist + + + + + station + + + + + Delete %1? + playlist/station/... + + + + + Would you like to delete the %1 <b>"%2"</b>? + e.g. Would you like to delete the playlist named Foobar? + + + + Save XSPF Сохранить XSPF - + Playlists (*.xspf) Плейлисты (*.xspf) @@ -1271,52 +1352,52 @@ connect and stream from you? Станция - + Browse Просмотреть - + Search History История поиска - + My Music Моя музыка - + SuperCollection Общая коллекция - + Top Loved Tracks Топ любимых песен - + Dashboard Панель - + Recently Played Последние воспроизводимые - + Charts Чарты - + New Releases Новые релизы - + Friends Друзья @@ -1324,52 +1405,52 @@ connect and stream from you? SpotifyConfig - + Form Форма - + Configure your Spotify account Настроить аккаунт Spotify - + Username or Facebook Email Имя пользователя или Facebook Email - + Log In Войти - + Right click on any Tomahawk playlist to sync it to Spotify. - + High Quality Streams Поток высокого качества - + Spotify playlists to keep in sync: Синхронизировать плейлисты Spotify: - + Delete Tomahawk playlist when removing synchronization - + Username: Имя пользователя: - + Password: Пароль: @@ -1377,12 +1458,12 @@ connect and stream from you? SpotifyPlaylistUpdater - + Delete in Spotify? Удалить в Spotify? - + Would you like to delete the corresponding Spotify playlist as well? @@ -1516,32 +1597,32 @@ connect and stream from you? Tomahawk::Accounts::AccountDelegate - + Add Account Добавить аккаунт - - Remove Account - Удалить аккаунт + + Remove + - + %1 downloads %1 загружено - + Online В сети - + Connecting... Соединяюсь... - + Offline Не в сети @@ -1549,13 +1630,13 @@ connect and stream from you? Tomahawk::Accounts::AccountModel - + Manual Install Required - - Unfortunately, automatic installation of this resolver is not yet available on Linux.<br /><br />Please use "Install from file" above, by fetching it from your distribution or compiling it yourself. Further instructions can be found here:<br /><br />http://www.tomahawk-player.org/resolvers/%1 + + Unfortunately, automatic installation of this resolver is not available or disabled for your platform.<br /><br />Please use "Install from file" above, by fetching it from your distribution or compiling it yourself. Further instructions can be found here:<br /><br />http://www.tomahawk-player.org/resolvers/%1 @@ -1606,7 +1687,7 @@ connect and stream from you? Tomahawk::Accounts::LastFmAccountFactory - + Scrobble your tracks to last.fm, and find freely downloadable tracks to play @@ -1614,23 +1695,49 @@ connect and stream from you? Tomahawk::Accounts::LastFmConfig - + + Testing... + + + + Test Login - - + + Importing %1 + e.g. Importing 2012/01/01 + + + + + Importing History... + + + + + History Incomplete. Resume + + + + + Playback History Imported + + + + + Failed Неудача - + Success Успех - + Could not contact server Не удается связаться с сервером @@ -1638,12 +1745,17 @@ connect and stream from you? Tomahawk::Accounts::SpotifyAccount - + Sync with Spotify Синхронизировать с Spotify - + + Re-enable syncing with Spotify + + + + Stop syncing with Spotify Прекратить синхронизацию с Spotify @@ -1651,22 +1763,22 @@ connect and stream from you? Tomahawk::Accounts::SpotifyAccountConfig - + Logging in... Вхожу... - + Logged in! Вход выполнен! - + Failed: %1 Ошибка: %1 - + Log In Войти @@ -1674,7 +1786,7 @@ connect and stream from you? Tomahawk::Accounts::SpotifyAccountFactory - + Play music from and sync your playlists with Spotify Premium @@ -1827,7 +1939,7 @@ You may wish to try re-authenticating. Tomahawk::Accounts::ZeroconfFactory - + Automatically connect to Tomahawks on the local network Автоматическое подключение к Tomahawks в локальной сети @@ -1841,29 +1953,29 @@ You may wish to try re-authenticating. - - + + Add to &Queue Добавить В &Очередь - + &Love &Любимая - + &Copy Track Link &Скопировать Ссылку Песни - + Un-&Love &Не Любимая - + &Delete Items &Удалить Песни @@ -1878,22 +1990,22 @@ You may wish to try re-authenticating. &Остановить воспроизведения и после этого трека - + &Show Track Page - + &Delete Item &Удалить Песню - + &Show Album Page - + &Show Artist Page @@ -1934,12 +2046,32 @@ You may wish to try re-authenticating. Tomahawk::DropJobNotifier - + + playlist + + + + + artist + + + + + track + + + + + album + + + + Fetching %1 from database Выборка %1 из базы данных - + Parsing %1 %2 Анализирую %1 %2 @@ -1986,17 +2118,17 @@ Please change the filters or try again. Tomahawk::DynamicView - + Add some filters above to seed this station! Добавить некоторые фильтры, чтобы увидеть эту станцию​​! - + Press Generate to get started! Нажмите кнопку Создать, чтобы начать! - + Add some filters above, and press Generate to get started! Добавьте несколько фильтров выше, а затем нажмите Создать, чтобы начать! @@ -2004,7 +2136,7 @@ Please change the filters or try again. Tomahawk::DynamicWidget - + Station ran out of tracks! Try tweaking the filters for a new set of songs to play. @@ -2321,92 +2453,92 @@ Try tweaking the filters for a new set of songs to play. Управляй этой станции: - + Much less Гораздо меньше - + Less Менее - + A bit less Чуть меньше - + Keep at current Имейтся в текущих - + A bit more Немного более - + More Более - + Much more Гораздо больше - + Tempo Ритм - + Loudness - + Danceability - + Energy Мощность - + Song Hotttnesss - + Artist Hotttnesss - + Artist Familiarity - + By Description По описанию - + Enter a description Введите описание - + Apply steering command - + Reset all steering commands @@ -2422,22 +2554,22 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::InfoSystem::ChartsPlugin - + Top Overall - + Artists Исполнители - + Albums Альбомы - + Tracks Песни @@ -2458,27 +2590,27 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::InfoSystem::LastFmInfoPlugin - + Top Tracks - + Loved Tracks - + Hyped Tracks - + Top Artists - + Hyped Artists @@ -2486,7 +2618,7 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::InfoSystem::NewReleasesPlugin - + Albums Альбом @@ -2494,7 +2626,7 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::InfoSystem::TwitterInfoPlugin - + Listening to "%1" by %2 and loving it! %3 @@ -2552,37 +2684,37 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::Query - + and и - + You Ты - + you ты - + and и - + %n other(s) - + %1 people %1 человек - + loved this track любимый @@ -2598,7 +2730,7 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::ShortenedLinkParser - + Network error parsing shortened link! @@ -2606,36 +2738,46 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::Source - - + + Scanning (%L1 tracks) Сканирование (%L1 песни) - + Scanning Сканирую - + Checking Проверяю - + Fetching Выбираю - + Parsing Анализирую - + Saving (%1%) Сохраняю (%1%) + + + Online + + + + + Offline + + Tomahawk::SpotifyParser @@ -2656,7 +2798,7 @@ Try tweaking the filters for a new set of songs to play. TomahawkApp - + My Collection Моя коллекция @@ -2678,39 +2820,48 @@ enter the displayed PIN number here: TomahawkTrayIcon - - + &Stop Playback after current Track &Остановить после текущего трека - - + + Hide Tomahawk Window Спрятать окно Tomahawk - + Show Tomahawk Window Показать окно Tomahawk - + Currently not playing. Не воспроизводится. - + Play Играть - + Pause Пауза - + + &Love + + + + + Un-&Love + + + + &Continue Playback after current Track &Продолжить воспроизведение после текущего трека @@ -2854,7 +3005,7 @@ enter the displayed PIN number here: - + Play Играть @@ -2874,162 +3025,172 @@ enter the displayed PIN number here: Следующая - + Back - + Go back one page - + Forward - + Go forward one page - + Global Search... Глобальный поиск - - + + Check For Updates... Проверить обновления... - - - + + + Connect To Peer Связаться с Peer - + Enter peer address: Введите адрес узла: - + Enter peer port: Введите адрес порта: - + Enter peer key: Введите адрес ключа: - + XSPF Error Ошибка XSPF - + This is not a valid XSPF playlist. Это не является допустимым XSPF плейлистом. - + Failed to save tracks Не удалось сохранить песни - + Some tracks in the playlist do not contain an artist and a title. They will be ignored. Некоторые треки в плейлисте не содержат исполнителя и название. Они будут проигнорированы. - + Sorry, there is a problem accessing your audio device or the desired track, current track will be skipped. Make sure you have a suitable Phonon backend and required plugins installed. - + Sorry, there is a problem accessing your audio device or the desired track, current track will be skipped. - + + Station + + + + Create New Station Создать новую станцию - + Name: Имя: - - New Station - Новая станция + + Playlist + - - New Playlist - Новый плейлист + + Automatic Playlist + - + Pause Пауза - + Go &offline Отключиться - + Go &online Подлючиться - + Authentication Error Ошибка авторизации - + Error connecting to SIP: Authentication failed! - + %1 by %2 track, artist name - + %1 - %2 current track, some window title - + <h2><b>Tomahawk %1<br/>(%2)</h2> <h2><b>Tomahawk %1<br/>(%2)</h2> - + <h2><b>Tomahawk %1</h2> <h2><b>Tomahawk %1</h2> - - Copyright 2010 - 2012<br/>Christian Muehlhaeuser &lt;muesli@tomahawk-player.org&gt;<br/><br/>Thanks to: Leo Franchi, Jeff Mitchell, Dominik Schmidt, Jason Herskowitz, Alejandro Wainzinger, Hugo Lindstr&ouml;m, Michael Zanetti, Harald Sitter and Steve Robertson - Copyright 2010 - 2012<br/>Christian Muehlhaeuser &lt;muesli@tomahawk-player.org&gt;<br/><br/>Thanks to: Leo Franchi, Jeff Mitchell, Dominik Schmidt, Jason Herskowitz, Alejandro Wainzinger, Hugo Lindstr&ouml;m, Michael Zanetti, Harald Sitter and Steve Robertson + + Copyright 2010 - 2012 + - + + Thanks to: + + + + About Tomahawk О Tomahawk @@ -3100,7 +3261,7 @@ enter the displayed PIN number here: TopTracksContext - + Top Hits Хиты @@ -3113,143 +3274,70 @@ enter the displayed PIN number here: - + Cover - + Track - - by - - - - + Artist - - from - - - - + Album - + Statistics - - Lyrics - - - - + Similar Tracks + + + Sorry, but we could not find similar tracks for this song! + + - + You've listened to this track %n time(s). - + You've never listened to this track before. - + You first listened to it on %1. - + You've listened to %1 %n time(s). - + You've never listened to %1 before. - - TrackModel - - - Artist - Исполнитель - - - - Title - Название - - - - Album - Альбом - - - - Track - Песня - - - - Duration - Длительность - - - - Bitrate - Битрей - - - - Age - Возраст - - - - Year - Год - - - - Size - Размер - - - - Origin - Расположение - - - - Score - Проиграно - - - - Composer - Композитор - - TrackView - + Sorry, your filter '%1' did not match any results. Ваш поиск '%1' недал результатов. @@ -3278,63 +3366,31 @@ enter the displayed PIN number here: TreeModel - - Name - Имя - - - - Duration - Длительность - - - - Bitrate - Битрей - - - - Age - Возраст - - - - Year - Год - - - - Size - Размер - - - - Origin - Расположение - - - - Composer - Композитор - - - + All Artists Все исполнители - - + + My Collection Моя коллекция - - + + Collection of %1 Коллекция из %1 + + TreeView + + + Sorry, your filter '%1' did not match any results. + + + TwitterConfigWidget @@ -3410,27 +3466,37 @@ You can re-send a sync message at any time simply by sending another tweet using ViewManager - + + After you have scanned your music collection you will find your tracks right here. + + + + + This collection is empty. + + + + SuperCollection Общая коллекция - + Combined libraries of all your online friends Комбинированные библиотек всех ваших друзей онлайн - + All available albums Доступные альбомы - + Recently Played Tracks - + Recently played tracks from all your friends @@ -3453,12 +3519,12 @@ You can re-send a sync message at any time simply by sending another tweet using Последние Воспроизводимые Песни - + No recently created playlists in your network. Нет списков, созданных в последнее время в вашей сети. - + Welcome to Tomahawk Добро пожаловать в Tomahawk @@ -3466,7 +3532,7 @@ You can re-send a sync message at any time simply by sending another tweet using WhatsHotWidget - + Charts Чарты @@ -3701,107 +3767,107 @@ Lyrics for "%1" by %2: XmppSipPlugin - + User Interaction Взаимодействие с пользователем - + Host is unknown Неизвестный хост - + Item not found Песня не найдена - + Authorization Error Ошибка авторизации - + Remote Stream Error Удаленный поток ошибок - + Remote Connection failed Ошибка подключения - + Internal Server Error Внутренняя ошибка сервера - + System shutdown Выключение системы - + Conflict Конфликт - + Unknown Неизвестный - + No Compression Support Нет поддержки сжатия - + No Encryption Support Нет поддержки шифрования - + No Authorization Support Нет поддержки авторизации - + No Supported Feature Не поддерживаемые функции - + Add Friend Добавить друга - + Enter Xmpp ID: Введите XMPP ID: - + Add Friend... Добавить друга... - + XML Console... XML Console... - + I'm sorry -- I'm just an automatic presence used by Tomahawk Player (http://gettomahawk.com). If you are getting this message, the person you are trying to reach is probably not signed on, so please try again later! - + Authorize User Авторизация пользователя - + Do you want to grant <b>%1</b> access to your Collection? diff --git a/lang/tomahawk_sv.ts b/lang/tomahawk_sv.ts index afa6f9f9c..ee7e0cdf0 100644 --- a/lang/tomahawk_sv.ts +++ b/lang/tomahawk_sv.ts @@ -2,17 +2,17 @@ AccountFactoryWrapper - + Dialog Dialog - + Description goes here Beskrivning här - + Add Account Lägg till konto @@ -20,17 +20,17 @@ AccountFactoryWrapperDelegate - + Online Online - + Connecting... Ansluter... - + Offline Offline @@ -133,7 +133,17 @@ connect and stream from you? Andra album av artisten - + + Sorry, we could not find any other albums for this artist! + + + + + Sorry, we could not find any tracks for this album! + + + + Other Albums by %1 Andra album av %1 @@ -141,35 +151,17 @@ connect and stream from you? AlbumModel - - Album - Album - - - - + + All albums from %1 Alla album från %1 - + All albums Alla album - - AlbumView - - - After you have scanned your music collection you will find your latest album additions right here. - Efter att du har scannat din musiksamling kommer du finna dina senaste tillagda album här. - - - - This collection doesn't have any recent albums. - Den här samlingen inga nya album. - - ArtistInfoWidget @@ -178,12 +170,12 @@ connect and stream from you? Formulär - + Top Hits Största hits - + Related Artists Relaterade artister @@ -192,23 +184,25 @@ connect and stream from you? Albums Album - - - ArtistView - - After you have scanned your music collection you will find your tracks right here. - Efter att du har scannat din musiksamling kommer du finna dina senaste tillagda låtar här. + + Cover + - - This collection is currently empty. - Denna samling är tom. + + Sorry, we could not find any albums for this artist! + - - Sorry, your filter '%1' did not match any results. - Tyvärr, ditt filter "%1" matchade inte några resultat. + + Sorry, we could not find any related artists! + + + + + Sorry, we could not find any top hits for this artist! + @@ -234,57 +228,57 @@ connect and stream from you? Nästa - + Artist Artist - + Album Album - + Owner Ägare - + social - + love älska - + Time Tid - + Time Left Tid kvar - + Shuffle Blanda - + Repeat Upprepa - + Low Låg - + High Hög @@ -293,22 +287,25 @@ connect and stream from you? CategoryAddItem - - New Playlist - Ny spellista + Create new Playlist + - - - - + + Create new Station + + + + + + New Station Ny station - - - + + + %1 Station %1 station @@ -334,27 +331,6 @@ connect and stream from you? Töm - - CollectionFlatModel - - - My Collection - Min samling - - - - Collection of %1 - Samling av %1 - - - - CollectionView - - - This collection is empty. - Denna samling är tom. - - ContextWidget @@ -364,12 +340,12 @@ connect and stream from you? - + Show Footnotes Visa fotnot - + Hide Footnotes Dölj fotnot @@ -383,7 +359,7 @@ connect and stream from you? - <html><head/><body><p><span style=" font-weight:600;">Sorry!</span> Tomahawk crashed. Please tell us about it! Tomahawk has created an error report for you that can help improve the stability in the future. You can now send the this report directly to the Tomahawk developers.</p></body></html> + <html><head/><body><p><span style=" font-weight:600;">Sorry!</span> Tomahawk crashed. Please tell us about it! Tomahawk 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 Tomahawk developers.</p></body></html> @@ -439,17 +415,17 @@ connect and stream from you? DelegateConfigWrapper - + About - + Delete Account Ta bort konto - + About this Account @@ -462,24 +438,11 @@ connect and stream from you? Diagnostik för Tomahawk - - Update - Uppdatera - - - + Copy to Clipboard Kopiera till urklipp - - DropJob - - - No tracks found for given %1 - Inga låtar hittades för %1 - - GlobalSearchWidget @@ -504,56 +467,43 @@ connect and stream from you? Inforad - + Filter... Filter... - - JobStatusView - - - Searching For - Söker efter - - - - Pending - Väntar - - - - Idle - Overksam - - LastFmConfig - + Form Formulär - + Scrobble tracks to Last.fm Scrobbla låtar till Last.fm - + Username: Användarnamn: - + Password: Lösenord: - + Test Login Testinloggning + + + Import Playback History + + LastfmContext @@ -656,11 +606,80 @@ connect and stream from you? NewReleasesWidget - + New Releases + + PlayableModel + + + Artist + + + + + Title + + + + + Composer + + + + + Album + + + + + Track + + + + + Duration + + + + + Bitrate + + + + + Age + + + + + Year + + + + + Size + + + + + Origin + + + + + Score + + + + + + Name + + + PlaylistItemDelegate @@ -677,17 +696,17 @@ connect and stream from you? PlaylistLargeItemDelegate - + played %1 by you %1 spelades av dig - + played %1 by %2 %1 spelades av %2 - + added %1 %1 tillagd @@ -695,12 +714,12 @@ connect and stream from you? PlaylistModel - + A playlist by %1, created %2 En spellista av %1, skapad %2 - + you dig @@ -756,7 +775,12 @@ connect and stream from you? PlaylistView - + + This playlist is currently empty. + + + + This playlist is currently empty. Add some tracks to it and enjoy the music! Denna spellista är för närvarande tom. Lägg till några spår och njut av musiken! @@ -824,67 +848,67 @@ connect and stream from you? QObject - + %n year(s) ago %n år sedan%n år sedan - + %n year(s) %n år sedan%n år sedan - + %n month(s) ago %n månad sedan%n månader sedan - + %n month(s) %n månad%n månader - + %n week(s) ago %n vecka sedan%n veckor sedan - + %n week(s) %n vecka%n veckor - + %n day(s) ago %n dag sedan%n dagar sedan - + %n day(s) %n dag%n dagar - + %n hour(s) ago %n timme sedan%n timmar sedan - + %n hour(s) %n timme%n timmar - + %1 minutes ago %1 minuter sedan - + %1 minutes %1 minuter - + just now precis nyss @@ -921,20 +945,25 @@ connect and stream from you? - - Show Queue - Visa kö + + Open Queue + + + + + Open Queue - %n item(s) + - - Hide Queue - Dölj kö + + Close Queue + RelatedArtistsContext - + Related Artists Relaterade artister @@ -1057,17 +1086,22 @@ connect and stream from you? - - Listening to "%1" by %2 and loving it! %3 + + Tweet - - Listening to "%1" by %2 on "%3" and loving it! %4 + + Listening to "%1" by %2. %3 - + + Listening to "%1" by %2 on "%3". %4 + + + + %1 characters left @@ -1100,29 +1134,19 @@ connect and stream from you? Topp 10 - - Offline - Frånkopplad - - - + All available tracks Alla tillgängliga spår - - Online - Ansluten - - - - + + Show Visa - - + + Hide Göm @@ -1145,17 +1169,17 @@ connect and stream from you? Senaste spelade spår - + New Additions Nya tillägg - + My recent activity Min senaste aktivitet - + Recent activity from %1 Senaste aktivitet från %1 @@ -1163,81 +1187,138 @@ connect and stream from you? SourceItem - + Collection Samling - - + + Latest Additions Senast tillagda - + Recently Played Senast spelade spår - + Loved Tracks Älskade låtar - + SuperCollection SuperCollection - + + Sorry, we could not find any loved tracks! + + + + Latest additions to your collection - + Latest additions to %1's collection - + + Sorry, we could not find any recent additions! + + + + Recently Played Tracks - + Your recently played tracks - + %1's recently played tracks + + + Sorry, we could not find any recent plays! + + SourceTreeView - + &Copy Link &Kopiera länk - + &Delete %1 &Ta bort %1 - + + Add to my Playlists + + + + + Add to my Automatic Playlists + + + + + Add to my Stations + + + + &Export Playlist &Exportera spellista - + + playlist + + + + + automatic playlist + + + + + station + + + + + Delete %1? + playlist/station/... + + + + + Would you like to delete the %1 <b>"%2"</b>? + e.g. Would you like to delete the playlist named Foobar? + + + + Save XSPF Spara XSPF - + Playlists (*.xspf) Spellistor (*.xspf) @@ -1270,52 +1351,52 @@ connect and stream from you? Station - + Browse Bläddra - + Search History Sökhistorik - + My Music Min Musik - + SuperCollection SuperCollection - + Top Loved Tracks Mest älskade spår - + Dashboard - + Recently Played - + Charts - + New Releases - + Friends @@ -1323,52 +1404,52 @@ connect and stream from you? SpotifyConfig - + Form - + Configure your Spotify account - + Username or Facebook Email - + Log In - + Right click on any Tomahawk playlist to sync it to Spotify. - + High Quality Streams - + Spotify playlists to keep in sync: - + Delete Tomahawk playlist when removing synchronization - + Username: - + Password: @@ -1376,12 +1457,12 @@ connect and stream from you? SpotifyPlaylistUpdater - + Delete in Spotify? - + Would you like to delete the corresponding Spotify playlist as well? @@ -1515,32 +1596,32 @@ connect and stream from you? Tomahawk::Accounts::AccountDelegate - + Add Account - - Remove Account + + Remove - + %1 downloads - + Online - + Connecting... - + Offline @@ -1548,13 +1629,13 @@ connect and stream from you? Tomahawk::Accounts::AccountModel - + Manual Install Required - - Unfortunately, automatic installation of this resolver is not yet available on Linux.<br /><br />Please use "Install from file" above, by fetching it from your distribution or compiling it yourself. Further instructions can be found here:<br /><br />http://www.tomahawk-player.org/resolvers/%1 + + Unfortunately, automatic installation of this resolver is not available or disabled for your platform.<br /><br />Please use "Install from file" above, by fetching it from your distribution or compiling it yourself. Further instructions can be found here:<br /><br />http://www.tomahawk-player.org/resolvers/%1 @@ -1605,7 +1686,7 @@ connect and stream from you? Tomahawk::Accounts::LastFmAccountFactory - + Scrobble your tracks to last.fm, and find freely downloadable tracks to play @@ -1613,23 +1694,49 @@ connect and stream from you? Tomahawk::Accounts::LastFmConfig - + + Testing... + + + + Test Login - - + + Importing %1 + e.g. Importing 2012/01/01 + + + + + Importing History... + + + + + History Incomplete. Resume + + + + + Playback History Imported + + + + + Failed - + Success - + Could not contact server @@ -1637,12 +1744,17 @@ connect and stream from you? Tomahawk::Accounts::SpotifyAccount - + Sync with Spotify - + + Re-enable syncing with Spotify + + + + Stop syncing with Spotify @@ -1650,22 +1762,22 @@ connect and stream from you? Tomahawk::Accounts::SpotifyAccountConfig - + Logging in... - + Logged in! - + Failed: %1 - + Log In @@ -1673,7 +1785,7 @@ connect and stream from you? Tomahawk::Accounts::SpotifyAccountFactory - + Play music from and sync your playlists with Spotify Premium @@ -1823,7 +1935,7 @@ You may wish to try re-authenticating. Tomahawk::Accounts::ZeroconfFactory - + Automatically connect to Tomahawks on the local network @@ -1837,29 +1949,29 @@ You may wish to try re-authenticating. - - + + Add to &Queue Lägg till i &kö - + &Love - + &Copy Track Link - + Un-&Love - + &Delete Items &Ta bort objekt @@ -1874,22 +1986,22 @@ You may wish to try re-authenticating. - + &Show Track Page - + &Delete Item &Ta bort objekt - + &Show Album Page - + &Show Artist Page @@ -1930,12 +2042,32 @@ You may wish to try re-authenticating. Tomahawk::DropJobNotifier - + + playlist + + + + + artist + + + + + track + + + + + album + + + + Fetching %1 from database Hämtar %1 från databasen - + Parsing %1 %2 Tolkar %1 %2 @@ -1980,17 +2112,17 @@ Please change the filters or try again. Tomahawk::DynamicView - + Add some filters above to seed this station! - + Press Generate to get started! - + Add some filters above, and press Generate to get started! @@ -1998,7 +2130,7 @@ Please change the filters or try again. Tomahawk::DynamicWidget - + Station ran out of tracks! Try tweaking the filters for a new set of songs to play. @@ -2315,92 +2447,92 @@ Try tweaking the filters for a new set of songs to play. - + Much less Mycket mindre - + Less Mindre - + A bit less Lite mindre - + Keep at current - + A bit more Lite mer - + More Mer - + Much more Mycket mer - + Tempo Tempo - + Loudness Loudness - + Danceability - + Energy Energi - + Song Hotttnesss - + Artist Hotttnesss - + Artist Familiarity - + By Description Efter beskrivning - + Enter a description Ange en beskrivning - + Apply steering command - + Reset all steering commands @@ -2416,22 +2548,22 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::InfoSystem::ChartsPlugin - + Top Overall - + Artists Artister - + Albums Album - + Tracks Spår @@ -2452,27 +2584,27 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::InfoSystem::LastFmInfoPlugin - + Top Tracks - + Loved Tracks - + Hyped Tracks - + Top Artists - + Hyped Artists @@ -2480,7 +2612,7 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::InfoSystem::NewReleasesPlugin - + Albums @@ -2488,7 +2620,7 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::InfoSystem::TwitterInfoPlugin - + Listening to "%1" by %2 and loving it! %3 @@ -2546,37 +2678,37 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::Query - + and - + You - + you - + and - + %n other(s) - + %1 people - + loved this track @@ -2592,7 +2724,7 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::ShortenedLinkParser - + Network error parsing shortened link! @@ -2600,36 +2732,46 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::Source - - + + Scanning (%L1 tracks) Söker igenom (%L1 spår) - + Scanning - + Checking Kontrollerar - + Fetching Hämtar - + Parsing Tolkar - + Saving (%1%) Sparar (%1%) + + + Online + + + + + Offline + + Tomahawk::SpotifyParser @@ -2650,7 +2792,7 @@ Try tweaking the filters for a new set of songs to play. TomahawkApp - + My Collection @@ -2672,39 +2814,48 @@ enter the displayed PIN number here: TomahawkTrayIcon - - + &Stop Playback after current Track - - + + Hide Tomahawk Window Dölj Tomahawk-fönstret - + Show Tomahawk Window Visa Tomahawk-fönstret - + Currently not playing. Spelar ingenting för närvarande. - + Play Spela upp - + Pause Paus - + + &Love + + + + + Un-&Love + + + + &Continue Playback after current Track @@ -2848,7 +2999,7 @@ enter the displayed PIN number here: - + Play Spela upp @@ -2868,162 +3019,172 @@ enter the displayed PIN number here: Nästa - + Back - + Go back one page - + Forward - + Go forward one page - + Global Search... Global sökning... - - + + Check For Updates... Leta efter uppdateringar... - - - + + + Connect To Peer Anslut till klient - + Enter peer address: Ange klientadress: - + Enter peer port: Ange klientport: - + Enter peer key: Ange klientnyckel: - + XSPF Error XSPF-fel - + This is not a valid XSPF playlist. Detta är inte en giltig XSPF-spellista. - + Failed to save tracks Misslyckades med att spara spår - + Some tracks in the playlist do not contain an artist and a title. They will be ignored. Några spår i spellistan innehåller inte någon artist och titel. De kommer att ignoreras. - + Sorry, there is a problem accessing your audio device or the desired track, current track will be skipped. Make sure you have a suitable Phonon backend and required plugins installed. - + Sorry, there is a problem accessing your audio device or the desired track, current track will be skipped. - + + Station + + + + Create New Station Skapa ny station - + Name: Namn: - - New Station - Ny station + + Playlist + - - New Playlist - Ny spellista + + Automatic Playlist + - + Pause Paus - + Go &offline Koppla &från - + Go &online A&nslut - + Authentication Error Autentiseringsfel - + Error connecting to SIP: Authentication failed! - + %1 by %2 track, artist name %1 av %2 - + %1 - %2 current track, some window title %1 - %2 - + <h2><b>Tomahawk %1<br/>(%2)</h2> - + <h2><b>Tomahawk %1</h2> - - Copyright 2010 - 2012<br/>Christian Muehlhaeuser &lt;muesli@tomahawk-player.org&gt;<br/><br/>Thanks to: Leo Franchi, Jeff Mitchell, Dominik Schmidt, Jason Herskowitz, Alejandro Wainzinger, Hugo Lindstr&ouml;m, Michael Zanetti, Harald Sitter and Steve Robertson + + Copyright 2010 - 2012 - + + Thanks to: + + + + About Tomahawk @@ -3094,7 +3255,7 @@ enter the displayed PIN number here: TopTracksContext - + Top Hits @@ -3107,143 +3268,70 @@ enter the displayed PIN number here: - + Cover - + Track - - by - - - - + Artist - - from - - - - + Album - + Statistics - - Lyrics - - - - + Similar Tracks + + + Sorry, but we could not find similar tracks for this song! + + - + You've listened to this track %n time(s). - + You've never listened to this track before. - + You first listened to it on %1. - + You've listened to %1 %n time(s). - + You've never listened to %1 before. - - TrackModel - - - Artist - Artist - - - - Title - Titel - - - - Album - Album - - - - Track - Spår - - - - Duration - Speltid - - - - Bitrate - Bitfrekvens - - - - Age - Ålder - - - - Year - År - - - - Size - Storlek - - - - Origin - Källa - - - - Score - Betyg - - - - Composer - - - TrackView - + Sorry, your filter '%1' did not match any results. Entschuldige, dein Filter '%1' erzeugte keine Ergebnisse. @@ -3272,63 +3360,31 @@ enter the displayed PIN number here: TreeModel - - Name - Namn - - - - Duration - Speltid - - - - Bitrate - Bitfrekvens - - - - Age - Ålder - - - - Year - År - - - - Size - Storlek - - - - Origin - Källa - - - - Composer - - - - + All Artists Alla artister - - + + My Collection Min samling - - + + Collection of %1 Samling av %1 + + TreeView + + + Sorry, your filter '%1' did not match any results. + + + TwitterConfigWidget @@ -3400,27 +3456,37 @@ You can re-send a sync message at any time simply by sending another tweet using ViewManager - + + After you have scanned your music collection you will find your tracks right here. + + + + + This collection is empty. + + + + SuperCollection - + Combined libraries of all your online friends - + All available albums Alla tillgängliga album - + Recently Played Tracks - + Recently played tracks from all your friends @@ -3443,12 +3509,12 @@ You can re-send a sync message at any time simply by sending another tweet using Senaste spelade spår - + No recently created playlists in your network. Inga skapade spellistor i ditt nätverk på sistone. - + Welcome to Tomahawk Välkommen till Tomahawk @@ -3456,7 +3522,7 @@ You can re-send a sync message at any time simply by sending another tweet using WhatsHotWidget - + Charts Topplistor @@ -3685,107 +3751,107 @@ Lyrics for "%1" by %2: XmppSipPlugin - + User Interaction - + Host is unknown - + Item not found - + Authorization Error - + Remote Stream Error - + Remote Connection failed - + Internal Server Error - + System shutdown - + Conflict - + Unknown - + No Compression Support - + No Encryption Support - + No Authorization Support - + No Supported Feature - + Add Friend - + Enter Xmpp ID: - + Add Friend... - + XML Console... - + I'm sorry -- I'm just an automatic presence used by Tomahawk Player (http://gettomahawk.com). If you are getting this message, the person you are trying to reach is probably not signed on, so please try again later! - + Authorize User - + Do you want to grant <b>%1</b> access to your Collection? diff --git a/lang/tomahawk_tr.ts b/lang/tomahawk_tr.ts index 944d2855a..fdd98d774 100644 --- a/lang/tomahawk_tr.ts +++ b/lang/tomahawk_tr.ts @@ -2,17 +2,17 @@ AccountFactoryWrapper - + Dialog İletişim Kutusu - + Description goes here Buraya açıklama gelecek - + Add Account Hesap Ekle @@ -20,17 +20,17 @@ AccountFactoryWrapperDelegate - + Online Çevrimiçi - + Connecting... Bağlanıyor... - + Offline Çevrimdışı @@ -133,7 +133,17 @@ connect and stream from you? Sanatçının Diğer Albümleri - + + Sorry, we could not find any other albums for this artist! + + + + + Sorry, we could not find any tracks for this album! + + + + Other Albums by %1 Diğer %1 Albümleri @@ -141,35 +151,17 @@ connect and stream from you? AlbumModel - - Album - Albüm - - - - + + All albums from %1 Bütün %1 albümleri - + All albums Bütün albümler - - AlbumView - - - After you have scanned your music collection you will find your latest album additions right here. - Müzik koleksiyonunuzu taradıktan sonra en son eklenen albümleri burada bulacaksınız. - - - - This collection doesn't have any recent albums. - Bu koleksiyonda en son eklenen bir albüm yok. - - ArtistInfoWidget @@ -178,12 +170,12 @@ connect and stream from you? Form - + Top Hits En Çok Dinlenenler - + Related Artists Benzer Sanatçılar @@ -192,23 +184,25 @@ connect and stream from you? Albums Albümler - - - ArtistView - - After you have scanned your music collection you will find your tracks right here. - Müzik koleksiyonunuzu taradıktan parçalarınız tam burada bulacaksınız. + + Cover + - - This collection is currently empty. - Bu koleksiyon şu anda boş. + + Sorry, we could not find any albums for this artist! + - - Sorry, your filter '%1' did not match any results. - Üzgünüm, '%1' filtresi hiçbir sonuç getirmedi. + + Sorry, we could not find any related artists! + + + + + Sorry, we could not find any top hits for this artist! + @@ -234,57 +228,57 @@ connect and stream from you? Sonraki - + Artist Sanatçı - + Album Albüm - + Owner Sahibi - + social - + love beğen - + Time Süre - + Time Left Kalan Süre - + Shuffle Karışık - + Repeat Yenile - + Low Düşük - + High Yüksek @@ -293,22 +287,25 @@ connect and stream from you? CategoryAddItem - - New Playlist - Yeni Şarkı Listesi + Create new Playlist + - - - - + + Create new Station + + + + + + New Station Yeni İstasyon - - - + + + %1 Station %1 İstasyon @@ -334,27 +331,6 @@ connect and stream from you? Temizle - - CollectionFlatModel - - - My Collection - Koleksiyonum - - - - Collection of %1 - %1 Koleksiyonu - - - - CollectionView - - - This collection is empty. - Bu koleksiyon boş. - - ContextWidget @@ -364,12 +340,12 @@ connect and stream from you? - + Show Footnotes Dipnotları Göster - + Hide Footnotes Dipnotları Gizle @@ -383,7 +359,7 @@ connect and stream from you? - <html><head/><body><p><span style=" font-weight:600;">Sorry!</span> Tomahawk crashed. Please tell us about it! Tomahawk has created an error report for you that can help improve the stability in the future. You can now send the this report directly to the Tomahawk developers.</p></body></html> + <html><head/><body><p><span style=" font-weight:600;">Sorry!</span> Tomahawk crashed. Please tell us about it! Tomahawk 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 Tomahawk developers.</p></body></html> @@ -439,17 +415,17 @@ connect and stream from you? DelegateConfigWrapper - + About - + Delete Account Hesabı Sil - + About this Account @@ -462,24 +438,11 @@ connect and stream from you? Tomahawk Tanılama - - Update - Güncelle - - - + Copy to Clipboard Pano'ya Kopyala - - DropJob - - - No tracks found for given %1 - Verilen %1 için hiç parça bulunamadı. - - GlobalSearchWidget @@ -504,56 +467,43 @@ connect and stream from you? BilgiÇubuğu - + Filter... Filtre... - - JobStatusView - - - Searching For - Şunu Ara: - - - - Pending - Beklemede - - - - Idle - Boşta - - LastFmConfig - + Form Form - + Scrobble tracks to Last.fm Dinlediğim şarkıların bilgisini Last.fm'e gönder. - + Username: Kullanıcı adı: - + Password: Parola: - + Test Login Bilgileri Test Et + + + Import Playback History + + LastfmContext @@ -656,11 +606,80 @@ connect and stream from you? NewReleasesWidget - + New Releases + + PlayableModel + + + Artist + + + + + Title + + + + + Composer + + + + + Album + + + + + Track + + + + + Duration + + + + + Bitrate + + + + + Age + + + + + Year + + + + + Size + + + + + Origin + + + + + Score + + + + + + Name + + + PlaylistItemDelegate @@ -677,17 +696,17 @@ connect and stream from you? PlaylistLargeItemDelegate - + played %1 by you - + played %1 by %2 - + added %1 @@ -695,12 +714,12 @@ connect and stream from you? PlaylistModel - + A playlist by %1, created %2 - + you @@ -756,7 +775,12 @@ connect and stream from you? PlaylistView - + + This playlist is currently empty. + + + + This playlist is currently empty. Add some tracks to it and enjoy the music! @@ -823,67 +847,67 @@ connect and stream from you? QObject - + %n year(s) ago - + %n year(s) - + %n month(s) ago - + %n month(s) - + %n week(s) ago - + %n week(s) - + %n day(s) ago - + %n day(s) - + %n hour(s) ago - + %n hour(s) - + %1 minutes ago - + %1 minutes - + just now @@ -920,20 +944,25 @@ connect and stream from you? - - Show Queue + + Open Queue + + + Open Queue - %n item(s) + + - - Hide Queue + + Close Queue RelatedArtistsContext - + Related Artists @@ -1056,17 +1085,22 @@ connect and stream from you? - - Listening to "%1" by %2 and loving it! %3 + + Tweet - - Listening to "%1" by %2 on "%3" and loving it! %4 + + Listening to "%1" by %2. %3 - + + Listening to "%1" by %2 on "%3". %4 + + + + %1 characters left @@ -1099,29 +1133,19 @@ connect and stream from you? - - Offline - - - - + All available tracks - - Online - - - - - + + Show - - + + Hide @@ -1144,17 +1168,17 @@ connect and stream from you? - + New Additions - + My recent activity - + Recent activity from %1 @@ -1162,81 +1186,138 @@ connect and stream from you? SourceItem - + Collection - - + + Latest Additions - + Recently Played - + Loved Tracks - + SuperCollection - + + Sorry, we could not find any loved tracks! + + + + Latest additions to your collection - + Latest additions to %1's collection - + + Sorry, we could not find any recent additions! + + + + Recently Played Tracks - + Your recently played tracks - + %1's recently played tracks + + + Sorry, we could not find any recent plays! + + SourceTreeView - + &Copy Link - + &Delete %1 - + + Add to my Playlists + + + + + Add to my Automatic Playlists + + + + + Add to my Stations + + + + &Export Playlist - + + playlist + + + + + automatic playlist + + + + + station + + + + + Delete %1? + playlist/station/... + + + + + Would you like to delete the %1 <b>"%2"</b>? + e.g. Would you like to delete the playlist named Foobar? + + + + Save XSPF - + Playlists (*.xspf) @@ -1269,52 +1350,52 @@ connect and stream from you? - + Browse - + Search History - + My Music - + SuperCollection - + Top Loved Tracks - + Dashboard - + Recently Played - + Charts - + New Releases - + Friends @@ -1322,52 +1403,52 @@ connect and stream from you? SpotifyConfig - + Form - + Configure your Spotify account - + Username or Facebook Email - + Log In - + Right click on any Tomahawk playlist to sync it to Spotify. - + High Quality Streams - + Spotify playlists to keep in sync: - + Delete Tomahawk playlist when removing synchronization - + Username: - + Password: @@ -1375,12 +1456,12 @@ connect and stream from you? SpotifyPlaylistUpdater - + Delete in Spotify? - + Would you like to delete the corresponding Spotify playlist as well? @@ -1514,32 +1595,32 @@ connect and stream from you? Tomahawk::Accounts::AccountDelegate - + Add Account - - Remove Account + + Remove - + %1 downloads - + Online - + Connecting... - + Offline @@ -1547,13 +1628,13 @@ connect and stream from you? Tomahawk::Accounts::AccountModel - + Manual Install Required - - Unfortunately, automatic installation of this resolver is not yet available on Linux.<br /><br />Please use "Install from file" above, by fetching it from your distribution or compiling it yourself. Further instructions can be found here:<br /><br />http://www.tomahawk-player.org/resolvers/%1 + + Unfortunately, automatic installation of this resolver is not available or disabled for your platform.<br /><br />Please use "Install from file" above, by fetching it from your distribution or compiling it yourself. Further instructions can be found here:<br /><br />http://www.tomahawk-player.org/resolvers/%1 @@ -1604,7 +1685,7 @@ connect and stream from you? Tomahawk::Accounts::LastFmAccountFactory - + Scrobble your tracks to last.fm, and find freely downloadable tracks to play @@ -1612,23 +1693,49 @@ connect and stream from you? Tomahawk::Accounts::LastFmConfig - + + Testing... + + + + Test Login - - + + Importing %1 + e.g. Importing 2012/01/01 + + + + + Importing History... + + + + + History Incomplete. Resume + + + + + Playback History Imported + + + + + Failed - + Success - + Could not contact server @@ -1636,12 +1743,17 @@ connect and stream from you? Tomahawk::Accounts::SpotifyAccount - + Sync with Spotify - + + Re-enable syncing with Spotify + + + + Stop syncing with Spotify @@ -1649,22 +1761,22 @@ connect and stream from you? Tomahawk::Accounts::SpotifyAccountConfig - + Logging in... - + Logged in! - + Failed: %1 - + Log In @@ -1672,7 +1784,7 @@ connect and stream from you? Tomahawk::Accounts::SpotifyAccountFactory - + Play music from and sync your playlists with Spotify Premium @@ -1822,7 +1934,7 @@ You may wish to try re-authenticating. Tomahawk::Accounts::ZeroconfFactory - + Automatically connect to Tomahawks on the local network @@ -1836,29 +1948,29 @@ You may wish to try re-authenticating. - - + + Add to &Queue - + &Love - + &Copy Track Link - + Un-&Love - + &Delete Items @@ -1873,22 +1985,22 @@ You may wish to try re-authenticating. - + &Show Track Page - + &Delete Item - + &Show Album Page - + &Show Artist Page @@ -1929,12 +2041,32 @@ You may wish to try re-authenticating. Tomahawk::DropJobNotifier - + + playlist + + + + + artist + + + + + track + + + + + album + + + + Fetching %1 from database - + Parsing %1 %2 @@ -1979,17 +2111,17 @@ Please change the filters or try again. Tomahawk::DynamicView - + Add some filters above to seed this station! - + Press Generate to get started! - + Add some filters above, and press Generate to get started! @@ -1997,7 +2129,7 @@ Please change the filters or try again. Tomahawk::DynamicWidget - + Station ran out of tracks! Try tweaking the filters for a new set of songs to play. @@ -2314,92 +2446,92 @@ Try tweaking the filters for a new set of songs to play. - + Much less - + Less - + A bit less - + Keep at current - + A bit more - + More - + Much more - + Tempo - + Loudness - + Danceability - + Energy - + Song Hotttnesss - + Artist Hotttnesss - + Artist Familiarity - + By Description - + Enter a description - + Apply steering command - + Reset all steering commands @@ -2415,22 +2547,22 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::InfoSystem::ChartsPlugin - + Top Overall - + Artists - + Albums - + Tracks @@ -2451,27 +2583,27 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::InfoSystem::LastFmInfoPlugin - + Top Tracks - + Loved Tracks - + Hyped Tracks - + Top Artists - + Hyped Artists @@ -2479,7 +2611,7 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::InfoSystem::NewReleasesPlugin - + Albums @@ -2487,7 +2619,7 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::InfoSystem::TwitterInfoPlugin - + Listening to "%1" by %2 and loving it! %3 @@ -2545,37 +2677,37 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::Query - + and - + You - + you - + and - + %n other(s) - + %1 people - + loved this track @@ -2591,7 +2723,7 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::ShortenedLinkParser - + Network error parsing shortened link! @@ -2599,36 +2731,46 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::Source - - + + Scanning (%L1 tracks) - + Scanning - + Checking - + Fetching - + Parsing - + Saving (%1%) + + + Online + + + + + Offline + + Tomahawk::SpotifyParser @@ -2649,7 +2791,7 @@ Try tweaking the filters for a new set of songs to play. TomahawkApp - + My Collection @@ -2671,39 +2813,48 @@ enter the displayed PIN number here: TomahawkTrayIcon - - + &Stop Playback after current Track - - + + Hide Tomahawk Window - + Show Tomahawk Window - + Currently not playing. - + Play - + Pause - + + &Love + + + + + Un-&Love + + + + &Continue Playback after current Track @@ -2847,7 +2998,7 @@ enter the displayed PIN number here: - + Play @@ -2867,162 +3018,172 @@ enter the displayed PIN number here: - + Back - + Go back one page - + Forward - + Go forward one page - + Global Search... - - + + Check For Updates... - - - + + + Connect To Peer - + Enter peer address: - + Enter peer port: - + Enter peer key: - + XSPF Error - + This is not a valid XSPF playlist. - + Failed to save tracks - + Some tracks in the playlist do not contain an artist and a title. They will be ignored. - + Sorry, there is a problem accessing your audio device or the desired track, current track will be skipped. Make sure you have a suitable Phonon backend and required plugins installed. - + Sorry, there is a problem accessing your audio device or the desired track, current track will be skipped. - + + Station + + + + Create New Station - + Name: - - New Station + + Playlist - - New Playlist + + Automatic Playlist - + Pause - + Go &offline - + Go &online - + Authentication Error - + Error connecting to SIP: Authentication failed! - + %1 by %2 track, artist name - + %1 - %2 current track, some window title - + <h2><b>Tomahawk %1<br/>(%2)</h2> - + <h2><b>Tomahawk %1</h2> - - Copyright 2010 - 2012<br/>Christian Muehlhaeuser &lt;muesli@tomahawk-player.org&gt;<br/><br/>Thanks to: Leo Franchi, Jeff Mitchell, Dominik Schmidt, Jason Herskowitz, Alejandro Wainzinger, Hugo Lindstr&ouml;m, Michael Zanetti, Harald Sitter and Steve Robertson + + Copyright 2010 - 2012 - + + Thanks to: + + + + About Tomahawk @@ -3093,7 +3254,7 @@ enter the displayed PIN number here: TopTracksContext - + Top Hits @@ -3106,143 +3267,70 @@ enter the displayed PIN number here: - + Cover - + Track - - by - - - - + Artist - - from - - - - + Album - + Statistics - - Lyrics - - - - + Similar Tracks + + + Sorry, but we could not find similar tracks for this song! + + - + You've listened to this track %n time(s). - + You've never listened to this track before. - + You first listened to it on %1. - + You've listened to %1 %n time(s). - + You've never listened to %1 before. - - TrackModel - - - Artist - - - - - Title - - - - - Album - - - - - Track - - - - - Duration - - - - - Bitrate - - - - - Age - - - - - Year - - - - - Size - - - - - Origin - - - - - Score - - - - - Composer - - - TrackView - + Sorry, your filter '%1' did not match any results. @@ -3271,63 +3359,31 @@ enter the displayed PIN number here: TreeModel - - Name - - - - - Duration - - - - - Bitrate - - - - - Age - - - - - Year - - - - - Size - - - - - Origin - - - - - Composer - - - - + All Artists - - + + My Collection - - + + Collection of %1 + + TreeView + + + Sorry, your filter '%1' did not match any results. + + + TwitterConfigWidget @@ -3399,27 +3455,37 @@ You can re-send a sync message at any time simply by sending another tweet using ViewManager - + + After you have scanned your music collection you will find your tracks right here. + + + + + This collection is empty. + + + + SuperCollection - + Combined libraries of all your online friends - + All available albums - + Recently Played Tracks - + Recently played tracks from all your friends @@ -3442,12 +3508,12 @@ You can re-send a sync message at any time simply by sending another tweet using - + No recently created playlists in your network. - + Welcome to Tomahawk @@ -3455,7 +3521,7 @@ You can re-send a sync message at any time simply by sending another tweet using WhatsHotWidget - + Charts @@ -3684,107 +3750,107 @@ Lyrics for "%1" by %2: XmppSipPlugin - + User Interaction - + Host is unknown - + Item not found - + Authorization Error - + Remote Stream Error - + Remote Connection failed - + Internal Server Error - + System shutdown - + Conflict - + Unknown - + No Compression Support - + No Encryption Support - + No Authorization Support - + No Supported Feature - + Add Friend - + Enter Xmpp ID: - + Add Friend... - + XML Console... - + I'm sorry -- I'm just an automatic presence used by Tomahawk Player (http://gettomahawk.com). If you are getting this message, the person you are trying to reach is probably not signed on, so please try again later! - + Authorize User - + Do you want to grant <b>%1</b> access to your Collection? diff --git a/lang/tomahawk_zh_CN.ts b/lang/tomahawk_zh_CN.ts index e2c0b64a7..5063130e7 100644 --- a/lang/tomahawk_zh_CN.ts +++ b/lang/tomahawk_zh_CN.ts @@ -2,17 +2,17 @@ AccountFactoryWrapper - + Dialog 对话框 - + Description goes here 注释于此处 - + Add Account 添加帐号 @@ -20,17 +20,17 @@ AccountFactoryWrapperDelegate - + Online 在线 - + Connecting... 连接中... - + Offline 离线 @@ -133,7 +133,17 @@ connect and stream from you? 艺人的其他专辑 - + + Sorry, we could not find any other albums for this artist! + + + + + Sorry, we could not find any tracks for this album! + + + + Other Albums by %1 %1 的其他专辑 @@ -141,35 +151,17 @@ connect and stream from you? AlbumModel - - Album - 专辑 - - - - + + All albums from %1 来自 %1 的所有专辑 - + All albums 所有专辑 - - AlbumView - - - After you have scanned your music collection you will find your latest album additions right here. - - - - - This collection doesn't have any recent albums. - - - ArtistInfoWidget @@ -178,12 +170,12 @@ connect and stream from you? - + Top Hits 最热曲目 - + Related Artists 相关艺人 @@ -192,23 +184,25 @@ connect and stream from you? Albums 专辑 - - - ArtistView - - After you have scanned your music collection you will find your tracks right here. + + Cover - - This collection is currently empty. - 此收藏目前为空 + + Sorry, we could not find any albums for this artist! + - - Sorry, your filter '%1' did not match any results. - 抱歉,你的过滤条件 '%1' 未匹配任何结果 + + Sorry, we could not find any related artists! + + + + + Sorry, we could not find any top hits for this artist! + @@ -234,57 +228,57 @@ connect and stream from you? 下一首 - + Artist 艺人 - + Album 专辑 - + Owner - + social - + love - + Time - + Time Left - + Shuffle 无序播放 - + Repeat 重复播放 - + Low - + High @@ -293,22 +287,25 @@ connect and stream from you? CategoryAddItem - - New Playlist - 新播放列表 + Create new Playlist + - - - - + + Create new Station + + + + + + New Station 新电台 - - - + + + %1 Station %1 电台 @@ -334,27 +331,6 @@ connect and stream from you? - - CollectionFlatModel - - - My Collection - - - - - Collection of %1 - - - - - CollectionView - - - This collection is empty. - - - ContextWidget @@ -364,12 +340,12 @@ connect and stream from you? - + Show Footnotes 显示脚注 - + Hide Footnotes 隐藏脚注 @@ -383,7 +359,7 @@ connect and stream from you? - <html><head/><body><p><span style=" font-weight:600;">Sorry!</span> Tomahawk crashed. Please tell us about it! Tomahawk has created an error report for you that can help improve the stability in the future. You can now send the this report directly to the Tomahawk developers.</p></body></html> + <html><head/><body><p><span style=" font-weight:600;">Sorry!</span> Tomahawk crashed. Please tell us about it! Tomahawk 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 Tomahawk developers.</p></body></html> @@ -439,17 +415,17 @@ connect and stream from you? DelegateConfigWrapper - + About - + Delete Account 删除账户 - + About this Account @@ -462,24 +438,11 @@ connect and stream from you? Tomahawk 诊断信息 - - Update - 更新 - - - + Copy to Clipboard 复制到剪贴板 - - DropJob - - - No tracks found for given %1 - - - GlobalSearchWidget @@ -504,56 +467,43 @@ connect and stream from you? - + Filter... - - JobStatusView - - - Searching For - - - - - Pending - - - - - Idle - - - LastFmConfig - + Form - + Scrobble tracks to Last.fm - + Username: 用户名 - + Password: 密码 - + Test Login 测试登录 + + + Import Playback History + + LastfmContext @@ -656,11 +606,80 @@ connect and stream from you? NewReleasesWidget - + New Releases + + PlayableModel + + + Artist + + + + + Title + + + + + Composer + + + + + Album + + + + + Track + + + + + Duration + + + + + Bitrate + + + + + Age + + + + + Year + + + + + Size + + + + + Origin + + + + + Score + + + + + + Name + + + PlaylistItemDelegate @@ -677,17 +696,17 @@ connect and stream from you? PlaylistLargeItemDelegate - + played %1 by you - + played %1 by %2 - + added %1 @@ -695,12 +714,12 @@ connect and stream from you? PlaylistModel - + A playlist by %1, created %2 - + you @@ -756,7 +775,12 @@ connect and stream from you? PlaylistView - + + This playlist is currently empty. + + + + This playlist is currently empty. Add some tracks to it and enjoy the music! @@ -823,67 +847,67 @@ connect and stream from you? QObject - + %n year(s) ago - + %n year(s) - + %n month(s) ago - + %n month(s) - + %n week(s) ago - + %n week(s) - + %n day(s) ago - + %n day(s) - + %n hour(s) ago - + %n hour(s) - + %1 minutes ago - + %1 minutes - + just now @@ -920,20 +944,25 @@ connect and stream from you? - - Show Queue + + Open Queue + + + Open Queue - %n item(s) + + - - Hide Queue + + Close Queue RelatedArtistsContext - + Related Artists @@ -1056,17 +1085,22 @@ connect and stream from you? - - Listening to "%1" by %2 and loving it! %3 + + Tweet - - Listening to "%1" by %2 on "%3" and loving it! %4 + + Listening to "%1" by %2. %3 - + + Listening to "%1" by %2 on "%3". %4 + + + + %1 characters left @@ -1099,29 +1133,19 @@ connect and stream from you? - - Offline - - - - + All available tracks - - Online - - - - - + + Show - - + + Hide @@ -1144,17 +1168,17 @@ connect and stream from you? - + New Additions - + My recent activity - + Recent activity from %1 @@ -1162,81 +1186,138 @@ connect and stream from you? SourceItem - + Collection - - + + Latest Additions - + Recently Played - + Loved Tracks - + SuperCollection - + + Sorry, we could not find any loved tracks! + + + + Latest additions to your collection - + Latest additions to %1's collection - + + Sorry, we could not find any recent additions! + + + + Recently Played Tracks - + Your recently played tracks - + %1's recently played tracks + + + Sorry, we could not find any recent plays! + + SourceTreeView - + &Copy Link - + &Delete %1 - + + Add to my Playlists + + + + + Add to my Automatic Playlists + + + + + Add to my Stations + + + + &Export Playlist - + + playlist + + + + + automatic playlist + + + + + station + + + + + Delete %1? + playlist/station/... + + + + + Would you like to delete the %1 <b>"%2"</b>? + e.g. Would you like to delete the playlist named Foobar? + + + + Save XSPF - + Playlists (*.xspf) @@ -1269,52 +1350,52 @@ connect and stream from you? - + Browse - + Search History - + My Music - + SuperCollection - + Top Loved Tracks - + Dashboard - + Recently Played - + Charts - + New Releases - + Friends @@ -1322,52 +1403,52 @@ connect and stream from you? SpotifyConfig - + Form - + Configure your Spotify account - + Username or Facebook Email - + Log In - + Right click on any Tomahawk playlist to sync it to Spotify. - + High Quality Streams - + Spotify playlists to keep in sync: - + Delete Tomahawk playlist when removing synchronization - + Username: - + Password: @@ -1375,12 +1456,12 @@ connect and stream from you? SpotifyPlaylistUpdater - + Delete in Spotify? - + Would you like to delete the corresponding Spotify playlist as well? @@ -1514,32 +1595,32 @@ connect and stream from you? Tomahawk::Accounts::AccountDelegate - + Add Account - - Remove Account + + Remove - + %1 downloads - + Online - + Connecting... - + Offline @@ -1547,13 +1628,13 @@ connect and stream from you? Tomahawk::Accounts::AccountModel - + Manual Install Required - - Unfortunately, automatic installation of this resolver is not yet available on Linux.<br /><br />Please use "Install from file" above, by fetching it from your distribution or compiling it yourself. Further instructions can be found here:<br /><br />http://www.tomahawk-player.org/resolvers/%1 + + Unfortunately, automatic installation of this resolver is not available or disabled for your platform.<br /><br />Please use "Install from file" above, by fetching it from your distribution or compiling it yourself. Further instructions can be found here:<br /><br />http://www.tomahawk-player.org/resolvers/%1 @@ -1604,7 +1685,7 @@ connect and stream from you? Tomahawk::Accounts::LastFmAccountFactory - + Scrobble your tracks to last.fm, and find freely downloadable tracks to play @@ -1612,23 +1693,49 @@ connect and stream from you? Tomahawk::Accounts::LastFmConfig - + + Testing... + + + + Test Login - - + + Importing %1 + e.g. Importing 2012/01/01 + + + + + Importing History... + + + + + History Incomplete. Resume + + + + + Playback History Imported + + + + + Failed - + Success - + Could not contact server @@ -1636,12 +1743,17 @@ connect and stream from you? Tomahawk::Accounts::SpotifyAccount - + Sync with Spotify - + + Re-enable syncing with Spotify + + + + Stop syncing with Spotify @@ -1649,22 +1761,22 @@ connect and stream from you? Tomahawk::Accounts::SpotifyAccountConfig - + Logging in... - + Logged in! - + Failed: %1 - + Log In @@ -1672,7 +1784,7 @@ connect and stream from you? Tomahawk::Accounts::SpotifyAccountFactory - + Play music from and sync your playlists with Spotify Premium @@ -1822,7 +1934,7 @@ You may wish to try re-authenticating. Tomahawk::Accounts::ZeroconfFactory - + Automatically connect to Tomahawks on the local network @@ -1836,29 +1948,29 @@ You may wish to try re-authenticating. - - + + Add to &Queue - + &Love - + &Copy Track Link - + Un-&Love - + &Delete Items @@ -1873,22 +1985,22 @@ You may wish to try re-authenticating. - + &Show Track Page - + &Delete Item - + &Show Album Page - + &Show Artist Page @@ -1929,12 +2041,32 @@ You may wish to try re-authenticating. Tomahawk::DropJobNotifier - + + playlist + + + + + artist + + + + + track + + + + + album + + + + Fetching %1 from database - + Parsing %1 %2 @@ -1979,17 +2111,17 @@ Please change the filters or try again. Tomahawk::DynamicView - + Add some filters above to seed this station! - + Press Generate to get started! - + Add some filters above, and press Generate to get started! @@ -1997,7 +2129,7 @@ Please change the filters or try again. Tomahawk::DynamicWidget - + Station ran out of tracks! Try tweaking the filters for a new set of songs to play. @@ -2314,92 +2446,92 @@ Try tweaking the filters for a new set of songs to play. - + Much less - + Less - + A bit less - + Keep at current - + A bit more - + More - + Much more - + Tempo - + Loudness - + Danceability - + Energy - + Song Hotttnesss - + Artist Hotttnesss - + Artist Familiarity - + By Description - + Enter a description - + Apply steering command - + Reset all steering commands @@ -2415,22 +2547,22 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::InfoSystem::ChartsPlugin - + Top Overall - + Artists - + Albums - + Tracks @@ -2451,27 +2583,27 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::InfoSystem::LastFmInfoPlugin - + Top Tracks - + Loved Tracks - + Hyped Tracks - + Top Artists - + Hyped Artists @@ -2479,7 +2611,7 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::InfoSystem::NewReleasesPlugin - + Albums @@ -2487,7 +2619,7 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::InfoSystem::TwitterInfoPlugin - + Listening to "%1" by %2 and loving it! %3 @@ -2545,37 +2677,37 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::Query - + and - + You - + you - + and - + %n other(s) - + %1 people - + loved this track @@ -2591,7 +2723,7 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::ShortenedLinkParser - + Network error parsing shortened link! @@ -2599,36 +2731,46 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::Source - - + + Scanning (%L1 tracks) - + Scanning - + Checking - + Fetching - + Parsing - + Saving (%1%) + + + Online + + + + + Offline + + Tomahawk::SpotifyParser @@ -2649,7 +2791,7 @@ Try tweaking the filters for a new set of songs to play. TomahawkApp - + My Collection @@ -2671,39 +2813,48 @@ enter the displayed PIN number here: TomahawkTrayIcon - - + &Stop Playback after current Track - - + + Hide Tomahawk Window - + Show Tomahawk Window - + Currently not playing. - + Play - + Pause - + + &Love + + + + + Un-&Love + + + + &Continue Playback after current Track @@ -2847,7 +2998,7 @@ enter the displayed PIN number here: - + Play @@ -2867,162 +3018,172 @@ enter the displayed PIN number here: - + Back - + Go back one page - + Forward - + Go forward one page - + Global Search... - - + + Check For Updates... - - - + + + Connect To Peer - + Enter peer address: - + Enter peer port: - + Enter peer key: - + XSPF Error - + This is not a valid XSPF playlist. - + Failed to save tracks - + Some tracks in the playlist do not contain an artist and a title. They will be ignored. - + Sorry, there is a problem accessing your audio device or the desired track, current track will be skipped. Make sure you have a suitable Phonon backend and required plugins installed. - + Sorry, there is a problem accessing your audio device or the desired track, current track will be skipped. - + + Station + + + + Create New Station - + Name: - - New Station + + Playlist - - New Playlist + + Automatic Playlist - + Pause - + Go &offline - + Go &online - + Authentication Error - + Error connecting to SIP: Authentication failed! - + %1 by %2 track, artist name - + %1 - %2 current track, some window title - + <h2><b>Tomahawk %1<br/>(%2)</h2> - + <h2><b>Tomahawk %1</h2> - - Copyright 2010 - 2012<br/>Christian Muehlhaeuser &lt;muesli@tomahawk-player.org&gt;<br/><br/>Thanks to: Leo Franchi, Jeff Mitchell, Dominik Schmidt, Jason Herskowitz, Alejandro Wainzinger, Hugo Lindstr&ouml;m, Michael Zanetti, Harald Sitter and Steve Robertson + + Copyright 2010 - 2012 - + + Thanks to: + + + + About Tomahawk @@ -3093,7 +3254,7 @@ enter the displayed PIN number here: TopTracksContext - + Top Hits @@ -3106,143 +3267,70 @@ enter the displayed PIN number here: - + Cover - + Track - - by - - - - + Artist - - from - - - - + Album - + Statistics - - Lyrics - - - - + Similar Tracks + + + Sorry, but we could not find similar tracks for this song! + + - + You've listened to this track %n time(s). - + You've never listened to this track before. - + You first listened to it on %1. - + You've listened to %1 %n time(s). - + You've never listened to %1 before. - - TrackModel - - - Artist - - - - - Title - - - - - Album - - - - - Track - - - - - Duration - - - - - Bitrate - - - - - Age - - - - - Year - - - - - Size - - - - - Origin - - - - - Score - - - - - Composer - - - TrackView - + Sorry, your filter '%1' did not match any results. @@ -3271,63 +3359,31 @@ enter the displayed PIN number here: TreeModel - - Name - - - - - Duration - - - - - Bitrate - - - - - Age - - - - - Year - - - - - Size - - - - - Origin - - - - - Composer - - - - + All Artists - - + + My Collection - - + + Collection of %1 + + TreeView + + + Sorry, your filter '%1' did not match any results. + + + TwitterConfigWidget @@ -3399,27 +3455,37 @@ You can re-send a sync message at any time simply by sending another tweet using ViewManager - + + After you have scanned your music collection you will find your tracks right here. + + + + + This collection is empty. + + + + SuperCollection - + Combined libraries of all your online friends - + All available albums - + Recently Played Tracks - + Recently played tracks from all your friends @@ -3442,12 +3508,12 @@ You can re-send a sync message at any time simply by sending another tweet using - + No recently created playlists in your network. - + Welcome to Tomahawk @@ -3455,7 +3521,7 @@ You can re-send a sync message at any time simply by sending another tweet using WhatsHotWidget - + Charts @@ -3684,107 +3750,107 @@ Lyrics for "%1" by %2: XmppSipPlugin - + User Interaction - + Host is unknown - + Item not found - + Authorization Error - + Remote Stream Error - + Remote Connection failed - + Internal Server Error - + System shutdown - + Conflict - + Unknown - + No Compression Support - + No Encryption Support - + No Authorization Support - + No Supported Feature - + Add Friend - + Enter Xmpp ID: - + Add Friend... - + XML Console... - + I'm sorry -- I'm just an automatic presence used by Tomahawk Player (http://gettomahawk.com). If you are getting this message, the person you are trying to reach is probably not signed on, so please try again later! - + Authorize User - + Do you want to grant <b>%1</b> access to your Collection? diff --git a/lang/tomahawk_zh_TW.ts b/lang/tomahawk_zh_TW.ts index b50ec223d..810820569 100644 --- a/lang/tomahawk_zh_TW.ts +++ b/lang/tomahawk_zh_TW.ts @@ -2,17 +2,17 @@ AccountFactoryWrapper - + Dialog 對話框 - + Description goes here 說明放在這裡 - + Add Account 新增帳戶 @@ -20,17 +20,17 @@ AccountFactoryWrapperDelegate - + Online 線上 - + Connecting... 連接中... - + Offline 離線 @@ -133,7 +133,17 @@ connect and stream from you? 列出演出者的其他專輯 - + + Sorry, we could not find any other albums for this artist! + + + + + Sorry, we could not find any tracks for this album! + + + + Other Albums by %1 列出所有其他專輯,依 %1 @@ -141,35 +151,17 @@ connect and stream from you? AlbumModel - - Album - 專輯 - - - - + + All albums from %1 從 %1 的所有專輯 - + All albums 所有專輯 - - AlbumView - - - After you have scanned your music collection you will find your latest album additions right here. - 當您掃描您的音樂收藏,您會發現您的最新專輯添加在這裡。 - - - - This collection doesn't have any recent albums. - 這個收藏沒有任何最新專輯。 - - ArtistInfoWidget @@ -178,12 +170,12 @@ connect and stream from you? 形式 - + Top Hits 流行精選 - + Related Artists 相關演出者 @@ -192,22 +184,24 @@ connect and stream from you? Albums 專輯 - - - ArtistView - - After you have scanned your music collection you will find your tracks right here. - 當您掃描您的音樂收藏,您將在這裡找到您的曲目。 + + Cover + - - This collection is currently empty. - 目前這個收藏是空的。 + + Sorry, we could not find any albums for this artist! + - - Sorry, your filter '%1' did not match any results. + + Sorry, we could not find any related artists! + + + + + Sorry, we could not find any top hits for this artist! @@ -234,57 +228,57 @@ connect and stream from you? 下一首 - + Artist 演出者 - + Album 專輯 - + Owner 擁有人 - + social - + love 喜愛 - + Time 時間 - + Time Left 剩餘時間 - + Shuffle 隨機 - + Repeat 重複 - + Low - + High @@ -293,22 +287,25 @@ connect and stream from you? CategoryAddItem - - New Playlist - 新增播放清單 + Create new Playlist + - - - - + + Create new Station + + + + + + New Station - - - + + + %1 Station @@ -334,27 +331,6 @@ connect and stream from you? 清除 - - CollectionFlatModel - - - My Collection - 我的收藏 - - - - Collection of %1 - - - - - CollectionView - - - This collection is empty. - 這個收藏是空的。 - - ContextWidget @@ -364,12 +340,12 @@ connect and stream from you? - + Show Footnotes 顯示註腳 - + Hide Footnotes 隱藏註腳 @@ -383,7 +359,7 @@ connect and stream from you? - <html><head/><body><p><span style=" font-weight:600;">Sorry!</span> Tomahawk crashed. Please tell us about it! Tomahawk has created an error report for you that can help improve the stability in the future. You can now send the this report directly to the Tomahawk developers.</p></body></html> + <html><head/><body><p><span style=" font-weight:600;">Sorry!</span> Tomahawk crashed. Please tell us about it! Tomahawk 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 Tomahawk developers.</p></body></html> @@ -439,17 +415,17 @@ connect and stream from you? DelegateConfigWrapper - + About 關於 - + Delete Account 刪除帳戶 - + About this Account 關於此帳戶 @@ -462,24 +438,11 @@ connect and stream from you? Tomahawk 診斷 - - Update - 更新 - - - + Copy to Clipboard 複製到剪貼簿 - - DropJob - - - No tracks found for given %1 - - - GlobalSearchWidget @@ -504,56 +467,43 @@ connect and stream from you? 信息欄 - + Filter... 過濾器... - - JobStatusView - - - Searching For - 搜尋 - - - - Pending - - - - - Idle - 閒置 - - LastFmConfig - + Form - + Scrobble tracks to Last.fm - + Username: 用戶名稱: - + Password: 密碼: - + Test Login 測試登錄 + + + Import Playback History + + LastfmContext @@ -656,11 +606,80 @@ connect and stream from you? NewReleasesWidget - + New Releases 新版本 + + PlayableModel + + + Artist + + + + + Title + + + + + Composer + + + + + Album + + + + + Track + + + + + Duration + + + + + Bitrate + + + + + Age + + + + + Year + + + + + Size + + + + + Origin + + + + + Score + + + + + + Name + + + PlaylistItemDelegate @@ -677,17 +696,17 @@ connect and stream from you? PlaylistLargeItemDelegate - + played %1 by you - + played %1 by %2 - + added %1 @@ -695,12 +714,12 @@ connect and stream from you? PlaylistModel - + A playlist by %1, created %2 - + you @@ -756,7 +775,12 @@ connect and stream from you? PlaylistView - + + This playlist is currently empty. + + + + This playlist is currently empty. Add some tracks to it and enjoy the music! 目前這個播放清單是空的。請加入一些曲目,然後盡情享受音樂! @@ -823,67 +847,67 @@ connect and stream from you? QObject - + %n year(s) ago - + %n year(s) - + %n month(s) ago - + %n month(s) - + %n week(s) ago - + %n week(s) - + %n day(s) ago - + %n day(s) - + %n hour(s) ago - + %n hour(s) - + %1 minutes ago %1 分鐘前 - + %1 minutes %1 分鐘 - + just now 剛才 @@ -920,20 +944,25 @@ connect and stream from you? - - Show Queue - 顯示佇列 + + Open Queue + + + + + Open Queue - %n item(s) + - - Hide Queue - 隱藏佇列 + + Close Queue + RelatedArtistsContext - + Related Artists 相關演出者 @@ -1056,17 +1085,22 @@ connect and stream from you? 文字標籤 - - Listening to "%1" by %2 and loving it! %3 + + Tweet - - Listening to "%1" by %2 on "%3" and loving it! %4 + + Listening to "%1" by %2. %3 - + + Listening to "%1" by %2 on "%3". %4 + + + + %1 characters left @@ -1099,29 +1133,19 @@ connect and stream from you? 前10名 - - Offline - 離線 - - - + All available tracks - - Online - 線上 - - - - + + Show 顯示 - - + + Hide 隱藏 @@ -1144,17 +1168,17 @@ connect and stream from you? 最近播放的曲目 - + New Additions 新增 - + My recent activity 我的近期活動 - + Recent activity from %1 @@ -1162,81 +1186,138 @@ connect and stream from you? SourceItem - + Collection 收藏 - - + + Latest Additions 最新加入 - + Recently Played 最近播放的 - + Loved Tracks - + SuperCollection 超級收藏 - + + Sorry, we could not find any loved tracks! + + + + Latest additions to your collection - + Latest additions to %1's collection - + + Sorry, we could not find any recent additions! + + + + Recently Played Tracks - + Your recently played tracks - + %1's recently played tracks + + + Sorry, we could not find any recent plays! + + SourceTreeView - + &Copy Link 複製鏈接 - + &Delete %1 - + + Add to my Playlists + + + + + Add to my Automatic Playlists + + + + + Add to my Stations + + + + &Export Playlist 匯出播放清單 - + + playlist + + + + + automatic playlist + + + + + station + + + + + Delete %1? + playlist/station/... + + + + + Would you like to delete the %1 <b>"%2"</b>? + e.g. Would you like to delete the playlist named Foobar? + + + + Save XSPF 儲存 XSPF - + Playlists (*.xspf) 播放清單(*.xspf) @@ -1269,52 +1350,52 @@ connect and stream from you? - + Browse 瀏覽 - + Search History 搜尋記錄 - + My Music 我的音樂 - + SuperCollection 超級收藏 - + Top Loved Tracks 最喜愛的曲目 - + Dashboard 儀表板 - + Recently Played 最近播放的 - + Charts - + New Releases 新版本 - + Friends 朋友 @@ -1322,52 +1403,52 @@ connect and stream from you? SpotifyConfig - + Form - + Configure your Spotify account - + Username or Facebook Email 使用者名稱或 Facebook 的電子郵件 - + Log In 登錄 - + Right click on any Tomahawk playlist to sync it to Spotify. - + High Quality Streams 高品質的串流 - + Spotify playlists to keep in sync: - + Delete Tomahawk playlist when removing synchronization 刪除同步時,刪除 Tomahawk 播放清單 - + Username: 用戶名稱: - + Password: 密碼: @@ -1375,12 +1456,12 @@ connect and stream from you? SpotifyPlaylistUpdater - + Delete in Spotify? - + Would you like to delete the corresponding Spotify playlist as well? @@ -1514,32 +1595,32 @@ connect and stream from you? Tomahawk::Accounts::AccountDelegate - + Add Account 新增帳戶 - - Remove Account - 刪除帳戶 + + Remove + - + %1 downloads - + Online 線上 - + Connecting... 連接中... - + Offline 離線 @@ -1547,13 +1628,13 @@ connect and stream from you? Tomahawk::Accounts::AccountModel - + Manual Install Required - - Unfortunately, automatic installation of this resolver is not yet available on Linux.<br /><br />Please use "Install from file" above, by fetching it from your distribution or compiling it yourself. Further instructions can be found here:<br /><br />http://www.tomahawk-player.org/resolvers/%1 + + Unfortunately, automatic installation of this resolver is not available or disabled for your platform.<br /><br />Please use "Install from file" above, by fetching it from your distribution or compiling it yourself. Further instructions can be found here:<br /><br />http://www.tomahawk-player.org/resolvers/%1 @@ -1604,7 +1685,7 @@ connect and stream from you? Tomahawk::Accounts::LastFmAccountFactory - + Scrobble your tracks to last.fm, and find freely downloadable tracks to play @@ -1612,23 +1693,49 @@ connect and stream from you? Tomahawk::Accounts::LastFmConfig - + + Testing... + + + + Test Login - - + + Importing %1 + e.g. Importing 2012/01/01 + + + + + Importing History... + + + + + History Incomplete. Resume + + + + + Playback History Imported + + + + + Failed 失敗 - + Success 成功 - + Could not contact server 無法聯繫服務器 @@ -1636,12 +1743,17 @@ connect and stream from you? Tomahawk::Accounts::SpotifyAccount - + Sync with Spotify - + + Re-enable syncing with Spotify + + + + Stop syncing with Spotify @@ -1649,22 +1761,22 @@ connect and stream from you? Tomahawk::Accounts::SpotifyAccountConfig - + Logging in... 登錄中... - + Logged in! 登錄了! - + Failed: %1 失敗:%1 - + Log In 登錄 @@ -1672,7 +1784,7 @@ connect and stream from you? Tomahawk::Accounts::SpotifyAccountFactory - + Play music from and sync your playlists with Spotify Premium @@ -1822,7 +1934,7 @@ You may wish to try re-authenticating. Tomahawk::Accounts::ZeroconfFactory - + Automatically connect to Tomahawks on the local network 自動連接到區域網路上的 Tomahawks @@ -1836,29 +1948,29 @@ You may wish to try re-authenticating. - - + + Add to &Queue 添加至佇列 - + &Love - + &Copy Track Link - + Un-&Love - + &Delete Items @@ -1873,22 +1985,22 @@ You may wish to try re-authenticating. - + &Show Track Page - + &Delete Item - + &Show Album Page - + &Show Artist Page @@ -1929,12 +2041,32 @@ You may wish to try re-authenticating. Tomahawk::DropJobNotifier - + + playlist + + + + + artist + + + + + track + + + + + album + + + + Fetching %1 from database - + Parsing %1 %2 @@ -1979,17 +2111,17 @@ Please change the filters or try again. Tomahawk::DynamicView - + Add some filters above to seed this station! - + Press Generate to get started! - + Add some filters above, and press Generate to get started! @@ -1997,7 +2129,7 @@ Please change the filters or try again. Tomahawk::DynamicWidget - + Station ran out of tracks! Try tweaking the filters for a new set of songs to play. @@ -2314,92 +2446,92 @@ Try tweaking the filters for a new set of songs to play. - + Much less - + Less - + A bit less - + Keep at current - + A bit more - + More - + Much more - + Tempo - + Loudness - + Danceability - + Energy - + Song Hotttnesss - + Artist Hotttnesss - + Artist Familiarity - + By Description - + Enter a description 輸入一個描述 - + Apply steering command - + Reset all steering commands @@ -2415,22 +2547,22 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::InfoSystem::ChartsPlugin - + Top Overall - + Artists 演出者 - + Albums 專輯 - + Tracks 曲目 @@ -2451,27 +2583,27 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::InfoSystem::LastFmInfoPlugin - + Top Tracks - + Loved Tracks - + Hyped Tracks - + Top Artists - + Hyped Artists @@ -2479,7 +2611,7 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::InfoSystem::NewReleasesPlugin - + Albums 專輯 @@ -2487,7 +2619,7 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::InfoSystem::TwitterInfoPlugin - + Listening to "%1" by %2 and loving it! %3 @@ -2545,37 +2677,37 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::Query - + and - + You - + you - + and - + %n other(s) - + %1 people - + loved this track @@ -2591,7 +2723,7 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::ShortenedLinkParser - + Network error parsing shortened link! @@ -2599,36 +2731,46 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::Source - - + + Scanning (%L1 tracks) - + Scanning - + Checking - + Fetching - + Parsing 解析 - + Saving (%1%) + + + Online + + + + + Offline + + Tomahawk::SpotifyParser @@ -2649,7 +2791,7 @@ Try tweaking the filters for a new set of songs to play. TomahawkApp - + My Collection 我的收藏 @@ -2671,39 +2813,48 @@ enter the displayed PIN number here: TomahawkTrayIcon - - + &Stop Playback after current Track - - + + Hide Tomahawk Window - + Show Tomahawk Window - + Currently not playing. 目前沒有播放。 - + Play 播放 - + Pause 暫停 - + + &Love + + + + + Un-&Love + + + + &Continue Playback after current Track @@ -2847,7 +2998,7 @@ enter the displayed PIN number here: - + Play 播放 @@ -2867,162 +3018,172 @@ enter the displayed PIN number here: 下一首 - + Back - + Go back one page - + Forward - + Go forward one page - + Global Search... 全域搜尋... - - + + Check For Updates... 檢查更新... - - - + + + Connect To Peer 連接點對點 - + Enter peer address: 輸入對等地址: - + Enter peer port: 輸入對等連接埠: - + Enter peer key: 輸入對等密鑰: - + XSPF Error XSPF 錯誤 - + This is not a valid XSPF playlist. - + Failed to save tracks 無法儲存曲目 - + Some tracks in the playlist do not contain an artist and a title. They will be ignored. - + Sorry, there is a problem accessing your audio device or the desired track, current track will be skipped. Make sure you have a suitable Phonon backend and required plugins installed. - + Sorry, there is a problem accessing your audio device or the desired track, current track will be skipped. - + + Station + + + + Create New Station - + Name: 名稱: - - New Station + + Playlist - - New Playlist - 新增播放清單 + + Automatic Playlist + - + Pause 暫停 - + Go &offline 離線 - + Go &online 上網 - + Authentication Error 驗證錯誤 - + Error connecting to SIP: Authentication failed! - + %1 by %2 track, artist name - + %1 - %2 current track, some window title - + <h2><b>Tomahawk %1<br/>(%2)</h2> <h2><b>Tomahawk %1<br/>(%2)</h2> - + <h2><b>Tomahawk %1</h2> <h2><b>Tomahawk %1</h2> - - Copyright 2010 - 2012<br/>Christian Muehlhaeuser &lt;muesli@tomahawk-player.org&gt;<br/><br/>Thanks to: Leo Franchi, Jeff Mitchell, Dominik Schmidt, Jason Herskowitz, Alejandro Wainzinger, Hugo Lindstr&ouml;m, Michael Zanetti, Harald Sitter and Steve Robertson + + Copyright 2010 - 2012 - + + Thanks to: + + + + About Tomahawk @@ -3093,7 +3254,7 @@ enter the displayed PIN number here: TopTracksContext - + Top Hits 流行精選 @@ -3106,143 +3267,70 @@ enter the displayed PIN number here: - + Cover - + Track - - by - - - - + Artist - - from - - - - + Album - + Statistics - - Lyrics - - - - + Similar Tracks + + + Sorry, but we could not find similar tracks for this song! + + - + You've listened to this track %n time(s). - + You've never listened to this track before. - + You first listened to it on %1. - + You've listened to %1 %n time(s). - + You've never listened to %1 before. - - TrackModel - - - Artist - 演出者 - - - - Title - 標題 - - - - Album - 專輯 - - - - Track - 曲目 - - - - Duration - 長度 - - - - Bitrate - 比特率 - - - - Age - 年代 - - - - Year - - - - - Size - - - - - Origin - - - - - Score - - - - - Composer - - - TrackView - + Sorry, your filter '%1' did not match any results. @@ -3271,64 +3359,31 @@ enter the displayed PIN number here: TreeModel - - Name - 名稱 - - - - Duration - 長度 - - - - - Bitrate - - - - - Age - 年代 - - - - Year - - - - - Size - - - - - Origin - - - - - Composer - - - - + All Artists - - + + My Collection 我的收藏 - - + + Collection of %1 + + TreeView + + + Sorry, your filter '%1' did not match any results. + + + TwitterConfigWidget @@ -3400,27 +3455,37 @@ You can re-send a sync message at any time simply by sending another tweet using ViewManager - + + After you have scanned your music collection you will find your tracks right here. + + + + + This collection is empty. + + + + SuperCollection 超級收藏 - + Combined libraries of all your online friends 聯合您所有線上朋友的音樂庫 - + All available albums 所有現有專輯 - + Recently Played Tracks - + Recently played tracks from all your friends @@ -3443,12 +3508,12 @@ You can re-send a sync message at any time simply by sending another tweet using 最近播放的曲目 - + No recently created playlists in your network. 沒有最近建立的播放清單在您的網路。 - + Welcome to Tomahawk 歡迎到 Tomahawk @@ -3456,7 +3521,7 @@ You can re-send a sync message at any time simply by sending another tweet using WhatsHotWidget - + Charts @@ -3685,107 +3750,107 @@ Lyrics for "%1" by %2: XmppSipPlugin - + User Interaction 使用者互動 - + Host is unknown 主機是未知 - + Item not found - + Authorization Error 授權錯誤 - + Remote Stream Error 遠端串流錯誤 - + Remote Connection failed 遠端連線失敗 - + Internal Server Error 內部服務器錯誤 - + System shutdown 系統關閉 - + Conflict 衝突 - + Unknown 未知 - + No Compression Support 沒有壓縮支持 - + No Encryption Support 沒有加密支持 - + No Authorization Support 沒有授權支持 - + No Supported Feature 沒有支持的功能 - + Add Friend 加為好友 - + Enter Xmpp ID: 輸入XMPP識別碼: - + Add Friend... 加為好友... - + XML Console... XML的控制台... - + I'm sorry -- I'm just an automatic presence used by Tomahawk Player (http://gettomahawk.com). If you are getting this message, the person you are trying to reach is probably not signed on, so please try again later! - + Authorize User 授權用戶 - + Do you want to grant <b>%1</b> access to your Collection? diff --git a/lang/translations.cmake b/lang/translations.cmake index a5b92f2f4..6b4f89557 100644 --- a/lang/translations.cmake +++ b/lang/translations.cmake @@ -1,25 +1,48 @@ -FILE (GLOB TS_FILES ${CMAKE_SOURCE_DIR}/lang/*.ts) -QT4_ADD_TRANSLATION(QM_FILES ${TS_FILES}) +macro(add_tomahawk_translations language) + list(APPEND TOMAHAWK_LANGUAGES ${ARGV}) -## HACK HACK HACK - around rcc limitations to allow out of source-tree building -SET( trans_file tomahawk_i18n ) -SET( trans_srcfile ${CMAKE_SOURCE_DIR}/lang/${trans_file}.qrc) -SET( trans_infile ${CMAKE_CURRENT_BINARY_DIR}/${trans_file}.qrc) -SET( trans_outfile ${CMAKE_CURRENT_BINARY_DIR}/qrc_${trans_file}.cxx) + set(tomahawk_i18n_qrc_content "\n") -# Copy the QRC file to the output directory -ADD_CUSTOM_COMMAND( - OUTPUT ${trans_infile} - COMMAND ${CMAKE_COMMAND} -E copy ${trans_srcfile} ${trans_infile} - MAIN_DEPENDENCY ${trans_srcfile} -) + # tomahawk and qt language files + set(tomahawk_i18n_qrc_content "${tomahawk_i18n_qrc_content}\n") + foreach(lang ${TOMAHAWK_LANGUAGES}) + set(tomahawk_i18n_qrc_content "${tomahawk_i18n_qrc_content}tomahawk_${lang}.qm\n") + if(NOT lang STREQUAL "en" AND EXISTS ${QT_TRANSLATIONS_DIR}/qt_${lang}.qm) + file(COPY ${QT_TRANSLATIONS_DIR}/qt_${lang}.qm DESTINATION ${CMAKE_CURRENT_BINARY_DIR}) + set(tomahawk_i18n_qrc_content "${tomahawk_i18n_qrc_content}qt_${lang}.qm\n") + endif() -# Run the resource compiler (rcc_options should already be set) -ADD_CUSTOM_COMMAND( - OUTPUT ${trans_outfile} - COMMAND ${QT_RCC_EXECUTABLE} - ARGS ${rcc_options} -name ${trans_file} -o ${trans_outfile} ${trans_infile} - MAIN_DEPENDENCY ${trans_infile} - DEPENDS ${QM_FILES} -) + # build explicitly enabled languages + list(APPEND TS_FILES "${CMAKE_SOURCE_DIR}/lang/tomahawk_${lang}.ts") + endforeach() + + set(tomahawk_i18n_qrc_content "${tomahawk_i18n_qrc_content}\n") + set(tomahawk_i18n_qrc_content "${tomahawk_i18n_qrc_content}\n") + + file(WRITE ${CMAKE_BINARY_DIR}/lang/tomahawk_i18n.qrc "${tomahawk_i18n_qrc_content}" ) + + QT4_ADD_TRANSLATION(QM_FILES ${TS_FILES}) + + ## HACK HACK HACK - around rcc limitations to allow out of source-tree building + SET( trans_file tomahawk_i18n ) + SET( trans_srcfile ${CMAKE_BINARY_DIR}/lang/${trans_file}.qrc) + SET( trans_infile ${CMAKE_CURRENT_BINARY_DIR}/${trans_file}.qrc) + SET( trans_outfile ${CMAKE_CURRENT_BINARY_DIR}/qrc_${trans_file}.cxx) + + # Copy the QRC file to the output directory + ADD_CUSTOM_COMMAND( + OUTPUT ${trans_infile} + COMMAND ${CMAKE_COMMAND} -E copy ${trans_srcfile} ${trans_infile} + MAIN_DEPENDENCY ${trans_srcfile} + ) + + # Run the resource compiler (rcc_options should already be set) + ADD_CUSTOM_COMMAND( + OUTPUT ${trans_outfile} + COMMAND ${QT_RCC_EXECUTABLE} + ARGS ${rcc_options} -name ${trans_file} -o ${trans_outfile} ${trans_infile} + MAIN_DEPENDENCY ${trans_infile} + DEPENDS ${QM_FILES} + ) +endmacro() diff --git a/resources.qrc b/resources.qrc index bea3686be..275207bd4 100644 --- a/resources.qrc +++ b/resources.qrc @@ -141,6 +141,10 @@ data/images/process-stop.png data/icons/tomahawk-icon-128x128-grayscale.png data/images/collection.png - data/misc/tomahawk_pubkey.pem + data/misc/tomahawk_pubkey.pem + data/images/track-icon-sidebar.png + data/images/jump-link.png + data/images/scrollbar-vertical-handle.png + data/images/scrollbar-horizontal-handle.png diff --git a/src/AudioControls.cpp b/src/AudioControls.cpp index 9080753f8..99d177c73 100644 --- a/src/AudioControls.cpp +++ b/src/AudioControls.cpp @@ -28,13 +28,14 @@ #include "playlist/PlaylistView.h" #include "database/Database.h" #include "widgets/ImageButton.h" -#include "utils/TomahawkUtils.h" +#include "utils/TomahawkUtilsGui.h" #include "utils/Logger.h" #include "Album.h" #include "DropJob.h" #include "SocialWidget.h" #include "GlobalActionManager.h" #include "ViewManager.h" +#include "Source.h" using namespace Tomahawk; @@ -60,6 +61,7 @@ AudioControls::AudioControls( QWidget* parent ) ui->artistTrackLabel->setFont( font ); ui->artistTrackLabel->setElideMode( Qt::ElideMiddle ); ui->artistTrackLabel->setType( QueryLabel::ArtistAndTrack ); + ui->artistTrackLabel->setJumpLinkVisible( true ); ui->albumLabel->setFont( font ); ui->albumLabel->setType( QueryLabel::Album ); @@ -87,6 +89,9 @@ AudioControls::AudioControls( QWidget* parent ) ui->socialButton->setPixmap( RESPATH "images/share.png" ); ui->loveButton->setPixmap( RESPATH "images/not-loved.png" ); ui->loveButton->setCheckable( true ); + + ui->socialButton->setFixedSize( QSize( 20, 20 ) ); + ui->loveButton->setFixedSize( QSize( 20, 20 ) ); #ifdef Q_WS_MAC ui->ownerLabel->setForegroundRole( QPalette::Text ); @@ -545,7 +550,6 @@ void AudioControls::onTrackClicked() { ViewManager::instance()->show( m_currentTrack->toQuery() ); -// ViewManager::instance()->showCurrentTrack(); } @@ -596,10 +600,13 @@ AudioControls::droppedTracks( QList< query_ptr > tracks ) void AudioControls::onSocialButtonClicked() { - SocialWidget* sw = new SocialWidget( m_parent ); - sw->setPosition( QCursor::pos() ); - sw->setQuery( m_currentTrack->toQuery() ); - sw->show(); + if ( !m_socialWidget.isNull() ) + return; + + m_socialWidget = new SocialWidget( m_parent ); + m_socialWidget.data()->setPosition( m_socialWidget.data()->mapFromGlobal( QCursor::pos() ) ); + m_socialWidget.data()->setQuery( m_currentTrack->toQuery() ); + m_socialWidget.data()->show(); } diff --git a/src/AudioControls.h b/src/AudioControls.h index d454bf2fe..aad7af1b9 100644 --- a/src/AudioControls.h +++ b/src/AudioControls.h @@ -31,6 +31,7 @@ class QDropEvent; class QDragEnterEvent; class QDragMoveEvent; +class SocialWidget; namespace Ui { @@ -91,6 +92,8 @@ private: void setSocialActions(); Ui::AudioControls* ui; + + QWeakPointer m_socialWidget; Tomahawk::result_ptr m_currentTrack; Tomahawk::PlaylistModes::RepeatMode m_repeatMode; diff --git a/src/AudioControls.ui b/src/AudioControls.ui index d8db84968..2ce80c3f8 100644 --- a/src/AudioControls.ui +++ b/src/AudioControls.ui @@ -207,9 +207,6 @@ 16 - - PointingHandCursor - Artist @@ -229,9 +226,6 @@ 16 - - PointingHandCursor - Album diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 78aefef0d..dd7e8dff5 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -13,8 +13,6 @@ SET( QT_USE_QTNETWORK TRUE ) SET( QT_USE_QTXML TRUE ) SET( QT_USE_QTWEBKIT TRUE ) -add_definitions( -DQT_SHAREDPOINTER_TRACK_POINTERS ) - INCLUDE( ${QT_USE_FILE} ) INCLUDE( AddAppIconMacro ) @@ -68,27 +66,13 @@ SET( tomahawkSourcesGui ${tomahawkSourcesGui} sourcetree/items/GroupItem.cpp sourcetree/items/HistoryItem.cpp - utils/GuiHelpers.cpp - - accounts/lastfm/LastFmAccount.cpp - accounts/lastfm/LastFmConfig.cpp - accounts/lastfm/LastFmInfoPlugin.cpp - - accounts/spotify/SpotifyAccount.cpp - accounts/spotify/SpotifyAccountConfig.cpp - accounts/spotify/SpotifyPlaylistUpdater.cpp - TomahawkTrayIcon.cpp AudioControls.cpp SettingsDialog.cpp DiagnosticsDialog.cpp - AccountDelegate.cpp SettingsListDelegate.cpp - DelegateConfigWrapper.cpp TomahawkWindow.cpp LoadXSPFDialog.cpp - AccountFactoryWrapper.cpp - AccountFactoryWrapperDelegate.cpp SocialWidget.cpp ) @@ -102,19 +86,14 @@ SET( tomahawkUI ${tomahawkUI} StackedSettingsDialog.ui ProxyDialog.ui - accounts/lastfm/LastFmConfig.ui - accounts/spotify/SpotifyAccountConfig.ui - AudioControls.ui LoadXSPFDialog.ui - AccountFactoryWrapper.ui SocialWidget.ui ) INCLUDE_DIRECTORIES( . ${CMAKE_CURRENT_BINARY_DIR} - ${CMAKE_BINARY_DIR}/thirdparty/liblastfm2/src audio database @@ -122,7 +101,6 @@ INCLUDE_DIRECTORIES( network sourcetree topbar - utils libtomahawk mac @@ -137,6 +115,8 @@ INCLUDE_DIRECTORIES( ${LIBATTICA_INCLUDE_DIR} ${LIBECHONEST_INCLUDE_DIR} ${LIBECHONEST_INCLUDE_DIR}/.. + ${LIBLASTFM_INCLUDE_DIRS} + ${LIBLASTFM_INCLUDE_DIRS}/.. ) SET( OS_SPECIFIC_LINK_LIBRARIES "" ) @@ -154,11 +134,6 @@ IF( APPLE ) SET( tomahawkSources ${tomahawkSources} mac/TomahawkApp_Mac.mm mac/MacShortcutHandler.cpp ) ENDIF( APPLE ) -IF(GLOOX_FOUND) - INCLUDE_DIRECTORIES( ${GLOOX_INCLUDE_DIR} ) - SET( tomahawkSources ${tomahawkSources} xmppbot/XmppBot.cpp ) -ENDIF(GLOOX_FOUND) - ADD_SUBDIRECTORY( accounts ) ADD_SUBDIRECTORY( infoplugins ) @@ -170,7 +145,9 @@ INCLUDE(GNUInstallDirs) configure_file(${CMAKE_CURRENT_SOURCE_DIR}/Config.h.in ${CMAKE_CURRENT_BINARY_DIR}/config.h) +# translations include( ${CMAKE_SOURCE_DIR}/lang/translations.cmake ) +add_tomahawk_translations(ar bg ca de en es fr ja pl pt_BR ru sv tr zh_CN zh_TW) SET( final_src ${final_src} ${tomahawkMoc} ${tomahawkSources} ${trans_outfile}) @@ -205,16 +182,13 @@ MESSAGE( STATUS "OS_SPECIFIC_LINK_LIBRARIES: ${OS_SPECIFIC_LINK_LIBRARIES}" ) SET(LINK_LIBRARIES "") IF(LIBLASTFM_FOUND) - SET(LINK_LIBRARIES ${LINK_LIBRARIES} tomahawk_lastfm2 ) + SET( LINK_LIBRARIES ${LINK_LIBRARIES} ${LIBLASTFM_LIBRARIES} ) ENDIF(LIBLASTFM_FOUND) -IF(GLOOX_FOUND) - SET(LINK_LIBRARIES ${LINK_LIBRARIES} ${GLOOX_LIBRARIES} ) -ENDIF(GLOOX_FOUND) IF(QCA2_FOUND) - SET(LINK_LIBRARIES ${LINK_LIBRARIES} ${QCA2_LIBRARIES} ) + SET( LINK_LIBRARIES ${LINK_LIBRARIES} ${QCA2_LIBRARIES} ) ENDIF(QCA2_FOUND) IF(WITH_BREAKPAD) - SET(LINK_LIBRARIES ${LINK_LIBRARIES} tomahawk_breakpad) + SET( LINK_LIBRARIES ${LINK_LIBRARIES} tomahawk_breakpad ) ENDIF() TARGET_LINK_LIBRARIES( tomahawk diff --git a/src/Config.h.in b/src/Config.h.in index 87ec9b48d..1aa764c96 100644 --- a/src/Config.h.in +++ b/src/Config.h.in @@ -19,9 +19,10 @@ #cmakedefine WITH_BREAKPAD #cmakedefine WITH_CRASHREPORTER +#cmakedefine WITH_BINARY_ATTICA + #cmakedefine LIBLASTFM_FOUND -#cmakedefine GLOOX_FOUND #cmakedefine QCA2_FOUND #endif // CONFIG_H_IN diff --git a/src/DiagnosticsDialog.cpp b/src/DiagnosticsDialog.cpp index 35ff7e9dc..e63a6fe16 100644 --- a/src/DiagnosticsDialog.cpp +++ b/src/DiagnosticsDialog.cpp @@ -26,11 +26,13 @@ #include "network/Servent.h" #include "SourceList.h" +#include #include #include #include #include #include +#include #include "utils/Logger.h" #include "sip/SipHandler.h" @@ -42,14 +44,17 @@ DiagnosticsDialog::DiagnosticsDialog( QWidget *parent ) { ui->setupUi( this ); - connect( ui->updateButton, SIGNAL( clicked() ), this, SLOT( updateLogView() ) ); connect( ui->clipboardButton, SIGNAL( clicked() ), this, SLOT( copyToClipboard() ) ); connect( ui->buttonBox, SIGNAL( rejected() ), this, SLOT( reject() ) ); + ui->scrollAreaWidgetContents->setLayout( new QVBoxLayout() ); + updateLogView(); } -void DiagnosticsDialog::updateLogView() + +void +DiagnosticsDialog::updateLogView() { QString log; @@ -59,16 +64,11 @@ void DiagnosticsDialog::updateLogView() ); // network - log.append( - "TOMAHAWK-VERSION: " TOMAHAWK_VERSION "\n\n\n" - ); + log.append( "TOMAHAWK-VERSION: " TOMAHAWK_VERSION "\n\n" ); // network - log.append( - "NETWORK:\n" - " General:\n" - ); - if( Servent::instance()->visibleExternally() ) + log.append( "NETWORK:\n General:\n" ); + if ( Servent::instance()->visibleExternally() ) { log.append( QString( @@ -83,17 +83,13 @@ void DiagnosticsDialog::updateLogView() } else { - log.append( - QString( - " visible: false" - ) - ); + log.append( " visible: false" ); } - log.append("\n\n"); - + ui->scrollAreaWidgetContents->layout()->addWidget( new QLabel( log, this ) ); // Peers / Accounts, TODO - log.append("ACCOUNTS:\n"); + ui->scrollAreaWidgetContents->layout()->addWidget( new QLabel( "ACCOUNTS:\n", this ) ); + const QList< Tomahawk::source_ptr > sources = SourceList::instance()->sources( true ); const QList< Tomahawk::Accounts::Account* > accounts = Tomahawk::Accounts::AccountManager::instance()->accounts( Tomahawk::Accounts::SipType ); foreach ( Tomahawk::Accounts::Account* account, accounts ) @@ -102,6 +98,104 @@ void DiagnosticsDialog::updateLogView() if ( !account || !account->sipPlugin() ) continue; + connect( account, SIGNAL( connectionStateChanged( Tomahawk::Accounts::Account::ConnectionState ) ), + SLOT( onAccountConnectionStateChanged( Tomahawk::Accounts::Account::ConnectionState ) ) ); + connect( account, SIGNAL( error( int, QString ) ), + SLOT( onAccountError( int, QString ) ) ); + + connect( account->sipPlugin(), SIGNAL( peerOnline( QString ) ), SLOT( onPeerOnline( QString ) ) ); + connect( account->sipPlugin(), SIGNAL( peerOffline( QString ) ), SLOT( onPeerOffline( QString ) ) ); + connect( account->sipPlugin(), SIGNAL( sipInfoReceived( QString, SipInfo ) ), SLOT( onSipInfoReceived( QString, SipInfo ) ) ); + connect( account->sipPlugin(), SIGNAL( softwareVersionReceived( QString, QString ) ), SLOT( onSoftwareVersionReceived( QString, QString ) ) ); + + QLabel* accountInfoLabel = new QLabel( this ); + ui->scrollAreaWidgetContents->layout()->addWidget( accountInfoLabel ); + m_accountDescriptionStore.insert( account, accountInfoLabel ); + + updateAccountLabel( account ); + } +} + + +void +DiagnosticsDialog::copyToClipboard() +{ + QString log; + foreach ( QLabel* label, m_accountDescriptionStore.values() ) + { + log += label->text() + "\n\n"; + } + + QApplication::clipboard()->setText( log ); +} + + +void +DiagnosticsDialog::onAccountConnectionStateChanged( Tomahawk::Accounts::Account::ConnectionState /* state */ ) +{ + Tomahawk::Accounts::Account* account = qobject_cast< Tomahawk::Accounts::Account* >( sender() ); + Q_ASSERT( account ); + + updateAccountLabel( account ); +} + + +void +DiagnosticsDialog::onAccountError( int /* errorId */ , QString /* errorString */ ) +{ + Tomahawk::Accounts::Account* account = qobject_cast< Tomahawk::Accounts::Account* >( sender() ); + Q_ASSERT( account ); +} + + +void +DiagnosticsDialog::onPeerOnline( const QString& ) +{ + Tomahawk::Accounts::Account* account = qobject_cast< SipPlugin* >( sender() )->account(); + Q_ASSERT( account ); + + updateAccountLabel( account ); +} + + +void +DiagnosticsDialog::onPeerOffline( const QString& ) +{ + Tomahawk::Accounts::Account* account = qobject_cast< SipPlugin* >( sender() )->account(); + Q_ASSERT( account ); + + updateAccountLabel( account ); +} + + +void +DiagnosticsDialog::onSipInfoReceived( const QString& /* peerId */ , const SipInfo& /* info */ ) +{ + Tomahawk::Accounts::Account* account = qobject_cast< SipPlugin* >( sender() )->account(); + Q_ASSERT( account ); + + updateAccountLabel( account ); +} + + +void +DiagnosticsDialog::onSoftwareVersionReceived( const QString& /* peerId */ , const QString& /* versionString */ ) +{ + Tomahawk::Accounts::Account* account = qobject_cast< SipPlugin* >( sender() )->account(); + Q_ASSERT( account ); + + updateAccountLabel( account ); +} + + +void +DiagnosticsDialog::updateAccountLabel( Tomahawk::Accounts::Account* account ) +{ + QLabel* accountInfoLabel = m_accountDescriptionStore.value( account ); + + if ( accountInfoLabel ) + { + QString accountInfo; QString stateString; switch( account->connectionState() ) { @@ -118,7 +212,7 @@ void DiagnosticsDialog::updateLogView() case Tomahawk::Accounts::Account::Disconnecting: stateString = "Disconnecting"; } - log.append( + accountInfo.append( QString( " %2 (%1): %3 (%4)\n" ) .arg( account->accountServiceName() ) .arg( account->sipPlugin()->friendlyName() ) @@ -126,55 +220,43 @@ void DiagnosticsDialog::updateLogView() .arg( stateString ) ); - foreach( const QString &peerId, account->sipPlugin()->peersOnline() ) + foreach( const QString& peerId, account->sipPlugin()->peersOnline() ) { - /* enable this again, when we check the Source.has this peerId - bool connected = false; - Q_FOREACH( const Tomahawk::source_ptr &source, sources ) - { - if( source->controlConnection() ) - { - connected = true; - break; - } - }*/ - QString versionString = SipHandler::instance()->versionString( peerId ); SipInfo sipInfo = SipHandler::instance()->sipInfo( peerId ); - if( !sipInfo.isValid() ) - log.append( + if ( !sipInfo.isValid() ) + { + accountInfo.append( QString(" %1: %2 %3" /*"(%4)"*/ "\n") .arg( peerId ) .arg( "sipinfo invalid" ) .arg( versionString ) // .arg( connected ? "connected" : "not connected") ); - else if( sipInfo.isVisible() ) - log.append( + } + else if ( sipInfo.isVisible() ) + { + accountInfo.append( QString(" %1: %2:%3 %4" /*" (%5)"*/ "\n") .arg( peerId ) .arg( sipInfo.host().hostName() ) .arg( sipInfo.port() ) .arg( versionString ) // .arg( connected ? "connected" : "not connected") - ); + } else - log.append( + { + accountInfo.append( QString(" %1: visible: false %2" /*" (%3)"*/ "\n") .arg( peerId ) .arg( versionString ) // .arg( connected ? "connected" : "not connected") - ); + } } - log.append("\n"); + accountInfo.append( "\n" ); + + accountInfoLabel->setText( accountInfo ); } - ui->logView->setPlainText(log); -} - -void DiagnosticsDialog::copyToClipboard() -{ - QApplication::clipboard()->setText( ui->logView->toPlainText() ); -} - +} \ No newline at end of file diff --git a/src/DiagnosticsDialog.h b/src/DiagnosticsDialog.h index e3fed2b59..99da5aae9 100644 --- a/src/DiagnosticsDialog.h +++ b/src/DiagnosticsDialog.h @@ -19,7 +19,15 @@ #ifndef DIGANOSTICSDIALOG_H #define DIAGNOSTICSDIALOG_H +#include "accounts/Account.h" + #include +#include + + +class QLabel; + +class SipInfo; namespace Ui { @@ -37,8 +45,19 @@ public: private slots: void updateLogView(); void copyToClipboard(); + + void onAccountConnectionStateChanged( Tomahawk::Accounts::Account::ConnectionState state ); + void onAccountError( int errorId, QString errorString ); + void onPeerOnline( const QString& ); + void onPeerOffline( const QString& ); + void onSipInfoReceived( const QString& peerId, const SipInfo& info ); + void onSoftwareVersionReceived( const QString& peerId, const QString& versionString ); + void updateAccountLabel( Tomahawk::Accounts::Account* ); private: + + QMap< Tomahawk::Accounts::Account*, QLabel* > m_accountDescriptionStore; + Ui::DiagnosticsDialog* ui; }; diff --git a/src/DiagnosticsDialog.ui b/src/DiagnosticsDialog.ui index 6d884eba6..d304b65f6 100644 --- a/src/DiagnosticsDialog.ui +++ b/src/DiagnosticsDialog.ui @@ -26,19 +26,26 @@ - + + + true + + + + + 0 + 0 + 708 + 386 + + + + - - - - Update - - - diff --git a/src/MusicScanner.cpp b/src/MusicScanner.cpp index f7e30c5e0..f1b489878 100644 --- a/src/MusicScanner.cpp +++ b/src/MusicScanner.cpp @@ -106,15 +106,17 @@ MusicScanner::MusicScanner( const QStringList& dirs, quint32 bs ) , m_batchsize( bs ) , m_dirListerThreadController( 0 ) { - m_ext2mime.insert( "mp3", TomahawkUtils::extensionToMimetype( "mp3" ) ); - m_ext2mime.insert( "ogg", TomahawkUtils::extensionToMimetype( "ogg" ) ); - m_ext2mime.insert( "oga", TomahawkUtils::extensionToMimetype( "oga" ) ); - m_ext2mime.insert( "mpc", TomahawkUtils::extensionToMimetype( "mpc" ) ); - m_ext2mime.insert( "wma", TomahawkUtils::extensionToMimetype( "wma" ) ); - m_ext2mime.insert( "aac", TomahawkUtils::extensionToMimetype( "aac" ) ); - m_ext2mime.insert( "m4a", TomahawkUtils::extensionToMimetype( "m4a" ) ); - m_ext2mime.insert( "mp4", TomahawkUtils::extensionToMimetype( "mp4" ) ); + m_ext2mime.insert( "mp3", TomahawkUtils::extensionToMimetype( "mp3" ) ); + m_ext2mime.insert( "ogg", TomahawkUtils::extensionToMimetype( "ogg" ) ); + m_ext2mime.insert( "oga", TomahawkUtils::extensionToMimetype( "oga" ) ); + m_ext2mime.insert( "mpc", TomahawkUtils::extensionToMimetype( "mpc" ) ); + m_ext2mime.insert( "wma", TomahawkUtils::extensionToMimetype( "wma" ) ); + m_ext2mime.insert( "aac", TomahawkUtils::extensionToMimetype( "aac" ) ); + m_ext2mime.insert( "m4a", TomahawkUtils::extensionToMimetype( "m4a" ) ); + m_ext2mime.insert( "mp4", TomahawkUtils::extensionToMimetype( "mp4" ) ); m_ext2mime.insert( "flac", TomahawkUtils::extensionToMimetype( "flac" ) ); + m_ext2mime.insert( "aiff", TomahawkUtils::extensionToMimetype( "aiff" ) ); + m_ext2mime.insert( "aif", TomahawkUtils::extensionToMimetype( "aif" ) ); } @@ -199,18 +201,16 @@ MusicScanner::listerFinished() foreach( const QString& key, m_filemtimes.keys() ) m_filesToDelete << m_filemtimes[ key ].keys().first(); - tDebug() << "Lister finished: to delete:" << m_filesToDelete; + tDebug( LOGINFO ) << "Scanning complete, saving to database. ( deleted" << m_filesToDelete.count() << "- scanned" << m_scanned << "- skipped" << m_skipped << ")"; + tDebug( LOGEXTRA ) << "Skipped the following files (no tags / no valid audio):"; + foreach ( const QString& s, m_skippedFiles ) + tDebug( LOGEXTRA ) << s; if ( m_filesToDelete.length() || m_scannedfiles.length() ) { commitBatch( m_scannedfiles, m_filesToDelete ); m_scannedfiles.clear(); m_filesToDelete.clear(); - - tDebug( LOGINFO ) << "Scanning complete, saving to database. ( scanned" << m_scanned << "skipped" << m_skipped << ")"; - tDebug( LOGEXTRA ) << "Skipped the following files (no tags / no valid audio):"; - foreach ( const QString& s, m_skippedFiles ) - tDebug( LOGEXTRA ) << s; } else cleanup(); @@ -335,9 +335,8 @@ MusicScanner::readFile( const QFileInfo& fi ) int bitrate = 0; int duration = 0; - + Tag *tag = Tag::fromFile( f ); - if ( f.audioProperties() ) { TagLib::AudioProperties *properties = f.audioProperties(); @@ -345,10 +344,14 @@ MusicScanner::readFile( const QFileInfo& fi ) bitrate = properties->bitrate(); } - QString artist = tag->artist().trimmed(); - QString album = tag->album().trimmed(); - QString track = tag->title().trimmed(); - if ( artist.isEmpty() || track.isEmpty() ) + QString artist, album, track; + if ( tag ) + { + artist = tag->artist().trimmed(); + album = tag->album().trimmed(); + track = tag->title().trimmed(); + } + if ( !tag || artist.isEmpty() || track.isEmpty() ) { // FIXME: do some clever filename guessing m_skippedFiles << fi.canonicalFilePath(); diff --git a/src/PipelineStatusView.cpp b/src/PipelineStatusView.cpp deleted file mode 100644 index e87614d70..000000000 --- a/src/PipelineStatusView.cpp +++ /dev/null @@ -1,117 +0,0 @@ -/* === This file is part of Tomahawk Player - === - * - * Copyright 2010-2011, Christian Muehlhaeuser - * Copyright 2011, Leo Franchi - * - * Tomahawk is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Tomahawk is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Tomahawk. If not, see . - */ - -#include "JobStatusView.h" - -#include -#include - -#include "libtomahawk/Pipeline.h" - -#include "utils/Logger.h" - -using namespace Tomahawk; - - -JobStatusView::JobStatusView( AnimatedSplitter* parent ) - : AnimatedWidget( parent ) - , m_parent( parent ) -{ - setHiddenSize( QSize( 0, 0 ) ); - setLayout( new QVBoxLayout() ); - m_tree = new QTreeWidget( this ); - - layout()->setMargin( 0 ); - layout()->addWidget( m_tree ); - - QStringList headers; - headers << tr( "Searching For" ) << tr( "Pending" ); - m_tree->setHeaderLabels( headers ); - - m_tree->setHorizontalScrollBarPolicy( Qt::ScrollBarAlwaysOff ); - m_tree->setSizePolicy( QSizePolicy::Preferred, QSizePolicy::Ignored ); - m_tree->setColumnCount( 2 ); - m_tree->setColumnWidth( 0, 200 ); - m_tree->setColumnWidth( 1, 50 ); - - m_tree->header()->setStretchLastSection( true ); - m_tree->setRootIsDecorated( false ); - - m_tree->setFrameShape( QFrame::NoFrame ); - m_tree->setAttribute( Qt::WA_MacShowFocusRect, 0 ); - - new QTreeWidgetItem( m_tree ); - - connect( Pipeline::instance(), SIGNAL( resolving( Tomahawk::query_ptr ) ), SLOT( onPipelineUpdate( Tomahawk::query_ptr ) ) ); - connect( Pipeline::instance(), SIGNAL( idle() ), SLOT( onPipelineUpdate() ) ); - -#ifndef Q_WS_WIN - QFont f = font(); - f.setPointSize( f.pointSize() - 1 ); - setFont( f ); -#endif - -#ifdef Q_WS_MAC - f.setPointSize( f.pointSize() - 2 ); - setFont( f ); -#endif - - onPipelineUpdate(); -} - - -void -JobStatusView::onPipelineUpdate( const query_ptr& query ) -{ - QTreeWidgetItem* ti = m_tree->invisibleRootItem()->child( 0 ); - - if ( Pipeline::instance()->activeQueryCount() && !query.isNull() ) - { - ti->setText( 0, QString( "%1 - %2" ).arg( query->artist() ).arg( query->track() ) ); - ti->setText( 1, QString( "%1" ).arg( Pipeline::instance()->activeQueryCount() + Pipeline::instance()->pendingQueryCount() ) ); - - if ( isHidden() ) - emit showWidget(); - } - else - { - ti->setText( 0, tr( "Idle" ) ); - ti->setText( 1, QString( "None" ) ); - - if ( !isHidden() ) - emit hideWidget(); - } -} - - -QSize -JobStatusView::sizeHint() const -{ - unsigned int y = 0; - y += m_tree->header()->height(); - y += m_tree->contentsMargins().top() + m_tree->contentsMargins().bottom(); - - if ( m_tree->invisibleRootItem()->childCount() ) - { - unsigned int rowheight = m_tree->sizeHintForRow( 0 ); - y += rowheight * m_tree->invisibleRootItem()->childCount() + 2; - } - - return QSize( 0, y ); -} diff --git a/src/PipelineStatusView.h b/src/PipelineStatusView.h deleted file mode 100644 index 857357082..000000000 --- a/src/PipelineStatusView.h +++ /dev/null @@ -1,51 +0,0 @@ -/* === This file is part of Tomahawk Player - === - * - * Copyright 2010-2011, Christian Muehlhaeuser - * Copyright 2011, Leo Franchi - * - * Tomahawk is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Tomahawk is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Tomahawk. If not, see . - */ - -#ifndef JOBSTATUSVIEW_H -#define JOBSTATUSVIEW_H - -#include - -#include "Typedefs.h" -#include "widgets/AnimatedSplitter.h" -#include "Query.h" - -class StreamConnection; - -class JobStatusView : public AnimatedWidget -{ -Q_OBJECT - -public: - explicit JobStatusView( AnimatedSplitter* parent ); - virtual ~JobStatusView() - { - } - - QSize sizeHint() const; - -private slots: - void onPipelineUpdate( const Tomahawk::query_ptr& query = Tomahawk::query_ptr() ); - -private: - QTreeView* m_tree; - AnimatedSplitter* m_parent; -}; - -#endif // JOBSTATUSVIEW_H diff --git a/src/Scrobbler.cpp b/src/Scrobbler.cpp index 8b5fa5456..6e1b77bc3 100644 --- a/src/Scrobbler.cpp +++ b/src/Scrobbler.cpp @@ -44,8 +44,8 @@ Scrobbler::Scrobbler( QObject* parent ) SLOT( engineTick( unsigned int ) ), Qt::QueuedConnection ); connect( Tomahawk::InfoSystem::InfoSystem::instance(), - SIGNAL( info( Tomahawk::InfoSystem::InfoRequestData, QVariant ) ), - SLOT( infoSystemInfo( Tomahawk::InfoSystem::InfoRequestData, QVariant ) ) ); + SIGNAL( info( Tomahawk::InfoSystem::InfoRequestData, QVariant ) ), + SLOT( infoSystemInfo( Tomahawk::InfoSystem::InfoRequestData, QVariant ) ) ); connect( AudioEngine::instance(), SIGNAL( started( const Tomahawk::result_ptr& ) ), SLOT( trackStarted( const Tomahawk::result_ptr& ) ), Qt::QueuedConnection ); @@ -72,16 +72,13 @@ void Scrobbler::trackStarted( const Tomahawk::result_ptr& track ) { Q_ASSERT( QThread::currentThread() == thread() ); -// qDebug() << Q_FUNC_INFO; - if( m_reachedScrobblePoint ) + if ( m_reachedScrobblePoint ) { m_reachedScrobblePoint = false; scrobble(); } - QVariantMap playInfo; - Tomahawk::InfoSystem::InfoStringHash trackInfo; trackInfo["title"] = track->track(); trackInfo["artist"] = track->artist()->name(); @@ -89,6 +86,7 @@ Scrobbler::trackStarted( const Tomahawk::result_ptr& track ) trackInfo["duration"] = QString::number( track->duration() ); trackInfo["albumpos"] = QString::number( track->albumpos() ); + QVariantMap playInfo; playInfo["trackinfo"] = QVariant::fromValue< Tomahawk::InfoSystem::InfoStringHash >( trackInfo ); playInfo["private"] = TomahawkSettings::instance()->privateListeningMode(); @@ -101,9 +99,9 @@ Scrobbler::trackStarted( const Tomahawk::result_ptr& track ) // liblastfm forces 0-length tracks to scrobble after 4 minutes, stupid. if ( track->duration() == 0 ) - m_scrobblePoint = ScrobblePoint( 30 ); + m_scrobblePoint = lastfm::ScrobblePoint( 30 ); else - m_scrobblePoint = ScrobblePoint( track->duration() / 2 ); + m_scrobblePoint = lastfm::ScrobblePoint( track->duration() / 2 ); } @@ -126,7 +124,7 @@ Scrobbler::trackStopped() { Q_ASSERT( QThread::currentThread() == thread() ); - if( m_reachedScrobblePoint ) + if ( m_reachedScrobblePoint ) { m_reachedScrobblePoint = false; scrobble(); diff --git a/src/Scrobbler.h b/src/Scrobbler.h index d47e34d1f..5d92bfbb1 100644 --- a/src/Scrobbler.h +++ b/src/Scrobbler.h @@ -20,7 +20,7 @@ #ifndef TOMAHAWK_SCROBBLER_H #define TOMAHAWK_SCROBBLER_H -#include "lastfm/ScrobblePoint" +#include "lastfm/ScrobblePoint.h" #include "Result.h" #include "infosystem/InfoSystem.h" @@ -51,7 +51,7 @@ private: void scrobble(); bool m_reachedScrobblePoint; - ScrobblePoint m_scrobblePoint; + lastfm::ScrobblePoint m_scrobblePoint; }; diff --git a/src/SettingsDialog.cpp b/src/SettingsDialog.cpp index c9cc2546c..54fab5fa5 100644 --- a/src/SettingsDialog.cpp +++ b/src/SettingsDialog.cpp @@ -32,16 +32,16 @@ #include "AtticaManager.h" #include "TomahawkApp.h" #include "TomahawkSettings.h" -#include "DelegateConfigWrapper.h" +#include "accounts/DelegateConfigWrapper.h" #include "MusicScanner.h" #include "Pipeline.h" #include "Resolver.h" #include "ExternalResolverGui.h" #include "utils/TomahawkUtilsGui.h" -#include "GuiHelpers.h" +#include "utils/GuiHelpers.h" #include "ScanManager.h" #include "SettingsListDelegate.h" -#include "AccountDelegate.h" +#include "accounts/AccountDelegate.h" #include "database/Database.h" #include "network/Servent.h" #include "utils/AnimatedSpinner.h" @@ -51,7 +51,7 @@ #include #include #include "utils/Logger.h" -#include "AccountFactoryWrapper.h" +#include "accounts/AccountFactoryWrapper.h" #include "accounts/spotify/SpotifyAccount.h" #include "ui_ProxyDialog.h" diff --git a/src/SocialWidget.cpp b/src/SocialWidget.cpp index 80f708939..9f0536f90 100644 --- a/src/SocialWidget.cpp +++ b/src/SocialWidget.cpp @@ -30,7 +30,7 @@ #define CORNER_ROUNDNESS 8.0 #define FADING_DURATION 500 #define FONT_SIZE 16 -#define OPACITY 0.70 +#define OPACITY 0.85 SocialWidget::SocialWidget( QWidget* parent ) @@ -55,17 +55,23 @@ SocialWidget::SocialWidget( QWidget* parent ) #endif ui->charsLeftLabel->setForegroundRole( QPalette::HighlightedText ); - + + ui->buttonBox->button( QDialogButtonBox::Ok )->setText( tr( "Tweet" ) ); + m_parent->installEventFilter( this ); connect( ui->buttonBox, SIGNAL( accepted() ), SLOT( accept() ) ); - connect( ui->buttonBox, SIGNAL( rejected() ), SLOT( deleteLater() ) ); + connect( ui->buttonBox, SIGNAL( rejected() ), SLOT( close() ) ); connect( ui->textEdit, SIGNAL( textChanged() ), SLOT( onChanged() ) ); connect( ui->facebookButton, SIGNAL( clicked( bool ) ), SLOT( onChanged() ) ); connect( ui->twitterButton, SIGNAL( clicked( bool ) ), SLOT( onChanged() ) ); connect( GlobalActionManager::instance(), SIGNAL( shortLinkReady( QUrl, QUrl, QVariant ) ), SLOT( onShortLinkReady( QUrl, QUrl, QVariant ) ) ); onChanged(); + + ui->twitterButton->setChecked( true ); + ui->twitterButton->setVisible( false ); + ui->facebookButton->setVisible( false ); } @@ -83,6 +89,7 @@ SocialWidget::setOpacity( qreal opacity ) if ( m_opacity == 0.00 && !isHidden() ) { QWidget::hide(); + emit hidden(); } else if ( m_opacity > 0.00 && isHidden() ) { @@ -197,9 +204,9 @@ SocialWidget::onShortLinkReady( const QUrl& longUrl, const QUrl& shortUrl, const Q_UNUSED( callbackObj ); if ( m_query->album().isEmpty() ) - ui->textEdit->setText( tr( "Listening to \"%1\" by %2 and loving it! %3" ).arg( m_query->track() ).arg( m_query->artist() ).arg( shortUrl.toString() ) ); + ui->textEdit->setText( tr( "Listening to \"%1\" by %2. %3" ).arg( m_query->track() ).arg( m_query->artist() ).arg( shortUrl.toString() ) ); else - ui->textEdit->setText( tr( "Listening to \"%1\" by %2 on \"%3\" and loving it! %4" ).arg( m_query->track() ).arg( m_query->artist() ).arg( m_query->album() ).arg( shortUrl.toString() ) ); + ui->textEdit->setText( tr( "Listening to \"%1\" by %2 on \"%3\". %4" ).arg( m_query->track() ).arg( m_query->artist() ).arg( m_query->album() ).arg( shortUrl.toString() ) ); } @@ -229,7 +236,29 @@ void SocialWidget::accept() { tDebug() << "Sharing social link!"; + + QVariantMap shareInfo; + Tomahawk::InfoSystem::InfoStringHash trackInfo; + trackInfo["title"] = m_query->track(); + trackInfo["artist"] = m_query->artist(); + trackInfo["album"] = m_query->album(); + + shareInfo["trackinfo"] = QVariant::fromValue< Tomahawk::InfoSystem::InfoStringHash >( trackInfo ); + shareInfo["message"] = ui->textEdit->toPlainText(); + shareInfo["accountlist"] = QStringList( "all" ); + + Tomahawk::InfoSystem::InfoPushData pushData( uuid(), Tomahawk::InfoSystem::InfoShareTrack, shareInfo, Tomahawk::InfoSystem::PushNoFlag ); + Tomahawk::InfoSystem::InfoSystem::instance()->pushInfo( pushData ); + + deleteLater(); +} + + +void +SocialWidget::close() +{ + QWidget::hide(); deleteLater(); } diff --git a/src/SocialWidget.h b/src/SocialWidget.h index 0fddf9a54..ec4230d5b 100644 --- a/src/SocialWidget.h +++ b/src/SocialWidget.h @@ -50,6 +50,9 @@ public: bool shown() const; +signals: + void hidden(); + public slots: void show( int timeoutSecs = 0 ); void hide(); @@ -65,6 +68,7 @@ private slots: void onShortLinkReady( const QUrl& longUrl, const QUrl& shortUrl, const QVariant& callbackObj ); void onGeometryUpdate(); + void close(); private: unsigned int charsAvailable() const; diff --git a/src/TomahawkApp.cpp b/src/TomahawkApp.cpp index 21dd156ad..f3ac2a95c 100644 --- a/src/TomahawkApp.cpp +++ b/src/TomahawkApp.cpp @@ -29,6 +29,7 @@ #include #include #include +#include #include "Artist.h" #include "Album.h" @@ -83,11 +84,6 @@ #include #endif -// should go to a plugin actually -#ifdef GLOOX_FOUND - #include "xmppbot/XmppBot.h" -#endif - #ifdef Q_WS_MAC #include "mac/MacShortcutHandler.h" @@ -134,6 +130,43 @@ TomahawkApp::TomahawkApp( int& argc, char *argv[] ) setApplicationVersion( QLatin1String( TOMAHAWK_VERSION ) ); registerMetaTypes(); + installTranslator(); +} + + +void +TomahawkApp::installTranslator() +{ + QString locale = QLocale::system().name(); + if ( locale == "C" ) + locale = "en"; + + // Tomahawk translations + QTranslator* translator = new QTranslator( this ); + if ( translator->load( QString( ":/lang/tomahawk_" ) + locale ) ) + { + tDebug() << "Translation: Tomahawk: Using system locale:" << locale; + } + else + { + tDebug() << "Translation: Tomahawk: Using default locale, system locale one not found:" << locale; + translator->load( QString( ":/lang/tomahawk_en" ) ); + } + + TOMAHAWK_APPLICATION::installTranslator( translator ); + + // Qt translations + translator = new QTranslator( this ); + if ( translator->load( QString( ":/lang/qt_" ) + locale ) ) + { + tDebug() << "Translation: Qt: Using system locale:" << locale; + } + else + { + tDebug() << "Translation: Qt: Using default locale, system locale one not found:" << locale; + } + + TOMAHAWK_APPLICATION::installTranslator( translator ); } @@ -309,9 +342,9 @@ TomahawkApp::init() connect( r, SIGNAL( finished() ), this, SLOT( spotifyApiCheckFinished() ) ); #endif -#ifdef Q_WS_MAC +#ifdef Q_OS_MAC // Make sure to do this after main window is inited - Tomahawk::enableFullscreen(); + Tomahawk::enableFullscreen( m_mainwindow ); #endif } @@ -426,6 +459,7 @@ TomahawkApp::registerMetaTypes() qRegisterMetaType("Tomahawk::ModelMode"); // Extra definition for namespaced-versions of signals/slots required + qRegisterMetaType< Tomahawk::Resolver* >("Tomahawk::Resolver*"); qRegisterMetaType< Tomahawk::source_ptr >("Tomahawk::source_ptr"); qRegisterMetaType< Tomahawk::collection_ptr >("Tomahawk::collection_ptr"); qRegisterMetaType< Tomahawk::result_ptr >("Tomahawk::result_ptr"); @@ -593,10 +627,6 @@ TomahawkApp::initSIP() //FIXME: jabber autoconnect is really more, now that there is sip -- should be renamed and/or split out of jabber-specific settings if ( !arguments().contains( "--nosip" ) ) { -#ifdef GLOOX_FOUND - m_xmppBot = QWeakPointer( new XMPPBot( this ) ); -#endif - tDebug( LOGINFO ) << "Connecting SIP classes"; Accounts::AccountManager::instance()->initSIP(); } diff --git a/src/TomahawkApp.h b/src/TomahawkApp.h index a1c6f0724..417bc3094 100644 --- a/src/TomahawkApp.h +++ b/src/TomahawkApp.h @@ -64,7 +64,7 @@ namespace Tomahawk } #ifdef LIBLASTFM_FOUND -#include +#include #include "Scrobbler.h" #endif @@ -115,6 +115,7 @@ private slots: void accountManagerReady(); private: + void installTranslator(); void registerMetaTypes(); void printHelp(); diff --git a/src/TomahawkTrayIcon.cpp b/src/TomahawkTrayIcon.cpp index 7fd9955ed..edcf2483c 100644 --- a/src/TomahawkTrayIcon.cpp +++ b/src/TomahawkTrayIcon.cpp @@ -40,8 +40,14 @@ TomahawkTrayIcon::TomahawkTrayIcon( QObject* parent ) , m_currentAnimationFrame( 0 ) , m_showWindowAction( 0 ) , m_stopContinueAfterTrackAction( 0 ) + , m_loveTrackAction( 0 ) { +#ifdef Q_WS_MAC QIcon icon( RESPATH "icons/tomahawk-icon-128x128-grayscale.png" ); +#else + QIcon icon( RESPATH "icons/tomahawk-icon-128x128.png" ); +#endif + setIcon( icon ); refreshToolTip(); @@ -49,11 +55,14 @@ TomahawkTrayIcon::TomahawkTrayIcon( QObject* parent ) m_contextMenu = new QMenu(); setContextMenu( m_contextMenu ); - m_stopContinueAfterTrackAction = new QAction( tr( "&Stop Playback after current Track" ), this ); + m_loveTrackAction = new QAction( this ); + m_stopContinueAfterTrackAction = new QAction( this ); ActionCollection *ac = ActionCollection::instance(); m_contextMenu->addAction( ac->getAction( "playPause" ) ); m_contextMenu->addAction( ac->getAction( "stop" ) ); + m_contextMenu->addSeparator(); + m_contextMenu->addAction( m_loveTrackAction ); m_contextMenu->addAction( m_stopContinueAfterTrackAction ); m_contextMenu->addSeparator(); m_contextMenu->addAction( ac->getAction( "previousTrack" ) ); @@ -61,8 +70,6 @@ TomahawkTrayIcon::TomahawkTrayIcon( QObject* parent ) m_contextMenu->addSeparator(); m_contextMenu->addAction( ActionCollection::instance()->getAction( "togglePrivacy" ) ); - connect( m_stopContinueAfterTrackAction, SIGNAL( triggered(bool) ), this, SLOT( stopContinueAfterTrackActionTriggered() ) ); - #ifdef Q_WS_MAC // On mac you can close the windows while leaving the app open. We then need a way to show the main window again m_contextMenu->addSeparator(); @@ -76,16 +83,20 @@ TomahawkTrayIcon::TomahawkTrayIcon( QObject* parent ) m_contextMenu->addSeparator(); m_contextMenu->addAction( ac->getAction( "quit" ) ); + connect( m_loveTrackAction, SIGNAL( triggered() ), SLOT( loveTrackTriggered() ) ); + connect( m_stopContinueAfterTrackAction, SIGNAL( triggered() ), SLOT( stopContinueAfterTrackActionTriggered() ) ); + connect( AudioEngine::instance(), SIGNAL( loading( Tomahawk::result_ptr ) ), SLOT( setResult( Tomahawk::result_ptr ) ) ); connect( AudioEngine::instance(), SIGNAL( started( Tomahawk::result_ptr ) ), SLOT( onPlay() ) ); - connect( AudioEngine::instance(), SIGNAL( resumed() ), this, SLOT( onResume() ) ); - connect( AudioEngine::instance(), SIGNAL( stopped() ), this, SLOT( onStop() ) ); - connect( AudioEngine::instance(), SIGNAL( paused() ), this, SLOT( onPause() ) ); - connect( AudioEngine::instance(), SIGNAL( stopAfterTrack_changed() ) , this, SLOT( stopContinueAfterTrack_StatusChanged() ) ); + connect( AudioEngine::instance(), SIGNAL( resumed() ), SLOT( onResume() ) ); + connect( AudioEngine::instance(), SIGNAL( stopped() ), SLOT( onStop() ) ); + connect( AudioEngine::instance(), SIGNAL( paused() ), SLOT( onPause() ) ); + connect( AudioEngine::instance(), SIGNAL( stopAfterTrackChanged() ), SLOT( onStopContinueAfterTrackChanged() ) ); connect( &m_animationTimer, SIGNAL( timeout() ), SLOT( onAnimationTimer() ) ); connect( this, SIGNAL( activated( QSystemTrayIcon::ActivationReason ) ), SLOT( onActivated( QSystemTrayIcon::ActivationReason ) ) ); + onStop(); show(); } @@ -145,8 +156,29 @@ TomahawkTrayIcon::menuAboutToShow() void TomahawkTrayIcon::setResult( const Tomahawk::result_ptr& result ) { + if ( m_currentTrack ) + { + disconnect( m_currentTrack->toQuery().data(), SIGNAL( socialActionsLoaded() ), this, SLOT( onSocialActionsLoaded() ) ); + } + m_currentTrack = result; refreshToolTip(); + + if ( result ) + connect( result->toQuery().data(), SIGNAL( socialActionsLoaded() ), SLOT( onSocialActionsLoaded() ), Qt::UniqueConnection ); + + onSocialActionsLoaded(); + onStopContinueAfterTrackChanged(); +} + + +void +TomahawkTrayIcon::onStopContinueAfterTrackChanged() +{ + if ( m_currentTrack && m_currentTrack->toQuery()->equals( AudioEngine::instance()->stopAfterTrack() ) ) + m_stopContinueAfterTrackAction->setText( tr( "&Continue Playback after current Track" ) ); + else + m_stopContinueAfterTrackAction->setText( tr( "&Stop Playback after current Track" ) ); } @@ -234,16 +266,20 @@ TomahawkTrayIcon::onPause() void TomahawkTrayIcon::onPlay() { + m_loveTrackAction->setEnabled( true ); m_stopContinueAfterTrackAction->setEnabled( true ); + onResume(); - stopContinueAfterTrack_StatusChanged(); } void TomahawkTrayIcon::onStop() { + m_loveTrackAction->setEnabled( false ); m_stopContinueAfterTrackAction->setEnabled( false ); + + setResult( Tomahawk::result_ptr() ); onPause(); } @@ -256,26 +292,41 @@ TomahawkTrayIcon::onResume() void -TomahawkTrayIcon::stopContinueAfterTrack_StatusChanged() +TomahawkTrayIcon::loveTrackTriggered() { - if ( !AudioEngine::instance()->currentTrack().isNull() ) - { - if ( AudioEngine::instance()->currentTrack()->toQuery()->equals( AudioEngine::instance()->stopAfterTrack() ) ) - m_stopContinueAfterTrackAction->setText( tr( "&Continue Playback after current Track" ) ); - else - m_stopContinueAfterTrackAction->setText( tr( "&Stop Playback after current Track" ) ); - } + if ( !m_currentTrack ) + return; + + m_currentTrack->toQuery()->setLoved( !m_currentTrack->toQuery()->loved() ); } -void TomahawkTrayIcon::stopContinueAfterTrackActionTriggered() +void +TomahawkTrayIcon::stopContinueAfterTrackActionTriggered() { - if ( !AudioEngine::instance()->currentTrack().isNull() ) + if ( !m_currentTrack ) + return; + + if ( !m_currentTrack->toQuery()->equals( AudioEngine::instance()->stopAfterTrack() ) ) + AudioEngine::instance()->setStopAfterTrack( m_currentTrack->toQuery() ); + else + AudioEngine::instance()->setStopAfterTrack( Tomahawk::query_ptr() ); +} + + +void +TomahawkTrayIcon::onSocialActionsLoaded() +{ + m_loveTrackAction->setText( tr( "&Love" ) ); + m_loveTrackAction->setIcon( QIcon( RESPATH "images/loved.png" ) ); + + if ( !m_currentTrack ) + return; + + if ( m_currentTrack->toQuery()->loved() ) { - if ( !AudioEngine::instance()->currentTrack()->toQuery()->equals( AudioEngine::instance()->stopAfterTrack() ) ) - AudioEngine::instance()->setStopAfterTrack( AudioEngine::instance()->currentTrack()->toQuery() ); - else - AudioEngine::instance()->setStopAfterTrack( Tomahawk::query_ptr() ); + m_loveTrackAction->setText( tr( "Un-&Love" ) ); + m_loveTrackAction->setIcon( QIcon( RESPATH "images/not-loved.png" ) ); } } @@ -301,4 +352,3 @@ TomahawkTrayIcon::event( QEvent* e ) return QSystemTrayIcon::event( e ); } - diff --git a/src/TomahawkTrayIcon.h b/src/TomahawkTrayIcon.h index d1504e835..31984492b 100644 --- a/src/TomahawkTrayIcon.h +++ b/src/TomahawkTrayIcon.h @@ -49,11 +49,13 @@ private slots: void onStop(); void onResume(); - void stopContinueAfterTrack_StatusChanged(); - + void onSocialActionsLoaded(); + void onStopContinueAfterTrackChanged(); void stopContinueAfterTrackActionTriggered(); + void loveTrackTriggered(); void menuAboutToShow(); + private: void refreshToolTip(); ~TomahawkTrayIcon(); @@ -68,6 +70,7 @@ private: QAction* m_showWindowAction; QAction* m_stopContinueAfterTrackAction; + QAction* m_loveTrackAction; }; #endif // TOMAHAWK_TRAYICON_H diff --git a/src/TomahawkWindow.cpp b/src/TomahawkWindow.cpp index 355ca6041..83db1ba4e 100644 --- a/src/TomahawkWindow.cpp +++ b/src/TomahawkWindow.cpp @@ -35,14 +35,12 @@ #include #include -#include "Playlist.h" -#include "Query.h" -#include "Artist.h" -#include "ViewManager.h" #include "accounts/AccountManager.h" #include "sourcetree/SourceTreeView.h" #include "network/Servent.h" +#include "utils/TomahawkUtilsGui.h" #include "utils/ProxyStyle.h" +#include "utils/WidgetDragFilter.h" #include "widgets/AnimatedSplitter.h" #include "widgets/NewPlaylistWidget.h" #include "widgets/SearchWidget.h" @@ -52,27 +50,31 @@ #include "playlist/PlaylistModel.h" #include "playlist/PlaylistView.h" #include "playlist/QueueView.h" +#include "jobview/JobStatusView.h" +#include "jobview/JobStatusModel.h" +#include "jobview/ErrorStatusMessage.h" +#include "jobview/JobStatusModel.h" +#include "Playlist.h" +#include "Query.h" +#include "Artist.h" +#include "ViewManager.h" +#include "ActionCollection.h" #include "AudioControls.h" #include "SettingsDialog.h" #include "DiagnosticsDialog.h" #include "TomahawkSettings.h" #include "SourceList.h" -#include "jobview/JobStatusView.h" -#include "jobview/JobStatusModel.h" -#include "jobview/ErrorStatusMessage.h" #include "TomahawkTrayIcon.h" #include "ScanManager.h" #include "TomahawkApp.h" +#include "LoadXSPFDialog.h" #ifdef Q_WS_WIN #include #endif #include "utils/Logger.h" -#include "jobview/JobStatusModel.h" -#include "LoadXSPFDialog.h" -#include using namespace Tomahawk; using namespace Accounts; @@ -118,6 +120,8 @@ TomahawkWindow::TomahawkWindow( QWidget* parent ) // set initial state onAccountDisconnected(); + audioStopped(); + vm->setQueue( m_queueView ); vm->showWelcomePage(); } @@ -156,11 +160,12 @@ TomahawkWindow::loadSettings() restoreState( s->mainWindowState() ); if ( !s->mainWindowSplitterState().isEmpty() ) ui->splitter->restoreState( s->mainWindowSplitterState() ); - else - { - ui->splitter->setStretchFactor( 0, 0 ); - ui->splitter->setStretchFactor( 1, 1 ); - } + + // Always set stretch factor. If user hasn't manually set splitter sizes, + // this will ensure a sane default on all startups. If the user has, the manual + // size will override the default stretching + ui->splitter->setStretchFactor( 0, 0 ); + ui->splitter->setStretchFactor( 1, 1 ); #ifdef QT_MAC_USE_COCOA if ( workaround ) @@ -191,7 +196,7 @@ TomahawkWindow::applyPlatformTweaks() if ( !QString( qApp->style()->metaObject()->className() ).toLower().contains( "qtcurve" ) ) qApp->setStyle( new ProxyStyle() ); -#ifdef Q_WS_MAC +#ifdef Q_OS_MAC setUnifiedTitleAndToolBarOnMac( true ); delete ui->hline1; delete ui->hline2; @@ -211,7 +216,12 @@ TomahawkWindow::setupToolBar() toolbar->setFloatable( false ); toolbar->setIconSize( QSize( 22, 22 ) ); toolbar->setToolButtonStyle( Qt::ToolButtonIconOnly ); - + toolbar->setStyleSheet( "border-bottom: 0px" ); + +#ifdef Q_OS_MAC + toolbar->installEventFilter( new WidgetDragFilter( toolbar ) ); +#endif + m_backAction = toolbar->addAction( QIcon( RESPATH "images/back.png" ), tr( "Back" ), ViewManager::instance(), SLOT( historyBack() ) ); m_backAction->setToolTip( tr( "Go back one page" ) ); m_forwardAction = toolbar->addAction( QIcon( RESPATH "images/forward.png" ), tr( "Forward" ), ViewManager::instance(), SLOT( historyForward() ) ); @@ -251,10 +261,6 @@ TomahawkWindow::setupSideBar() jobsView->setModel( m_jobsModel ); m_queueView = new QueueView( m_sidebar ); - m_queueModel = new PlaylistModel( m_queueView ); - m_queueModel->setStyle( PlaylistModel::Short ); - m_queueView->queue()->setPlaylistModel( m_queueModel ); - m_queueView->queue()->playlistModel()->setReadOnly( false ); AudioEngine::instance()->setQueue( m_queueView->queue()->proxyModel()->playlistInterface() ); m_sidebar->addWidget( m_sourcetree ); @@ -271,7 +277,7 @@ TomahawkWindow::setupSideBar() sidebarWidget->layout()->setContentsMargins( 0, 0, 0, 0 ); sidebarWidget->layout()->setMargin( 0 ); -#ifndef Q_WS_MAC +#ifndef Q_OS_MAC sidebarWidget->layout()->setSpacing( 0 ); #endif @@ -286,11 +292,11 @@ TomahawkWindow::setupSideBar() void TomahawkWindow::setupUpdateCheck() { -#ifndef Q_WS_MAC +#ifndef Q_OS_MAC ui->menu_Help->insertSeparator( ui->actionAboutTomahawk ); #endif -#if defined( Q_WS_MAC ) && defined( HAVE_SPARKLE ) +#if defined( Q_OS_MAC ) && defined( HAVE_SPARKLE ) QAction* checkForUpdates = ui->menu_Help->addAction( tr( "Check For Updates..." ) ); checkForUpdates->setMenuRole( QAction::ApplicationSpecificRole ); connect( checkForUpdates, SIGNAL( triggered( bool ) ), SLOT( checkForUpdates() ) ); @@ -328,7 +334,7 @@ TomahawkWindow::setupSignals() connect( AudioEngine::instance(), SIGNAL( loading( const Tomahawk::result_ptr& ) ), SLOT( onPlaybackLoading( const Tomahawk::result_ptr& ) ) ); connect( AudioEngine::instance(), SIGNAL( started( Tomahawk::result_ptr ) ), SLOT( audioStarted() ) ); connect( AudioEngine::instance(), SIGNAL( resumed()), SLOT( audioStarted() ) ); - connect( AudioEngine::instance(), SIGNAL( paused() ), SLOT( audioStopped() ) ); + connect( AudioEngine::instance(), SIGNAL( paused() ), SLOT( audioPaused() ) ); connect( AudioEngine::instance(), SIGNAL( stopped() ), SLOT( audioStopped() ) ); // @@ -349,7 +355,7 @@ TomahawkWindow::setupSignals() connect( ui->actionNext, SIGNAL( triggered() ), AudioEngine::instance(), SLOT( next() ) ); connect( ui->actionPrevious, SIGNAL( triggered() ), AudioEngine::instance(), SLOT( previous() ) ); -#if defined( Q_WS_MAC ) +#if defined( Q_OS_MAC ) connect( ui->actionMinimize, SIGNAL( triggered() ), SLOT( minimize() ) ); connect( ui->actionZoom, SIGNAL( triggered() ), SLOT( maximize() ) ); #else @@ -398,7 +404,7 @@ TomahawkWindow::changeEvent( QEvent* e ) void TomahawkWindow::closeEvent( QCloseEvent* e ) { -#ifndef Q_WS_MAC +#ifndef Q_OS_MAC if ( e->spontaneous() && QSystemTrayIcon::isSystemTrayAvailable() ) { hide(); @@ -418,7 +424,7 @@ TomahawkWindow::showEvent( QShowEvent* e ) { QMainWindow::showEvent( e ); -#if defined( Q_WS_MAC ) +#if defined( Q_OS_MAC ) ui->actionMinimize->setDisabled( false ); ui->actionZoom->setDisabled( false ); #endif @@ -430,7 +436,7 @@ TomahawkWindow::hideEvent( QHideEvent* e ) { QMainWindow::hideEvent( e ); -#if defined( Q_WS_MAC ) +#if defined( Q_OS_MAC ) ui->actionMinimize->setDisabled( true ); ui->actionZoom->setDisabled( true ); #endif @@ -441,7 +447,7 @@ void TomahawkWindow::keyPressEvent( QKeyEvent* e ) { bool accept = true; -#if ! defined ( Q_WS_MAC ) +#if ! defined ( Q_OS_MAC ) #define KEY_PRESSED Q_FUNC_INFO << "Multimedia Key Pressed:" switch( e->key() ) { @@ -589,11 +595,25 @@ TomahawkWindow::showOfflineSources() } +void +TomahawkWindow::fullScreenEntered() +{ + statusBar()->setSizeGripEnabled( false ); +} + + +void +TomahawkWindow::fullScreenExited() +{ + statusBar()->setSizeGripEnabled( true ); +} + + void TomahawkWindow::loadSpiff() { LoadXSPFDialog* diag = new LoadXSPFDialog( this, Qt::Sheet ); -#ifdef Q_WS_MAC +#ifdef Q_OS_MAC connect( diag, SIGNAL( finished( int ) ), this, SLOT( loadXspfFinished( int ) ) ); diag->show(); #else @@ -679,18 +699,18 @@ TomahawkWindow::onAudioEngineError( AudioEngine::AudioErrorCode /* error */ ) void TomahawkWindow::createAutomaticPlaylist( QString playlistName ) { - QString name = playlistName; - - if ( name.isEmpty() ) + if ( playlistName.isEmpty() ) return; source_ptr author = SourceList::instance()->getLocal(); QString id = uuid(); QString info = ""; // FIXME QString creator = "someone"; // FIXME - dynplaylist_ptr playlist = DynamicPlaylist::create( author, id, name, info, creator, Static, false ); + + dynplaylist_ptr playlist = DynamicPlaylist::create( author, id, playlistName, info, creator, Static, false ); playlist->setMode( Static ); playlist->createNewRevision( uuid(), playlist->currentrevision(), playlist->type(), playlist->generator()->controls(), playlist->entries() ); + ViewManager::instance()->show( playlist ); } @@ -698,18 +718,36 @@ TomahawkWindow::createAutomaticPlaylist( QString playlistName ) void TomahawkWindow::createStation() { + QString title = tr( "Station" ); bool ok; - QString name = QInputDialog::getText( this, tr( "Create New Station" ), tr( "Name:" ), QLineEdit::Normal, tr( "New Station" ), &ok ); - if ( !ok || name.isEmpty() ) + QString playlistName = QInputDialog( this, Qt::Sheet ).getText( this, tr( "Create New Station" ), tr( "Name:" ), QLineEdit::Normal, title, &ok ); + if ( !ok ) return; + if ( playlistName.isEmpty() || playlistName == title ) + { + QList< dynplaylist_ptr > pls = SourceList::instance()->getLocal()->collection()->stations(); + QStringList titles; + foreach ( const playlist_ptr& pl, pls ) + titles << pl->title(); + + playlistName = title; + int i = 2; + while ( titles.contains( playlistName ) ) + { + playlistName = QString( "%1 (%2)" ).arg( title ).arg( i++ ); + } + } + source_ptr author = SourceList::instance()->getLocal(); QString id = uuid(); QString info = ""; // FIXME QString creator = "someone"; // FIXME - dynplaylist_ptr playlist = DynamicPlaylist::create( author, id, name, info, creator, OnDemand, false ); + + dynplaylist_ptr playlist = DynamicPlaylist::create( author, id, playlistName, info, creator, OnDemand, false ); playlist->setMode( OnDemand ); playlist->createNewRevision( uuid(), playlist->currentrevision(), playlist->type(), playlist->generator()->controls() ); + ViewManager::instance()->show( playlist ); } @@ -718,11 +756,12 @@ void TomahawkWindow::createPlaylist() { PlaylistTypeSelectorDlg* playlistSelectorDlg = new PlaylistTypeSelectorDlg( TomahawkApp::instance()->mainWindow(), Qt::Sheet ); -#ifndef Q_WS_MAC + +#ifndef Q_OS_MAC playlistSelectorDlg->setModal( true ); #endif - connect( playlistSelectorDlg, SIGNAL( finished( int ) ), this, SLOT( playlistCreateDialogFinished( int ) ) ); + connect( playlistSelectorDlg, SIGNAL( finished( int ) ), SLOT( playlistCreateDialogFinished( int ) ) ); playlistSelectorDlg->show(); } @@ -734,17 +773,50 @@ TomahawkWindow::playlistCreateDialogFinished( int ret ) Q_ASSERT( playlistSelectorDlg ); QString playlistName = playlistSelectorDlg->playlistName(); - if ( playlistName.isEmpty() ) - playlistName = tr( "New Playlist" ); - if ( !playlistSelectorDlg->playlistTypeIsAuto() && ret ) { + if ( !playlistSelectorDlg->playlistTypeIsAuto() && ret ) + { + if ( playlistName.isEmpty() ) + { + QList< playlist_ptr > pls = SourceList::instance()->getLocal()->collection()->playlists(); + QStringList titles; + foreach ( const playlist_ptr& pl, pls ) + titles << pl->title(); + + QString title = tr( "Playlist" ); + playlistName = title; + int i = 2; + while ( titles.contains( playlistName ) ) + { + playlistName = QString( "%1 (%2)" ).arg( title ).arg( i++ ); + } + } playlist_ptr playlist = Tomahawk::Playlist::create( SourceList::instance()->getLocal(), uuid(), playlistName, "", "", false, QList< query_ptr>() ); ViewManager::instance()->show( playlist ); - } else if ( playlistSelectorDlg->playlistTypeIsAuto() && ret ) { + } + else if ( playlistSelectorDlg->playlistTypeIsAuto() && ret ) + { // create Auto Playlist + if ( playlistName.isEmpty() ) + { + QList< dynplaylist_ptr > pls = SourceList::instance()->getLocal()->collection()->autoPlaylists(); + QStringList titles; + foreach ( const dynplaylist_ptr& pl, pls ) + titles << pl->title(); + + QString title = tr( "Automatic Playlist" ); + playlistName = title; + int i = 2; + while ( titles.contains( playlistName ) ) + { + playlistName = QString( "%1 (%2)" ).arg( title ).arg( i++ ); + } + } + createAutomaticPlaylist( playlistName ); } + playlistSelectorDlg->deleteLater(); } @@ -753,21 +825,27 @@ void TomahawkWindow::audioStarted() { m_audioRetryCounter = 0; + ui->actionPlay->setText( tr( "Pause" ) ); + ActionCollection::instance()->getAction( "stop" )->setEnabled( true ); +} + + +void +TomahawkWindow::audioPaused() +{ + ui->actionPlay->setText( tr( "Play" ) ); } void TomahawkWindow::audioStopped() { - ui->actionPlay->setText( tr( "Play" ) ); + audioPaused(); + ActionCollection::instance()->getAction( "stop" )->setEnabled( false ); - tDebug() << Q_FUNC_INFO << AudioEngine::instance()->isStopped(); - if ( AudioEngine::instance()->isStopped() ) - { - m_currentTrack = result_ptr(); - setWindowTitle( m_windowTitle ); - } + m_currentTrack = result_ptr(); + setWindowTitle( m_windowTitle ); } @@ -847,8 +925,13 @@ TomahawkWindow::showAboutTomahawk() .arg( TomahawkUtils::appFriendlyVersion() ); #endif - desc = tr( "Copyright 2010 - 2012
Christian Muehlhaeuser <muesli@tomahawk-player.org>

" - "Thanks to: Leo Franchi, Jeff Mitchell, Dominik Schmidt, Jason Herskowitz, Alejandro Wainzinger, Hugo Lindström, Michael Zanetti, Harald Sitter and Steve Robertson" ); + const QString copyright( tr( "Copyright 2010 - 2012" ) ); + const QString thanksto( tr( "Thanks to:" ) ); + + desc = QString( "%1
Christian Muehlhaeuser <muesli@tomahawk-player.org>

" + "%2 Leo Franchi, Jeff Mitchell, Dominik Schmidt, Jason Herskowitz, Alejandro Wainzinger, Hugo Lindström, Syd Lawrence, Michael Zanetti, Harald Sitter, Steve Robertson" ) + .arg( copyright ) + .arg( thanksto ); QMessageBox::about( this, tr( "About Tomahawk" ), head + desc ); } @@ -857,7 +940,7 @@ TomahawkWindow::showAboutTomahawk() void TomahawkWindow::checkForUpdates() { -#ifdef Q_WS_MAC +#ifdef Q_OS_MAC Tomahawk::checkForUpdates(); #endif } diff --git a/src/TomahawkWindow.h b/src/TomahawkWindow.h index d0f0cdaa1..dee2122ff 100644 --- a/src/TomahawkWindow.h +++ b/src/TomahawkWindow.h @@ -88,6 +88,9 @@ public slots: void pluginMenuRemoved(QMenu*); void showOfflineSources(); + void fullScreenEntered(); + void fullScreenExited(); + private slots: void onAccountAdded( Tomahawk::Accounts::Account* account ); void onAccountConnected(); @@ -107,6 +110,7 @@ private slots: void onPlaybackLoading( const Tomahawk::result_ptr& result ); void audioStarted(); + void audioPaused(); void audioStopped(); void showAboutTomahawk(); @@ -144,7 +148,6 @@ private: SourceTreeView* m_sourcetree; QPushButton* m_statusButton; QPushButton* m_queueButton; - PlaylistModel* m_queueModel; QueueView* m_queueView; AnimatedSplitter* m_sidebar; JobStatusModel* m_jobsModel; diff --git a/src/accounts/twitter/TwitterAccount.cpp b/src/accounts/twitter/TwitterAccount.cpp index 91dce3ca1..852968c31 100644 --- a/src/accounts/twitter/TwitterAccount.cpp +++ b/src/accounts/twitter/TwitterAccount.cpp @@ -130,7 +130,6 @@ TwitterAccount::authenticateSlot() { infoPlugin().data()->moveToThread( Tomahawk::InfoSystem::InfoSystem::instance()->workerThread().data() ); Tomahawk::InfoSystem::InfoSystem::instance()->addInfoPlugin( infoPlugin() ); - QMetaObject::invokeMethod( infoPlugin().data(), "init", Qt::QueuedConnection ); } } diff --git a/src/accounts/twitter/TwitterInfoPlugin.cpp b/src/accounts/twitter/TwitterInfoPlugin.cpp index 39e375f0a..add608f33 100644 --- a/src/accounts/twitter/TwitterInfoPlugin.cpp +++ b/src/accounts/twitter/TwitterInfoPlugin.cpp @@ -76,15 +76,15 @@ TwitterInfoPlugin::~TwitterInfoPlugin() bool TwitterInfoPlugin::refreshTwitterAuth() { - tDebug() << Q_FUNC_INFO << " begin" << this; - if( !m_twitterAuth.isNull() ) + tDebug() << Q_FUNC_INFO << "begin" << this; + if ( !m_twitterAuth.isNull() ) delete m_twitterAuth.data(); Q_ASSERT( TomahawkUtils::nam() != 0 ); - tDebug() << Q_FUNC_INFO << " with nam " << TomahawkUtils::nam() << this; + tDebug() << Q_FUNC_INFO << "with nam" << TomahawkUtils::nam() << this; m_twitterAuth = QWeakPointer< TomahawkOAuthTwitter >( new TomahawkOAuthTwitter( TomahawkUtils::nam(), this ) ); - if( m_twitterAuth.isNull() ) + if ( m_twitterAuth.isNull() ) return false; m_twitterAuth.data()->setOAuthToken( m_account->credentials()[ "oauthtoken" ].toString().toLatin1() ); @@ -138,7 +138,8 @@ TwitterInfoPlugin::pushInfo( Tomahawk::InfoSystem::InfoPushData pushData ) return; } - if ( !map[ "accountlist" ].toStringList().contains( m_account->accountId() ) ) + const QStringList accountList = map[ "accountlist" ].toStringList(); + if ( !accountList.contains( "all" ) && !accountList.contains( m_account->accountId() ) ) { tLog( LOGVERBOSE ) << Q_FUNC_INFO << "Our account not in the list, not tweeting out"; return; @@ -168,7 +169,7 @@ TwitterInfoPlugin::pushInfo( Tomahawk::InfoSystem::InfoPushData pushData ) QTweetStatusUpdate *statUpdate = new QTweetStatusUpdate( m_twitterAuth.data(), this ); connect( statUpdate, SIGNAL( postedStatus(const QTweetStatus &) ), SLOT( postLovedStatusUpdateReply(const QTweetStatus &) ) ); connect( statUpdate, SIGNAL( error(QTweetNetBase::ErrorCode, const QString&) ), SLOT( postLovedStatusUpdateError(QTweetNetBase::ErrorCode, const QString &) ) ); - tDebug() << Q_FUNC_INFO << "Posting message: " << msg; + tDebug() << Q_FUNC_INFO << "Posting message:" << msg; statUpdate->post( msg ); } diff --git a/src/accounts/twitter/TwitterInfoPlugin.h b/src/accounts/twitter/TwitterInfoPlugin.h index e1b221105..0919515b7 100644 --- a/src/accounts/twitter/TwitterInfoPlugin.h +++ b/src/accounts/twitter/TwitterInfoPlugin.h @@ -44,7 +44,6 @@ namespace Tomahawk { virtual ~TwitterInfoPlugin(); public slots: - void init(); void notInCacheSlot( const Tomahawk::InfoSystem::InfoStringHash criteria, Tomahawk::InfoSystem::InfoRequestData requestData ) { Q_UNUSED( criteria ); @@ -52,6 +51,7 @@ namespace Tomahawk { } protected slots: + void init(); void pushInfo( Tomahawk::InfoSystem::InfoPushData pushData ); void getInfo( Tomahawk::InfoSystem::InfoRequestData requestData ) { diff --git a/src/accounts/xmpp/XmppInfoPlugin.h b/src/accounts/xmpp/XmppInfoPlugin.h index f553b43d0..cbb248e6d 100644 --- a/src/accounts/xmpp/XmppInfoPlugin.h +++ b/src/accounts/xmpp/XmppInfoPlugin.h @@ -42,10 +42,10 @@ namespace Tomahawk { void publishTune( QUrl url, Tomahawk::InfoSystem::InfoStringHash trackInfo ); public slots: - void init(); void notInCacheSlot( const Tomahawk::InfoSystem::InfoStringHash criteria, Tomahawk::InfoSystem::InfoRequestData requestData ); protected slots: + void init(); void pushInfo( Tomahawk::InfoSystem::InfoPushData pushData ); void getInfo( Tomahawk::InfoSystem::InfoRequestData requestData ); diff --git a/src/accounts/xmpp/sip/AvatarManager.cpp b/src/accounts/xmpp/sip/AvatarManager.cpp index 2c1eff6d0..9ff1d26bf 100644 --- a/src/accounts/xmpp/sip/AvatarManager.cpp +++ b/src/accounts/xmpp/sip/AvatarManager.cpp @@ -33,47 +33,51 @@ #include "utils/Logger.h" -AvatarManager::AvatarManager(Jreen::Client *client) : - m_cacheDir(TomahawkUtils::appDataDir().absolutePath().append("/jreen/")) +AvatarManager::AvatarManager( Jreen::Client* client ) + : m_cacheDir( TomahawkUtils::appDataDir().absolutePath().append( "/jreen/" ) ) { m_client = client; - m_cachedAvatars = m_cacheDir.entryList(); - connect(m_client, SIGNAL(serverFeaturesReceived(QSet)), SLOT(onNewConnection())); - connect(m_client, SIGNAL(presenceReceived(Jreen::Presence)), SLOT(onNewPresence(Jreen::Presence))); - connect(m_client, SIGNAL(iqReceived(Jreen::IQ)), SLOT(onNewIq(Jreen::IQ))); + connect( m_client, SIGNAL( serverFeaturesReceived( QSet ) ), SLOT( onNewConnection() ) ); + connect( m_client, SIGNAL( presenceReceived( Jreen::Presence ) ), SLOT( onNewPresence( Jreen::Presence ) ) ); + connect( m_client, SIGNAL( iqReceived( Jreen::IQ ) ), SLOT( onNewIq( Jreen::IQ ) ) ); - connect(this, SIGNAL(newAvatar(QString)), SLOT(onNewAvatar(QString))); + connect( this, SIGNAL( newAvatar( QString ) ), SLOT( onNewAvatar( QString ) ) ); } + AvatarManager::~AvatarManager() { } -void AvatarManager::onNewConnection() + +void +AvatarManager::onNewConnection() { fetchVCard( m_client->jid().bare() ); } -void AvatarManager::fetchVCard(const QString &jid) +void +AvatarManager::fetchVCard( const QString& jid ) { -// qDebug() << Q_FUNC_INFO; + Jreen::IQ iq( Jreen::IQ::Get, jid ); + iq.addExtension( new Jreen::VCard() ); + Jreen::IQReply *reply = m_client->send( iq ); - Jreen::IQ iq(Jreen::IQ::Get, jid ); - iq.addExtension(new Jreen::VCard()); - Jreen::IQReply *reply = m_client->send(iq); - connect(reply, SIGNAL(received(Jreen::IQ)), SLOT(onNewIq(Jreen::IQ))); + connect( reply, SIGNAL( received( Jreen::IQ ) ), SLOT( onNewIq( Jreen::IQ ) ) ); } -void AvatarManager::onNewPresence(const Jreen::Presence& presence) + +void +AvatarManager::onNewPresence( const Jreen::Presence& presence ) { Jreen::VCardUpdate::Ptr update = presence.payload(); - if(update) + if ( update ) { // qDebug() << "vcard: found update for" << presence.from().full(); - if(!isCached(update->photoHash())) + if ( !isCached( update->photoHash() ) ) { // qDebug() << presence.from().full() << "vcard: photo not cached, starting request..." << update->photoHash(); fetchVCard( presence.from().bare() ); @@ -84,78 +88,72 @@ void AvatarManager::onNewPresence(const Jreen::Presence& presence) m_JidsAvatarHashes.insert( update->photoHash(), presence.from().bare() ); if ( !this->avatar( presence.from().bare() ).isNull() ) - emit newAvatar(presence.from().bare()); + emit newAvatar( presence.from().bare() ); } } else { -// qDebug() << Q_FUNC_INFO << presence.from().full() << "got no statusupdateextension"; - //TODO: do we want this? might fetch avatars for broken clients fetchVCard( presence.from().bare() ); } } -void AvatarManager::onNewIq(const Jreen::IQ& iq) + +void +AvatarManager::onNewIq( const Jreen::IQ& iq ) { Jreen::VCard::Ptr vcard = iq.payload(); - if(vcard) + if ( vcard ) { iq.accept(); - // qDebug() << Q_FUNC_INFO << "Got vcard from " << iq.from().full(); QString id = iq.from().full(); QString avatarHash; const Jreen::VCard::Photo &photo = vcard->photo(); - if (!photo.data().isEmpty()) { + if ( !photo.data().isEmpty() ) + { // qDebug() << "vcard: got photo data" << id; - avatarHash = QCryptographicHash::hash(photo.data(), QCryptographicHash::Sha1).toHex(); + avatarHash = QCryptographicHash::hash( photo.data(), QCryptographicHash::Sha1 ).toHex(); - if (!m_cacheDir.exists()) + if ( !m_cacheDir.exists() ) m_cacheDir.mkpath( avatarDir( avatarHash ).absolutePath() ); - - QFile file(avatarPath(avatarHash)); - if (file.open(QIODevice::WriteOnly)) { - file.write(photo.data()); + QFile file( avatarPath( avatarHash ) ); + if ( file.open( QIODevice::WriteOnly ) ) + { + file.write( photo.data() ); file.close(); } - m_cachedAvatars.append(avatarHash); + m_cachedAvatars.append( avatarHash ); m_JidsAvatarHashes.insert( avatarHash, iq.from().bare() ); - Q_ASSERT(!this->avatar(iq.from().bare()).isNull()); - emit newAvatar(iq.from().bare()); - } - else - { -// qDebug() << "vcard: got no photo data" << id; + Q_ASSERT( !this->avatar( iq.from().bare() ).isNull() ); + emit newAvatar( iq.from().bare() ); } // got own presence if ( m_client->jid().bare() == id ) { -// qDebug() << Q_FUNC_INFO << "got own vcard"; - Jreen::Presence presence = m_client->presence(); Jreen::VCardUpdate::Ptr update = presence.payload(); - if (update->photoHash() != avatarHash) + if ( update->photoHash() != avatarHash ) { - qDebug() << Q_FUNC_INFO << "Updating own presence..."; - - update->setPhotoHash(avatarHash); - m_client->send(presence); + update->setPhotoHash( avatarHash ); + m_client->send( presence ); } } } } -QPixmap AvatarManager::avatar(const QString &jid) const + +QPixmap +AvatarManager::avatar( const QString& jid ) const { - if( isCached( avatarHash( jid ) ) ) + if ( isCached( avatarHash( jid ) ) ) { return QPixmap( avatarPath( avatarHash( jid ) ) ); } @@ -165,29 +163,39 @@ QPixmap AvatarManager::avatar(const QString &jid) const } } -QString AvatarManager::avatarHash(const QString &jid) const + +QString +AvatarManager::avatarHash( const QString& jid ) const { - //qDebug() << Q_FUNC_INFO << jid << m_JidsAvatarHashes.key(jid); - return m_JidsAvatarHashes.key(jid); + //qDebug() << Q_FUNC_INFO << jid << m_JidsAvatarHashes.key( jid ); + return m_JidsAvatarHashes.key( jid ); } -QDir AvatarManager::avatarDir(const QString&) const + +QDir +AvatarManager::avatarDir( const QString& /* avatarHash */ ) const { return m_cacheDir; } -QString AvatarManager::avatarPath(const QString &avatarHash) const + +QString +AvatarManager::avatarPath( const QString& avatarHash ) const { - Q_ASSERT(!avatarHash.contains("@")); - return avatarDir(avatarHash).absoluteFilePath(avatarHash); + Q_ASSERT( !avatarHash.contains( "@" ) ); + return avatarDir( avatarHash ).absoluteFilePath( avatarHash ); } -bool AvatarManager::isCached(const QString &avatarHash) const + +bool +AvatarManager::isCached( const QString& avatarHash ) const { return m_cachedAvatars.contains( avatarHash ); } -void AvatarManager::onNewAvatar(const QString&) + +void +AvatarManager::onNewAvatar( const QString& /* jid */ ) { // qDebug() << Q_FUNC_INFO << "Found new Avatar..." << jid; } diff --git a/src/accounts/xmpp/sip/AvatarManager.h b/src/accounts/xmpp/sip/AvatarManager.h index 31ab900cf..a42cee08d 100644 --- a/src/accounts/xmpp/sip/AvatarManager.h +++ b/src/accounts/xmpp/sip/AvatarManager.h @@ -32,32 +32,32 @@ class ACCOUNTDLLEXPORT AvatarManager : public QObject Q_OBJECT public: - AvatarManager(Jreen::Client *client); + AvatarManager(Jreen::Client* client); virtual ~AvatarManager(); - QPixmap avatar(const QString &jid) const; + QPixmap avatar(const QString& jid) const; signals: - void newAvatar( const QString &jid ); + void newAvatar( const QString& jid ); private slots: void onNewPresence( const Jreen::Presence& presence ); - void onNewIq(const Jreen::IQ &iq); + void onNewIq(const Jreen::IQ& iq); void onNewConnection(); - void onNewAvatar( const QString &jid ); + void onNewAvatar( const QString& jid ); private: - void fetchVCard( const QString &jid); - QString avatarHash(const QString &jid) const; - QString avatarPath(const QString &avatarHash) const; + void fetchVCard( const QString& jid ); + QString avatarHash( const QString& jid ) const; + QString avatarPath( const QString& avatarHash ) const; - QDir avatarDir(const QString &avatarHash) const; - bool isCached(const QString &avatarHash) const; + QDir avatarDir( const QString& avatarHash ) const; + bool isCached( const QString& avatarHash ) const; - Jreen::Client *m_client; + Jreen::Client* m_client; QStringList m_cachedAvatars; QDir m_cacheDir; - QMap m_JidsAvatarHashes; + QMap< QString, QString > m_JidsAvatarHashes; }; #endif // AVATARMANAGER_H diff --git a/src/accounts/xmpp/sip/XmppSip.cpp b/src/accounts/xmpp/sip/XmppSip.cpp index 6330d39c8..2c202f589 100644 --- a/src/accounts/xmpp/sip/XmppSip.cpp +++ b/src/accounts/xmpp/sip/XmppSip.cpp @@ -65,27 +65,32 @@ using namespace Accounts; // instead of simply copying this function for another thirdparty lib // please make it a meta-function or a macro and put it in Logger.h. kthxbbq #define JREEN_LOG_INFIX "Jreen" +#define TOMAHAWK_FEATURE QLatin1String( "tomahawk:sip:v1" ) +#define TOMAHAWK_CAP_NODE_NAME QLatin1String( "http://tomahawk-player.org/" ) + + void -JreenMessageHandler(QtMsgType type, const char *msg) +JreenMessageHandler( QtMsgType type, const char *msg ) { - switch (type) + switch ( type ) { case QtDebugMsg: - tDebug(LOGTHIRDPARTY).nospace() << JREEN_LOG_INFIX << ": " << "Debug: " << msg; + tDebug( LOGTHIRDPARTY ).nospace() << JREEN_LOG_INFIX << ": " << "Debug: " << msg; break; case QtWarningMsg: - tDebug(LOGTHIRDPARTY).nospace() << JREEN_LOG_INFIX << ": " << "Warning: " << msg; + tDebug( LOGTHIRDPARTY ).nospace() << JREEN_LOG_INFIX << ": " << "Warning: " << msg; break; case QtCriticalMsg: - tDebug(LOGTHIRDPARTY).nospace() << JREEN_LOG_INFIX << ": " << "Critical: " << msg; + tDebug( LOGTHIRDPARTY ).nospace() << JREEN_LOG_INFIX << ": " << "Critical: " << msg; break; case QtFatalMsg: - tDebug(LOGTHIRDPARTY).nospace() << JREEN_LOG_INFIX << ": " << "Fatal: " << msg; + tDebug( LOGTHIRDPARTY ).nospace() << JREEN_LOG_INFIX << ": " << "Fatal: " << msg; abort(); } } -XmppSipPlugin::XmppSipPlugin( Account *account ) + +XmppSipPlugin::XmppSipPlugin( Account* account ) : SipPlugin( account ) , m_state( Account::Disconnected ) #ifndef ENABLE_HEADLESS @@ -97,7 +102,6 @@ XmppSipPlugin::XmppSipPlugin( Account *account ) Jreen::Logger::addHandler( JreenMessageHandler ); m_currentUsername = readUsername(); - m_currentServer = readServer(); m_currentPassword = readPassword(); m_currentPort = readPort(); @@ -122,6 +126,7 @@ XmppSipPlugin::XmppSipPlugin( Account *account ) m_xmlConsole->show(); } #endif + // add VCardUpdate extension to own presence m_client->presence().addExtension( new Jreen::VCardUpdate() ); @@ -148,19 +153,19 @@ XmppSipPlugin::XmppSipPlugin( Account *account ) qDebug() << "Our Port set to" << m_client->port(); // setup slots - connect(m_client, SIGNAL(serverFeaturesReceived(QSet)), SLOT(onConnect())); - connect(m_client, SIGNAL(disconnected(Jreen::Client::DisconnectReason)), SLOT(onDisconnect(Jreen::Client::DisconnectReason))); - connect(m_client, SIGNAL(messageReceived(Jreen::Message)), SLOT(onNewMessage(Jreen::Message))); + connect( m_client, SIGNAL( serverFeaturesReceived( QSet ) ), SLOT( onConnect() ) ); + connect( m_client, SIGNAL( disconnected( Jreen::Client::DisconnectReason ) ), SLOT( onDisconnect( Jreen::Client::DisconnectReason ) ) ); + connect( m_client, SIGNAL( messageReceived( Jreen::Message ) ), SLOT( onNewMessage( Jreen::Message ) ) ); - connect(m_client, SIGNAL(iqReceived(Jreen::IQ)), SLOT(onNewIq(Jreen::IQ))); + connect( m_client, SIGNAL( iqReceived( Jreen::IQ ) ), SLOT( onNewIq( Jreen::IQ ) ) ); - connect(m_roster, SIGNAL(presenceReceived(Jreen::RosterItem::Ptr,Jreen::Presence)), - SLOT(onPresenceReceived(Jreen::RosterItem::Ptr,Jreen::Presence))); - connect(m_roster, SIGNAL(subscriptionReceived(Jreen::RosterItem::Ptr,Jreen::Presence)), - SLOT(onSubscriptionReceived(Jreen::RosterItem::Ptr,Jreen::Presence))); + connect( m_roster, SIGNAL( presenceReceived( Jreen::RosterItem::Ptr, Jreen::Presence ) ), + SLOT( onPresenceReceived( Jreen::RosterItem::Ptr, Jreen::Presence ) ) ); + connect( m_roster, SIGNAL( subscriptionReceived( Jreen::RosterItem::Ptr, Jreen::Presence ) ), + SLOT( onSubscriptionReceived( Jreen::RosterItem::Ptr, Jreen::Presence ) ) ); #ifndef ENABLE_HEADLESS - connect(m_avatarManager, SIGNAL(newAvatar(QString)), SLOT(onNewAvatar(QString))); + connect( m_avatarManager, SIGNAL( newAvatar( QString ) ), SLOT( onNewAvatar( QString ) ) ); #endif m_pubSubManager = new Jreen::PubSub::Manager( m_client ); @@ -168,15 +173,16 @@ XmppSipPlugin::XmppSipPlugin( Account *account ) // Clear status Jreen::Tune::Ptr tune( new Jreen::Tune() ); - m_pubSubManager->publishItems(QList() << tune, Jreen::JID()); - + m_pubSubManager->publishItems( QList() << tune, Jreen::JID() ); } + XmppSipPlugin::~XmppSipPlugin() { //Note: the next two lines don't currently work, because the deletion wipes out internally posted events, need to talk to euro about a fix Jreen::Tune::Ptr tune( new Jreen::Tune() ); - m_pubSubManager->publishItems(QList() << tune, Jreen::JID()); + m_pubSubManager->publishItems( QList() << tune, Jreen::JID() ); + delete m_pubSubManager; delete m_avatarManager; delete m_roster; @@ -205,21 +211,20 @@ XmppSipPlugin::menu() } #endif + void XmppSipPlugin::connectPlugin() { - qDebug() << Q_FUNC_INFO; - - if( m_client->isConnected() ) + if ( m_client->isConnected() ) { qDebug() << Q_FUNC_INFO << "Already connected to server, not connecting again..."; return; } - if( m_account->configuration().contains("enforcesecure") && m_account->configuration().value("enforcesecure").toBool() ) + if ( m_account->configuration().contains( "enforcesecure" ) && m_account->configuration().value( "enforcesecure" ).toBool() ) { tLog() << Q_FUNC_INFO << "Enforcing secure connection..."; - m_client->setFeatureConfig(Jreen::Client::Encryption, Jreen::Client::Force); + m_client->setFeatureConfig( Jreen::Client::Encryption, Jreen::Client::Force ); } tDebug() << "Connecting to the Xmpp server..." << m_client->jid().full(); @@ -228,18 +233,17 @@ XmppSipPlugin::connectPlugin() QTimer::singleShot( 1000, m_client, SLOT( connectToServer() ) ); if ( m_client->connection() ) - connect(m_client->connection(), SIGNAL(error(Jreen::Connection::SocketError)), SLOT(onError(Jreen::Connection::SocketError))); + connect( m_client->connection(), SIGNAL( error( Jreen::Connection::SocketError ) ), SLOT( onError( Jreen::Connection::SocketError ) ) ); m_state = Account::Connecting; emit stateChanged( m_state ); - return; } void XmppSipPlugin::disconnectPlugin() { - if (!m_client->isConnected()) + if ( !m_client->isConnected() ) { if ( m_state != Account::Disconnected ) // might be Connecting { @@ -267,8 +271,6 @@ XmppSipPlugin::disconnectPlugin() void XmppSipPlugin::onConnect() { -// qDebug() << Q_FUNC_INFO; - // update jid resource, servers like gtalk use resource binding and may // have changed our requested /resource if ( m_client->jid().resource() != m_currentResource ) @@ -277,15 +279,9 @@ XmppSipPlugin::onConnect() emit jidChanged( m_client->jid().full() ); } - qDebug() << "Connected to xmpp as:" << m_client->jid().full(); - // set presence to least valid value - m_client->setPresence(Jreen::Presence::XA, "Got Tomahawk? http://gettomahawk.com", -127); - - // set ping timeout to 15 secs (TODO: verify if this works) - m_client->setPingInterval(1000); - - // load roster + m_client->setPresence( Jreen::Presence::XA, "Got Tomahawk? http://gettomahawk.com", -127 ); + m_client->setPingInterval( 1000 ); m_roster->load(); // load XmppInfoPlugin @@ -293,13 +289,12 @@ XmppSipPlugin::onConnect() { infoPlugin().data()->moveToThread( Tomahawk::InfoSystem::InfoSystem::instance()->workerThread().data() ); Tomahawk::InfoSystem::InfoSystem::instance()->addInfoPlugin( infoPlugin() ); - QMetaObject::invokeMethod( infoPlugin().data(), "init", Qt::QueuedConnection ); } //FIXME: this implementation is totally broken atm, so it's disabled to avoid harm :P // join MUC with bare jid as nickname //TODO: make the room a list of rooms and make that configurable - QString mucNickname = QString( "tomahawk@conference.qutim.org/" ).append( QString( m_client->jid().bare() ).replace( "@", "-" ) ); + // QString mucNickname = QString( "tomahawk@conference.qutim.org/" ).append( QString( m_client->jid().bare() ).replace( "@", "-" ) ); //m_room = new Jreen::MUCRoom(m_client, Jreen::JID( mucNickname ) ); //m_room->setHistorySeconds(0); //m_room->join(); @@ -318,8 +313,6 @@ XmppSipPlugin::onConnect() void XmppSipPlugin::onDisconnect( Jreen::Client::DisconnectReason reason ) { - qDebug() << Q_FUNC_INFO; - switch( reason ) { case Jreen::Client::User: @@ -346,7 +339,7 @@ XmppSipPlugin::onDisconnect( Jreen::Client::DisconnectReason reason ) default: qDebug() << "Not all Client::DisconnectReasons checked" << ( int ) reason; - Q_ASSERT(false); + Q_ASSERT( false ); break; } m_state = Account::Disconnected; @@ -354,9 +347,9 @@ XmppSipPlugin::onDisconnect( Jreen::Client::DisconnectReason reason ) removeMenuHelper(); - Q_FOREACH(const Jreen::JID &peer, m_peers.keys()) + Q_FOREACH( const Jreen::JID &peer, m_peers.keys() ) { - handlePeerStatus(peer, Jreen::Presence::Unavailable); + handlePeerStatus( peer, Jreen::Presence::Unavailable ); } if ( !m_infoPlugin.isNull() ) @@ -377,56 +370,51 @@ XmppSipPlugin::errorMessage( Jreen::Client::DisconnectReason reason ) switch( reason ) { case Jreen::Client::User: - return tr("User Interaction"); + return tr( "User Interaction" ); break; case Jreen::Client::HostUnknown: - return tr("Host is unknown"); + return tr( "Host is unknown" ); break; case Jreen::Client::ItemNotFound: - return tr("Item not found"); + return tr( "Item not found" ); break; case Jreen::Client::AuthorizationError: - return tr("Authorization Error"); + return tr( "Authorization Error" ); break; case Jreen::Client::RemoteStreamError: - return tr("Remote Stream Error"); + return tr( "Remote Stream Error" ); break; case Jreen::Client::RemoteConnectionFailed: - return tr("Remote Connection failed"); + return tr( "Remote Connection failed" ); break; case Jreen::Client::InternalServerError: - return tr("Internal Server Error"); + return tr( "Internal Server Error" ); break; case Jreen::Client::SystemShutdown: - return tr("System shutdown"); + return tr( "System shutdown" ); break; case Jreen::Client::Conflict: - return tr("Conflict"); + return tr( "Conflict" ); break; - - case Jreen::Client::Unknown: - return tr("Unknown"); - break; - case Jreen::Client::NoCompressionSupport: - return tr("No Compression Support"); + return tr( "No Compression Support" ); break; - case Jreen::Client::NoEncryptionSupport: - return tr("No Encryption Support"); + return tr( "No Encryption Support" ); break; - case Jreen::Client::NoAuthorizationSupport: - return tr("No Authorization Support"); + return tr( "No Authorization Support" ); break; - case Jreen::Client::NoSupportedFeature: - return tr("No Supported Feature"); + return tr( "No Supported Feature" ); + break; + case Jreen::Client::Unknown: + return tr( "Unknown" ); break; default: qDebug() << "Not all Client::DisconnectReasons checked"; - Q_ASSERT(false); + Q_ASSERT( false ); break; } @@ -442,9 +430,8 @@ XmppSipPlugin::sendMsg( const QString& to, const QString& msg ) { qDebug() << Q_FUNC_INFO << to << msg; - if ( !m_client ) { + if ( !m_client ) return; - } /******************************************************* * Obsolete this by a SipMessage class @@ -452,29 +439,24 @@ XmppSipPlugin::sendMsg( const QString& to, const QString& msg ) QJson::Parser parser; bool ok; QVariant v = parser.parse( msg.toAscii(), &ok ); - if ( !ok || v.type() != QVariant::Map ) + if ( !ok || v.type() != QVariant::Map ) { qDebug() << "Invalid JSON in Xmpp msg"; return; } + QVariantMap m = v.toMap(); /*******************************************************/ TomahawkXmppMessage *sipMessage; - if(m["visible"].toBool()) + if ( m["visible"].toBool() ) { - sipMessage = new TomahawkXmppMessage( m["ip"].toString(), - m["port"].toInt(), - m["uniqname"].toString(), - m["key"].toString() - ); + sipMessage = new TomahawkXmppMessage( m["ip"].toString(), m["port"].toInt(), m["uniqname"].toString(), m["key"].toString() ); } else - { sipMessage = new TomahawkXmppMessage(); - } - qDebug() << "Send sip messsage to " << to; + qDebug() << "Send sip messsage to" << to; Jreen::IQ iq( Jreen::IQ::Set, to ); iq.addExtension( sipMessage ); Jreen::IQReply *reply = m_client->send( iq ); @@ -486,12 +468,10 @@ XmppSipPlugin::sendMsg( const QString& to, const QString& msg ) void XmppSipPlugin::broadcastMsg( const QString& msg ) { - qDebug() << Q_FUNC_INFO; - if ( !m_client ) return; - foreach( const Jreen::JID& jid, m_peers.keys() ) + foreach ( const Jreen::JID& jid, m_peers.keys() ) { sendMsg( jid.full(), msg ); } @@ -502,14 +482,11 @@ void XmppSipPlugin::addContact( const QString& jid, const QString& msg ) { // Add contact to the Tomahawk group on the roster - QString realJid = jid; - if( !realJid.contains( '@' ) ) + if ( !realJid.contains( '@' ) ) realJid += defaultSuffix(); m_roster->subscribe( realJid, msg, realJid, QStringList() << "Tomahawk" ); - - return; } @@ -533,24 +510,24 @@ XmppSipPlugin::showAddFriendDialog() void XmppSipPlugin::publishTune( const QUrl& url, const InfoSystem::InfoStringHash& trackInfo ) { - if( m_account->configuration().value("publishtracks").toBool() == false ) + if ( m_account->configuration().value("publishtracks").toBool() == false ) { - tDebug() << Q_FUNC_INFO << m_client->jid().full() << "Not publishing now playing info (disabled in account config)"; + tDebug() << Q_FUNC_INFO << m_client->jid().full() << "Not publishing now playing info (disabled in account config)"; return; } if ( trackInfo.isEmpty() ) { Jreen::Tune::Ptr tune( new Jreen::Tune() ); - m_pubSubManager->publishItems(QList() << tune, Jreen::JID()); + m_pubSubManager->publishItems( QList() << tune, Jreen::JID() ); } Jreen::Tune::Ptr tune( new Jreen::Tune() ); tune->setTitle( trackInfo.value( "title" ) ); tune->setArtist( trackInfo.value( "artist" ) ); - tune->setLength( trackInfo.value("duration").toInt() ); - tune->setTrack( trackInfo.value("albumpos") ); + tune->setLength( trackInfo.value( "duration" ).toInt() ); + tune->setTrack( trackInfo.value( "albumpos" ) ); //TODO: provide a rating once available in Tomahawk tune->setRating( 10 ); @@ -559,7 +536,7 @@ XmppSipPlugin::publishTune( const QUrl& url, const InfoSystem::InfoStringHash& t tune->setSource( "Tomahawk" ); tune->setUri( url ); - tDebug() << Q_FUNC_INFO << "Setting URI of " << tune->uri().toString(); + tDebug() << Q_FUNC_INFO << "Setting URI of" << tune->uri().toString(); m_pubSubManager->publishItems( QList() << tune, Jreen::JID() ); } @@ -643,13 +620,15 @@ XmppSipPlugin::configurationChanged() } } -void XmppSipPlugin::setupClientHelper() + +void +XmppSipPlugin::setupClientHelper() { Jreen::JID jid = Jreen::JID( m_currentUsername ); m_client->setJID( jid ); m_client->setPassword( m_currentPassword ); - if( !m_currentServer.isEmpty() ) + if ( !m_currentServer.isEmpty() ) { // set explicit server details m_client->setServer( m_currentServer ); @@ -663,20 +642,22 @@ void XmppSipPlugin::setupClientHelper() } } -void XmppSipPlugin::addMenuHelper() + +void +XmppSipPlugin::addMenuHelper() { #ifndef ENABLE_HEADLESS - if( !m_menu ) + if ( !m_menu ) { m_menu = new QMenu( QString( "%1 (" ).arg( friendlyName() ).append( readUsername() ).append(")" ) ); QAction* addFriendAction = m_menu->addAction( tr( "Add Friend..." ) ); - connect( addFriendAction, SIGNAL( triggered() ), this, SLOT( showAddFriendDialog() ) ); + connect( addFriendAction, SIGNAL( triggered() ), SLOT( showAddFriendDialog() ) ); - if( readXmlConsoleEnabled() ) + if ( readXmlConsoleEnabled() ) { - QAction* showXmlConsoleAction = m_menu->addAction( tr( "XML Console...") ); - connect( showXmlConsoleAction, SIGNAL( triggered() ), this, SLOT( showXmlConsole() ) ); + QAction* showXmlConsoleAction = m_menu->addAction( tr( "XML Console..." ) ); + connect( showXmlConsoleAction, SIGNAL( triggered() ), SLOT( showXmlConsole() ) ); } emit addMenu( m_menu ); @@ -684,10 +665,12 @@ void XmppSipPlugin::addMenuHelper() #endif } -void XmppSipPlugin::removeMenuHelper() + +void +XmppSipPlugin::removeMenuHelper() { #ifndef ENABLE_HEADLESS - if( m_menu ) + if ( m_menu ) { emit removeMenu( m_menu ); @@ -698,37 +681,35 @@ void XmppSipPlugin::removeMenuHelper() } -void XmppSipPlugin::onNewMessage( const Jreen::Message& message ) +void +XmppSipPlugin::onNewMessage( const Jreen::Message& message ) { if ( m_state != Account::Connected ) return; -// qDebug() << Q_FUNC_INFO << "message type" << message.subtype(); - QString from = message.from().full(); QString msg = message.body(); - if(msg.isEmpty()) + if ( msg.isEmpty() ) return; - if( message.subtype() == Jreen::Message::Error ) + if ( message.subtype() == Jreen::Message::Error ) { - tDebug() << Q_FUNC_INFO << "Received error message from " << from << ", not answering... (Condition: " + tDebug() << Q_FUNC_INFO << "Received error message from" << from << ", not answering... (Condition:" << ( message.error().isNull() ? -1 : message.error()->condition() ) << ")"; return; } SipInfo info = SipInfo::fromJson( msg ); - if ( !info.isValid() ) { QString to = from; - QString response = QString( tr("I'm sorry -- I'm just an automatic presence used by Tomahawk Player" - " (http://gettomahawk.com). If you are getting this message, the person you" - " are trying to reach is probably not signed on, so please try again later!") ); + QString response = QString( tr( "I'm sorry -- I'm just an automatic presence used by Tomahawk Player" + " (http://gettomahawk.com). If you are getting this message, the person you" + " are trying to reach is probably not signed on, so please try again later!" ) ); // this is not a sip message, so we send it directly through the client - m_client->send( Jreen::Message ( Jreen::Message::Error, Jreen::JID(to), response) ); + m_client->send( Jreen::Message ( Jreen::Message::Error, Jreen::JID( to ), response) ); emit msgReceived( from, msg ); return; @@ -739,7 +720,8 @@ void XmppSipPlugin::onNewMessage( const Jreen::Message& message ) } -void XmppSipPlugin::onPresenceReceived( const Jreen::RosterItem::Ptr &item, const Jreen::Presence& presence ) +void +XmppSipPlugin::onPresenceReceived( const Jreen::RosterItem::Ptr& item, const Jreen::Presence& presence ) { Q_UNUSED(item); if ( m_state != Account::Connected ) @@ -750,19 +732,20 @@ void XmppSipPlugin::onPresenceReceived( const Jreen::RosterItem::Ptr &item, cons qDebug() << Q_FUNC_INFO << "* New presence:" << fulljid << presence.subtype(); - if( jid == m_client->jid() ) + if ( jid == m_client->jid() ) return; - if ( presence.error() ) { + if ( presence.error() ) + { //qDebug() << Q_FUNC_INFO << fulljid << "Running tomahawk: no" << "presence error"; return; } // ignore anyone not Running tomahawk: Jreen::Capabilities::Ptr caps = presence.payload(); - if( caps ) + if ( caps ) { - qDebug() << Q_FUNC_INFO << fulljid << "Running tomahawk: maybe" << "caps " << caps->node() << "requesting disco..."; + qDebug() << Q_FUNC_INFO << fulljid << "Running tomahawk: maybe" << "caps" << caps->node() << "requesting disco..."; // request disco features QString node = caps->node() + '#' + caps->ver(); @@ -774,7 +757,7 @@ void XmppSipPlugin::onPresenceReceived( const Jreen::RosterItem::Ptr &item, cons reply->setData( RequestDisco ); connect( reply, SIGNAL( received( Jreen::IQ ) ), SLOT( onNewIq( Jreen::IQ ) ) ); } - else if( !caps ) + else if ( !caps ) { // qDebug() << Q_FUNC_INFO << "Running tomahawk: no" << "no caps"; if ( presenceMeansOnline( m_peers[ jid ] ) ) @@ -783,46 +766,40 @@ void XmppSipPlugin::onPresenceReceived( const Jreen::RosterItem::Ptr &item, cons } -void XmppSipPlugin::onSubscriptionReceived( const Jreen::RosterItem::Ptr& item, const Jreen::Presence& presence ) +void +XmppSipPlugin::onSubscriptionReceived( const Jreen::RosterItem::Ptr& item, const Jreen::Presence& presence ) { if ( m_state != Account::Connected ) return; -// qDebug() << Q_FUNC_INFO << "presence type:" << presence.subtype(); - if(item) + if ( item ) qDebug() << Q_FUNC_INFO << presence.from().full() << "subs" << item->subscription() << "ask" << item->ask(); else qDebug() << Q_FUNC_INFO << "item empty"; // don't do anything if the contact is already subscribed to us - if( presence.subtype() != Jreen::Presence::Subscribe || - ( - item && (item->subscription() == Jreen::RosterItem::From || item->subscription() == Jreen::RosterItem::Both) - ) - ) + if ( presence.subtype() != Jreen::Presence::Subscribe || + ( item && (item->subscription() == Jreen::RosterItem::From || item->subscription() == Jreen::RosterItem::Both ) ) ) { return; } // check if the requester is already on the roster - if(item && - ( - item->subscription() == Jreen::RosterItem::To || - ( item->subscription() == Jreen::RosterItem::None && !item->ask().isEmpty() ) - ) - ) + if ( item && + ( item->subscription() == Jreen::RosterItem::To || ( item->subscription() == Jreen::RosterItem::None && !item->ask().isEmpty() ) ) ) { qDebug() << Q_FUNC_INFO << presence.from().bare() << "already on the roster so we assume ack'ing subscription request is okay..."; - m_roster->allowSubscription(presence.from(), true); + m_roster->allowSubscription( presence.from(), true ); return; } + #ifndef ENABLE_HEADLESS // preparing the confirm box for the user QMessageBox *confirmBox = new QMessageBox( QMessageBox::Question, tr( "Authorize User" ), - QString( tr( "Do you want to grant %1 access to your Collection?" ) ).arg(presence.from().bare()), + QString( tr( "Do you want to grant %1 access to your Collection?" ) ).arg( presence.from().bare() ), QMessageBox::Yes | QMessageBox::No, TomahawkUtils::tomahawkWindow() ); @@ -858,11 +835,10 @@ XmppSipPlugin::onSubscriptionRequestConfirmed( int result ) sender()->deleteLater(); QMessageBox::StandardButton allowSubscription = static_cast< QMessageBox::StandardButton >( result ); - if ( allowSubscription == QMessageBox::Yes ) { qDebug() << Q_FUNC_INFO << jid.bare() << "accepted by user, adding to roster"; - addContact(jid, ""); + addContact( jid, "" ); } else { @@ -874,7 +850,8 @@ XmppSipPlugin::onSubscriptionRequestConfirmed( int result ) } -void XmppSipPlugin::onNewIq( const Jreen::IQ& iq ) +void +XmppSipPlugin::onNewIq( const Jreen::IQ& iq ) { if ( m_state != Account::Connected ) return; @@ -888,10 +865,9 @@ void XmppSipPlugin::onNewIq( const Jreen::IQ& iq ) Jreen::Disco::Info *discoInfo = iq.payload< Jreen::Disco::Info >().data(); if ( !discoInfo ) return; + iq.accept(); - Jreen::JID jid = iq.from(); - Jreen::DataForm::Ptr form = discoInfo->form(); if ( discoInfo->features().contains( TOMAHAWK_FEATURE ) ) @@ -907,8 +883,8 @@ void XmppSipPlugin::onNewIq( const Jreen::IQ& iq ) Jreen::SoftwareVersion::Ptr softwareVersion = iq.payload(); if ( softwareVersion ) { - QString versionString = QString("%1 %2 %3").arg( softwareVersion->name(), softwareVersion->os(), softwareVersion->version() ); - qDebug() << Q_FUNC_INFO << "Received software version for " << iq.from().full() << ":" << versionString; + QString versionString = QString( "%1 %2 %3" ).arg( softwareVersion->name(), softwareVersion->os(), softwareVersion->version() ); + qDebug() << Q_FUNC_INFO << "Received software version for" << iq.from().full() << ":" << versionString; emit softwareVersionReceived( iq.from().full(), versionString ); } } @@ -936,9 +912,8 @@ void XmppSipPlugin::onNewIq( const Jreen::IQ& iq ) SipInfo info; info.setVisible( sipMessage->visible() ); - if( sipMessage->visible() ) + if ( sipMessage->visible() ) { - QHostInfo hi; hi.setHostName( sipMessage->ip() ); info.setHost( hi ); @@ -956,7 +931,8 @@ void XmppSipPlugin::onNewIq( const Jreen::IQ& iq ) } -bool XmppSipPlugin::presenceMeansOnline( Jreen::Presence::Type p ) +bool +XmppSipPlugin::presenceMeansOnline( Jreen::Presence::Type p ) { switch( p ) { @@ -965,22 +941,21 @@ bool XmppSipPlugin::presenceMeansOnline( Jreen::Presence::Type p ) case Jreen::Presence::Error: return false; break; + default: return true; } } -void XmppSipPlugin::handlePeerStatus( const Jreen::JID& jid, Jreen::Presence::Type presenceType ) +void +XmppSipPlugin::handlePeerStatus( const Jreen::JID& jid, Jreen::Presence::Type presenceType ) { QString fulljid = jid.full(); // "going offline" event if ( !presenceMeansOnline( presenceType ) && - ( !m_peers.contains( jid ) || - presenceMeansOnline( m_peers.value( jid ) ) - ) - ) + ( !m_peers.contains( jid ) || presenceMeansOnline( m_peers.value( jid ) ) ) ) { m_peers[ jid ] = presenceType; qDebug() << Q_FUNC_INFO << "* Peer goes offline:" << fulljid; @@ -991,10 +966,7 @@ void XmppSipPlugin::handlePeerStatus( const Jreen::JID& jid, Jreen::Presence::Ty // "coming online" event if ( presenceMeansOnline( presenceType ) && - ( !m_peers.contains( jid ) || - !presenceMeansOnline( m_peers.value( jid ) ) - ) - ) + ( !m_peers.contains( jid ) || !presenceMeansOnline( m_peers.value( jid ) ) ) ) { m_peers[ jid ] = presenceType; qDebug() << Q_FUNC_INFO << "* Peer goes online:" << fulljid; @@ -1021,7 +993,8 @@ void XmppSipPlugin::handlePeerStatus( const Jreen::JID& jid, Jreen::Presence::Ty } -void XmppSipPlugin::onNewAvatar( const QString& jid ) +void +XmppSipPlugin::onNewAvatar( const QString& jid ) { #ifndef ENABLE_HEADLESS // qDebug() << Q_FUNC_INFO << jid; @@ -1032,20 +1005,20 @@ void XmppSipPlugin::onNewAvatar( const QString& jid ) // find peers for the jid QList< Jreen::JID > peers = m_peers.keys(); - foreach ( const Jreen::JID &peer, peers ) + foreach ( const Jreen::JID& peer, peers ) { - if( peer.bare() == jid ) + if ( peer.bare() == jid ) { - emit avatarReceived ( peer.full(), m_avatarManager->avatar( jid ) ); + emit avatarReceived( peer.full(), m_avatarManager->avatar( jid ) ); } } if ( jid == m_client->jid().bare() ) // own avatar - emit avatarReceived ( m_avatarManager->avatar( jid ) ); + emit avatarReceived( m_avatarManager->avatar( jid ) ); else // someone else's avatar - emit avatarReceived ( jid, m_avatarManager->avatar( jid ) ); + emit avatarReceived( jid, m_avatarManager->avatar( jid ) ); #endif } @@ -1066,6 +1039,7 @@ XmppSipPlugin::readUsername() return credentials.contains( "username" ) ? credentials[ "username" ].toString() : QString(); } + QString XmppSipPlugin::readPassword() { diff --git a/src/accounts/xmpp/sip/XmppSip.h b/src/accounts/xmpp/sip/XmppSip.h index ce95a9615..de9f09282 100644 --- a/src/accounts/xmpp/sip/XmppSip.h +++ b/src/accounts/xmpp/sip/XmppSip.h @@ -48,9 +48,6 @@ #include #endif -#define TOMAHAWK_FEATURE QLatin1String( "tomahawk:sip:v1" ) -#define TOMAHAWK_CAP_NODE_NAME QLatin1String( "http://tomahawk-player.org/" ) - #include "accounts/AccountDllMacro.h" #include "../XmppInfoPlugin.h" @@ -90,10 +87,11 @@ public slots: virtual void checkSettings(); virtual void configurationChanged(); virtual void sendMsg( const QString& to, const QString& msg ); - void broadcastMsg( const QString &msg ); - virtual void addContact( const QString &jid, const QString& msg = QString() ); + virtual void addContact( const QString& jid, const QString& msg = QString() ); + + void broadcastMsg( const QString& msg ); void showAddFriendDialog(); - void publishTune( const QUrl &url, const Tomahawk::InfoSystem::InfoStringHash &trackInfo ); + void publishTune( const QUrl& url, const Tomahawk::InfoSystem::InfoStringHash& trackInfo ); protected: virtual QString defaultSuffix() const; @@ -103,14 +101,14 @@ private slots: void onConnect(); void onDisconnect( Jreen::Client::DisconnectReason reason ); - void onPresenceReceived( const Jreen::RosterItem::Ptr &item, const Jreen::Presence& presence ); - void onSubscriptionReceived( const Jreen::RosterItem::Ptr &item, const Jreen::Presence& presence ); + void onPresenceReceived( const Jreen::RosterItem::Ptr& item, const Jreen::Presence& presence ); + void onSubscriptionReceived( const Jreen::RosterItem::Ptr& item, const Jreen::Presence& presence ); void onSubscriptionRequestConfirmed( int result ); void onNewMessage( const Jreen::Message& message ); void onError( const Jreen::Connection::SocketError& e ); - void onNewIq( const Jreen::IQ &iq ); - void onNewAvatar( const QString &jid ); + void onNewIq( const Jreen::IQ& iq ); + void onNewAvatar( const QString& jid ); private: bool readXmlConsoleEnabled(); @@ -125,7 +123,7 @@ private: void removeMenuHelper(); bool presenceMeansOnline( Jreen::Presence::Type p ); - void handlePeerStatus( const Jreen::JID &jid, Jreen::Presence::Type presenceType ); + void handlePeerStatus( const Jreen::JID& jid, Jreen::Presence::Type presenceType ); QString m_currentUsername; QString m_currentPassword; @@ -133,22 +131,24 @@ private: int m_currentPort; QString m_currentResource; - QWeakPointer< Tomahawk::InfoSystem::XmppInfoPlugin> m_infoPlugin; + QWeakPointer< Tomahawk::InfoSystem::XmppInfoPlugin > m_infoPlugin; Tomahawk::Accounts::Account::ConnectionState m_state; // sort out - Jreen::Client *m_client; + Jreen::Client* m_client; + + Jreen::MUCRoom* m_room; + Jreen::SimpleRoster* m_roster; + QHash< Jreen::JID, Jreen::Presence::Type > m_peers; - Jreen::MUCRoom *m_room; - Jreen::SimpleRoster *m_roster; - QHash m_peers; #ifndef ENABLE_HEADLESS - QHash m_subscriptionConfirmBoxes; + QHash< Jreen::JID, QMessageBox* > m_subscriptionConfirmBoxes; QMenu* m_menu; XmlConsole* m_xmlConsole; #endif + enum IqContext { NoContext, RequestDisco, RequestedDisco, SipMessageSent, RequestedVCard, RequestVersion, RequestedVersion }; - AvatarManager *m_avatarManager; + AvatarManager* m_avatarManager; Jreen::PubSub::Manager* m_pubSubManager; }; diff --git a/src/accounts/zeroconf/ZeroconfAccount.cpp b/src/accounts/zeroconf/ZeroconfAccount.cpp index 44d74e057..364022a37 100644 --- a/src/accounts/zeroconf/ZeroconfAccount.cpp +++ b/src/accounts/zeroconf/ZeroconfAccount.cpp @@ -86,7 +86,7 @@ void ZeroconfAccount::authenticate() { if ( !isAuthenticated() ) - static_cast< ZeroconfPlugin* >( m_sipPlugin.data() )->connectPlugin(); + sipPlugin()->connectPlugin(); } @@ -94,7 +94,7 @@ void ZeroconfAccount::deauthenticate() { if ( isAuthenticated() ) - static_cast< ZeroconfPlugin* >( m_sipPlugin.data() )->disconnectPlugin(); + sipPlugin()->disconnectPlugin(); } @@ -112,7 +112,7 @@ ZeroconfAccount::connectionState() const return Disconnected; // TODO can we get called before sipPlugin()? - return static_cast< ZeroconfPlugin* >( m_sipPlugin.data() )->connectionState(); + return m_sipPlugin.data()->connectionState(); } @@ -120,10 +120,10 @@ SipPlugin* ZeroconfAccount::sipPlugin() { if ( m_sipPlugin.isNull() ) - m_sipPlugin = QWeakPointer< SipPlugin >( new ZeroconfPlugin( this ) ); + m_sipPlugin = QWeakPointer< ZeroconfPlugin >( new ZeroconfPlugin( this ) ); return m_sipPlugin.data(); } -Q_EXPORT_PLUGIN2( Tomahawk::Accounts::AccountFactory, Tomahawk::Accounts::ZeroconfFactory ) \ No newline at end of file +Q_EXPORT_PLUGIN2( Tomahawk::Accounts::AccountFactory, Tomahawk::Accounts::ZeroconfFactory ) diff --git a/src/accounts/zeroconf/ZeroconfAccount.h b/src/accounts/zeroconf/ZeroconfAccount.h index 30d43e038..136c971c0 100644 --- a/src/accounts/zeroconf/ZeroconfAccount.h +++ b/src/accounts/zeroconf/ZeroconfAccount.h @@ -19,6 +19,7 @@ #ifndef ZEROCONF_ACCOUNTS_H #define ZEROCONF_ACCOUNTS_H +#include "Zeroconf.h" #include "accounts/Account.h" #include "../AccountDllMacro.h" @@ -71,7 +72,7 @@ public: QWidget* aclWidget() { return 0; } private: - QWeakPointer< SipPlugin > m_sipPlugin; + QWeakPointer< ZeroconfPlugin > m_sipPlugin; }; } diff --git a/src/breakpad/CrashReporter/CrashReporter.ui b/src/breakpad/CrashReporter/CrashReporter.ui index 10d1d406f..8cfe575fb 100644 --- a/src/breakpad/CrashReporter/CrashReporter.ui +++ b/src/breakpad/CrashReporter/CrashReporter.ui @@ -77,7 +77,7 @@ - <html><head/><body><p><span style=" font-weight:600;">Sorry!</span> Tomahawk crashed. Please tell us about it! Tomahawk has created an error report for you that can help improve the stability in the future. You can now send the this report directly to the Tomahawk developers.</p></body></html> + <html><head/><body><p><span style=" font-weight:600;">Sorry!</span> Tomahawk crashed. Please tell us about it! Tomahawk 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 Tomahawk developers.</p></body></html> Qt::RichText diff --git a/src/infoplugins/generic/CMakeLists.txt b/src/infoplugins/generic/CMakeLists.txt index 7473744f1..c077e1e77 100644 --- a/src/infoplugins/generic/CMakeLists.txt +++ b/src/infoplugins/generic/CMakeLists.txt @@ -9,6 +9,7 @@ list(APPEND simple_plugins MusixMatch MusicBrainz Rovi + Discogs ) foreach(simple_plugin ${simple_plugins}) diff --git a/src/infoplugins/generic/charts/ChartsPlugin.cpp b/src/infoplugins/generic/charts/ChartsPlugin.cpp index 3a3433fb4..20123c997 100644 --- a/src/infoplugins/generic/charts/ChartsPlugin.cpp +++ b/src/infoplugins/generic/charts/ChartsPlugin.cpp @@ -52,8 +52,23 @@ ChartsPlugin::ChartsPlugin() : InfoPlugin() , m_chartsFetchJobs( 0 ) { + tDebug( LOGVERBOSE ) << Q_FUNC_INFO << QThread::currentThread(); /// If you add resource, update version aswell m_chartVersion = "2.3"; + m_supportedGetTypes << InfoChart << InfoChartCapabilities; +} + + +ChartsPlugin::~ChartsPlugin() +{ + tDebug( LOGVERBOSE ) << Q_FUNC_INFO << QThread::currentThread(); +} + + +void +ChartsPlugin::init() +{ + tDebug( LOGVERBOSE ) << Q_FUNC_INFO << QThread::currentThread(); QVariantList source_qvarlist = TomahawkUtils::Cache::instance()->getData( "ChartsPlugin", "chart_sources" ).toList(); foreach( const QVariant & source, source_qvarlist ) { m_chartResources.append( source.toString() ); @@ -63,14 +78,6 @@ ChartsPlugin::ChartsPlugin() tDebug( LOGVERBOSE ) << Q_FUNC_INFO << "total sources" << m_chartResources.size() << source_qvarlist.size(); if( m_chartResources.size() == 0 ) fetchChartSourcesList( true ); - m_supportedGetTypes << InfoChart << InfoChartCapabilities; - -} - - -ChartsPlugin::~ChartsPlugin() -{ - tDebug( LOGVERBOSE ) << Q_FUNC_INFO; } @@ -219,7 +226,7 @@ ChartsPlugin::fetchChartSourcesList( bool fetchOnlySourceList ) reply->setProperty( "only_source_list", fetchOnlySourceList ); - tDebug() << "fetching:" << url; + tDebug() << Q_FUNC_INFO << "fetching:" << url; connect( reply, SIGNAL( finished() ), SLOT( chartSourcesList() ) ); } @@ -227,7 +234,7 @@ ChartsPlugin::fetchChartSourcesList( bool fetchOnlySourceList ) void ChartsPlugin::chartSourcesList() { - tDebug( LOGVERBOSE ) << "Got chart sources list"; + tDebug( LOGVERBOSE ) << Q_FUNC_INFO << "Got chart sources list"; QNetworkReply* reply = qobject_cast( sender() ); if ( reply->error() == QNetworkReply::NoError ) @@ -239,7 +246,7 @@ ChartsPlugin::chartSourcesList() if ( !ok ) { - tLog() << "Failed to parse sources" << p.errorString() << "On line" << p.errorLine(); + tLog() << Q_FUNC_INFO << "Failed to parse sources" << p.errorString() << "On line" << p.errorLine(); return; } @@ -253,6 +260,8 @@ ChartsPlugin::chartSourcesList() if( !reply->property("only_source_list" ).toBool() ) fetchAllChartSources(); } + else + tDebug() << Q_FUNC_INFO << "Encountered error fetching chart sources list"; } void ChartsPlugin::fetchAllChartSources() @@ -266,7 +275,7 @@ void ChartsPlugin::fetchAllChartSources() QNetworkReply* reply = TomahawkUtils::nam()->get( QNetworkRequest( url ) ); reply->setProperty( "chart_source", source); - tDebug() << "fetching:" << url; + tDebug() << Q_FUNC_INFO << "fetching:" << url; connect( reply, SIGNAL( finished() ), SLOT( chartsList() ) ); m_chartsFetchJobs++; @@ -291,7 +300,7 @@ void ChartsPlugin::fetchChart( Tomahawk::InfoSystem::InfoRequestData requestData void ChartsPlugin::chartsList() { - tDebug( LOGVERBOSE ) << "Got chart list result"; + tDebug( LOGVERBOSE ) << Q_FUNC_INFO << "Got chart list result"; QNetworkReply* reply = qobject_cast( sender() ); if ( reply->error() == QNetworkReply::NoError ) diff --git a/src/infoplugins/generic/charts/ChartsPlugin.h b/src/infoplugins/generic/charts/ChartsPlugin.h index d521bb19a..bc0fbacfe 100644 --- a/src/infoplugins/generic/charts/ChartsPlugin.h +++ b/src/infoplugins/generic/charts/ChartsPlugin.h @@ -55,6 +55,7 @@ public: ChartType chartType() const { return m_chartType; } protected slots: + virtual void init(); virtual void getInfo( Tomahawk::InfoSystem::InfoRequestData requestData ); virtual void notInCacheSlot( Tomahawk::InfoSystem::InfoStringHash criteria, Tomahawk::InfoSystem::InfoRequestData requestData ); diff --git a/src/infoplugins/generic/discogs/DiscogsPlugin.cpp b/src/infoplugins/generic/discogs/DiscogsPlugin.cpp new file mode 100644 index 000000000..f4dc88652 --- /dev/null +++ b/src/infoplugins/generic/discogs/DiscogsPlugin.cpp @@ -0,0 +1,189 @@ +/* === This file is part of Tomahawk Player - === + * + * Copyright 2012 Leo Franchi + * + * Tomahawk is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Tomahawk is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Tomahawk. If not, see . + */ + +#include "DiscogsPlugin.h" + +#include +#include +#include + +#include "utils/TomahawkUtils.h" +#include "utils/Logger.h" +#include "utils/Closure.h" +#include + +using namespace Tomahawk::InfoSystem; + + +DiscogsPlugin::DiscogsPlugin() + : InfoPlugin() +{ + qDebug() << Q_FUNC_INFO; + m_supportedGetTypes << Tomahawk::InfoSystem::InfoAlbumSongs; +} + + +DiscogsPlugin::~DiscogsPlugin() {} + + +void +DiscogsPlugin::getInfo( Tomahawk::InfoSystem::InfoRequestData requestData ) +{ + if ( !requestData.input.canConvert< Tomahawk::InfoSystem::InfoStringHash >() ) + { + emit info( requestData, QVariant() ); + return; + } + + InfoStringHash hash = requestData.input.value< Tomahawk::InfoSystem::InfoStringHash >(); + if ( !hash.contains( "artist" ) || !hash.contains( "album" ) ) + { + emit info( requestData, QVariant() ); + return; + } + + switch ( requestData.type ) + { + case InfoAlbumSongs: + { + + Tomahawk::InfoSystem::InfoStringHash criteria; + criteria["artist"] = hash["artist"]; + criteria["album"] = hash["album"]; + + emit getCachedInfo( criteria, 2419200000, requestData ); + + break; + } + + default: + { + Q_ASSERT( false ); + break; + } + } +} + + +void +DiscogsPlugin::notInCacheSlot( InfoStringHash criteria, InfoRequestData requestData ) +{ + switch ( requestData.type ) + { + case InfoAlbumSongs: + { + QString requestString( "http://api.discogs.com/database/search" ); + QUrl url( requestString ); + url.addQueryItem( "type", "release" ); + url.addQueryItem( "release_title", criteria[ "album" ] ); + url.addQueryItem( "artist", criteria[ "artist" ] ); + QNetworkRequest req( url ); + req.setRawHeader( "User-Agent", "TomahawkPlayer/1.0 +http://tomahawk-player.org" ); + QNetworkReply* reply = TomahawkUtils::nam()->get( req ); + + NewClosure( reply, SIGNAL( finished() ), this, SLOT( albumSearchSlot( Tomahawk::InfoSystem::InfoRequestData, QNetworkReply* ) ), requestData, reply ); + break; + } + + default: + { + Q_ASSERT( false ); + break; + } + } +} + + +void +DiscogsPlugin::albumSearchSlot( const InfoRequestData &requestData, QNetworkReply *reply ) +{ + QJson::Parser p; + QVariantMap results = p.parse( reply ).toMap(); + + if ( !results.contains( "results" ) || results.value( "results" ).toList().isEmpty() ) + { + emit info( requestData, QVariant() ); + return; + } + + const QVariantMap result = results.value( "results" ).toList().first().toMap(); + if ( !result.contains( "id" ) ) + { + emit info( requestData, QVariant() ); + return; + } + + const int id = result.value( "id" ).toInt(); + QUrl url( QString( "http://api.discogs.com/release/%1" ).arg( id ) ); + QNetworkRequest req( url ); + req.setRawHeader( "User-Agent", "TomahawkPlayer/1.0 +http://tomahawk-player.org" ); + + QNetworkReply* reply2 = TomahawkUtils::nam()->get( req ); + NewClosure( reply2, SIGNAL( finished() ), this, SLOT( albumInfoSlot( Tomahawk::InfoSystem::InfoRequestData, QNetworkReply* ) ), requestData, reply2 ); +} + + +void +DiscogsPlugin::albumInfoSlot( const InfoRequestData& requestData, QNetworkReply* reply ) +{ + QJson::Parser p; + QVariantMap results = p.parse( reply ).toMap(); + + if ( !results.contains( "resp" ) ) + { + emit info( requestData, QVariant() ); + return; + } + + const QVariantMap resp = results[ "resp" ].toMap(); + if ( !resp.contains( "release" ) ) + { + emit info( requestData, QVariant() ); + return; + } + + const QVariantMap release = resp[ "release" ].toMap(); + if ( !release.contains( "tracklist" ) || release[ "tracklist" ].toList().isEmpty() ) + { + emit info( requestData, QVariant() ); + return; + } + + QStringList trackNameList; + foreach ( const QVariant& v, release[ "tracklist" ].toList() ) + { + const QVariantMap track = v.toMap(); + if ( track.contains( "title" ) ) + trackNameList << track[ "title" ].toString(); + } + + QVariantMap returnedData; + returnedData["tracks"] = trackNameList; + + emit info( requestData, returnedData ); + + Tomahawk::InfoSystem::InfoStringHash criteria; + criteria["artist"] = requestData.input.value< Tomahawk::InfoSystem::InfoStringHash>()["artist"]; + criteria["album"] = requestData.input.value< Tomahawk::InfoSystem::InfoStringHash>()["album"]; + + emit updateCache( criteria, 0, requestData.type, returnedData ); +} + + + +Q_EXPORT_PLUGIN2( Tomahawk::InfoSystem::InfoPlugin, Tomahawk::InfoSystem::DiscogsPlugin ) diff --git a/src/infoplugins/generic/discogs/DiscogsPlugin.h b/src/infoplugins/generic/discogs/DiscogsPlugin.h new file mode 100644 index 000000000..654fe7e52 --- /dev/null +++ b/src/infoplugins/generic/discogs/DiscogsPlugin.h @@ -0,0 +1,63 @@ +/* === This file is part of Tomahawk Player - === + * + * Copyright 2012 Leo Franchi + * + * Tomahawk is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Tomahawk is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Tomahawk. If not, see . + */ + +#ifndef DISCOGS_PLUGIN_H +#define DISCOGS_PLUGIN_H + +#include "Typedefs.h" +#include "infosystem/InfoSystem.h" +#include "infosystem/InfoSystemWorker.h" +#include "infoplugins/InfoPluginDllMacro.h" + +class QNetworkReply; + +namespace Tomahawk +{ + +namespace InfoSystem +{ + +class INFOPLUGINDLLEXPORT DiscogsPlugin : public InfoPlugin +{ + Q_OBJECT + Q_INTERFACES( Tomahawk::InfoSystem::InfoPlugin ) + +public: + DiscogsPlugin(); + virtual ~DiscogsPlugin(); + +protected slots: + virtual void init() {} + virtual void getInfo( Tomahawk::InfoSystem::InfoRequestData requestData ); + virtual void notInCacheSlot( InfoStringHash criteria, InfoRequestData requestData ); + + virtual void pushInfo( Tomahawk::InfoSystem::InfoPushData ) {} +private slots: + void albumSearchSlot( const Tomahawk::InfoSystem::InfoRequestData& , QNetworkReply* ); + void albumInfoSlot( const Tomahawk::InfoSystem::InfoRequestData& , QNetworkReply* ); + +private: + bool isValidTrackData( Tomahawk::InfoSystem::InfoRequestData requestData ); +}; + +} + +} + +Q_DECLARE_METATYPE( QNetworkReply* ) +#endif diff --git a/src/infoplugins/generic/echonest/EchonestPlugin.cpp b/src/infoplugins/generic/echonest/EchonestPlugin.cpp index f1d28b89a..b0e1ec65c 100644 --- a/src/infoplugins/generic/echonest/EchonestPlugin.cpp +++ b/src/infoplugins/generic/echonest/EchonestPlugin.cpp @@ -39,7 +39,6 @@ EchonestPlugin::EchonestPlugin() { qDebug() << Q_FUNC_INFO; m_supportedGetTypes << Tomahawk::InfoSystem::InfoArtistBiography << Tomahawk::InfoSystem::InfoArtistFamiliarity << Tomahawk::InfoSystem::InfoArtistHotttness << Tomahawk::InfoSystem::InfoArtistTerms << Tomahawk::InfoSystem::InfoMiscTopTerms; - Echonest::Config::instance()->setNetworkAccessManager( TomahawkUtils::nam() ); } @@ -49,6 +48,13 @@ EchonestPlugin::~EchonestPlugin() } +void +EchonestPlugin::init() +{ + Echonest::Config::instance()->setNetworkAccessManager( TomahawkUtils::nam() ); +} + + void EchonestPlugin::getInfo( Tomahawk::InfoSystem::InfoRequestData requestData ) { diff --git a/src/infoplugins/generic/echonest/EchonestPlugin.h b/src/infoplugins/generic/echonest/EchonestPlugin.h index 4468c375c..bdd4e6a3a 100644 --- a/src/infoplugins/generic/echonest/EchonestPlugin.h +++ b/src/infoplugins/generic/echonest/EchonestPlugin.h @@ -45,6 +45,8 @@ public: virtual ~EchonestPlugin(); protected slots: + virtual void init(); + virtual void getInfo( Tomahawk::InfoSystem::InfoRequestData requestData ); virtual void pushInfo( Tomahawk::InfoSystem::InfoPushData pushData ) diff --git a/src/infoplugins/generic/hypem/HypemPlugin.cpp b/src/infoplugins/generic/hypem/HypemPlugin.cpp index c4c3a23a1..4827d425c 100644 --- a/src/infoplugins/generic/hypem/HypemPlugin.cpp +++ b/src/infoplugins/generic/hypem/HypemPlugin.cpp @@ -30,6 +30,7 @@ #include "Typedefs.h" #include "TomahawkSettings.h" #include "utils/TomahawkUtils.h" +#include "infosystem/InfoSystemWorker.h" #include "utils/Logger.h" #include "Source.h" @@ -94,8 +95,6 @@ HypemPlugin::HypemPlugin() << "Techno" << "Punk" << "New wave"; - chartTypes(); - } @@ -107,6 +106,13 @@ HypemPlugin::~HypemPlugin() } +void +HypemPlugin::init() +{ + chartTypes(); +} + + void HypemPlugin::dataError( Tomahawk::InfoSystem::InfoRequestData requestData ) { @@ -189,6 +195,7 @@ HypemPlugin::fetchChartCapabilities( Tomahawk::InfoSystem::InfoRequestData reque void HypemPlugin::notInCacheSlot( QHash criteria, Tomahawk::InfoSystem::InfoRequestData requestData ) { + tDebug( LOGVERBOSE ) << "HypemPlugin thread: " << QThread::currentThread() << ", InfoSystemWorker thread: " << Tomahawk::InfoSystem::InfoSystem::instance()->workerThread().data()->currentThread(); switch ( requestData.type ) { case InfoChart: diff --git a/src/infoplugins/generic/hypem/HypemPlugin.h b/src/infoplugins/generic/hypem/HypemPlugin.h index 1848bd99e..63fc2f4c8 100644 --- a/src/infoplugins/generic/hypem/HypemPlugin.h +++ b/src/infoplugins/generic/hypem/HypemPlugin.h @@ -58,6 +58,7 @@ public slots: void chartTypes(); protected slots: + virtual void init(); virtual void getInfo( Tomahawk::InfoSystem::InfoRequestData requestData ); virtual void notInCacheSlot( Tomahawk::InfoSystem::InfoStringHash criteria, Tomahawk::InfoSystem::InfoRequestData requestData ); virtual void pushInfo( Tomahawk::InfoSystem::InfoPushData pushData ) diff --git a/src/infoplugins/generic/musicbrainz/MusicBrainzPlugin.cpp b/src/infoplugins/generic/musicbrainz/MusicBrainzPlugin.cpp index 625a527ce..3a52e3e52 100644 --- a/src/infoplugins/generic/musicbrainz/MusicBrainzPlugin.cpp +++ b/src/infoplugins/generic/musicbrainz/MusicBrainzPlugin.cpp @@ -129,32 +129,6 @@ MusicBrainzPlugin::notInCacheSlot( InfoStringHash criteria, InfoRequestData requ } -bool -MusicBrainzPlugin::isValidTrackData( Tomahawk::InfoSystem::InfoRequestData requestData ) -{ - if ( requestData.input.isNull() || !requestData.input.isValid() || !requestData.input.canConvert< QVariantMap >() ) - { - emit info( requestData, QVariant() ); - qDebug() << Q_FUNC_INFO << "Data null, invalid, or can't convert"; - return false; - } - QVariantMap hash = requestData.input.value< QVariantMap >(); - if ( hash[ "trackName" ].toString().isEmpty() ) - { - emit info( requestData, QVariant() ); - qDebug() << Q_FUNC_INFO << "Track name is empty"; - return false; - } - if ( hash[ "artistName" ].toString().isEmpty() ) - { - emit info( requestData, QVariant() ); - qDebug() << Q_FUNC_INFO << "No artist name found"; - return false; - } - return true; -} - - void MusicBrainzPlugin::artistSearchSlot() { diff --git a/src/infoplugins/generic/musicbrainz/MusicBrainzPlugin.h b/src/infoplugins/generic/musicbrainz/MusicBrainzPlugin.h index 17c57faf9..57ca6bc99 100644 --- a/src/infoplugins/generic/musicbrainz/MusicBrainzPlugin.h +++ b/src/infoplugins/generic/musicbrainz/MusicBrainzPlugin.h @@ -42,6 +42,7 @@ public: virtual ~MusicBrainzPlugin(); protected slots: + virtual void init() {} virtual void getInfo( Tomahawk::InfoSystem::InfoRequestData requestData ); virtual void notInCacheSlot( InfoStringHash criteria, InfoRequestData requestData ); @@ -58,9 +59,6 @@ private slots: void albumFoundSlot(); void tracksFoundSlot(); - -private: - bool isValidTrackData( Tomahawk::InfoSystem::InfoRequestData requestData ); }; } diff --git a/src/infoplugins/generic/musixmatch/MusixMatchPlugin.h b/src/infoplugins/generic/musixmatch/MusixMatchPlugin.h index 3f3557f8a..5c17c0c75 100644 --- a/src/infoplugins/generic/musixmatch/MusixMatchPlugin.h +++ b/src/infoplugins/generic/musixmatch/MusixMatchPlugin.h @@ -46,6 +46,7 @@ public slots: void trackLyricsSlot(); protected slots: + virtual void init() {} virtual void getInfo( Tomahawk::InfoSystem::InfoRequestData requestData ); virtual void pushInfo( Tomahawk::InfoSystem::InfoPushData pushData ) diff --git a/src/infoplugins/generic/newreleases/NewReleasesPlugin.cpp b/src/infoplugins/generic/newreleases/NewReleasesPlugin.cpp index 9d3c7cece..b5b2ae1a2 100644 --- a/src/infoplugins/generic/newreleases/NewReleasesPlugin.cpp +++ b/src/infoplugins/generic/newreleases/NewReleasesPlugin.cpp @@ -24,12 +24,36 @@ using namespace Tomahawk::InfoSystem; +bool newReleaseSort( const InfoStringHash& left, const InfoStringHash& right ) +{ + if ( !left.contains( "date" ) || !right.contains( "date" ) ) + { + return true; + } + + const QDate lDate = QDate::fromString( left[ "date" ], "yyyy-MM-dd" ); + const QDate rDate = QDate::fromString( right[ "date" ], "yyyy-MM-dd" ); + + return lDate > rDate; +} + + NewReleasesPlugin::NewReleasesPlugin() : InfoPlugin() , m_nrFetchJobs ( 0 ) { m_nrVersion = "0"; m_supportedGetTypes << InfoNewReleaseCapabilities << InfoNewRelease; +} + +NewReleasesPlugin::~NewReleasesPlugin() +{ + tDebug ( LOGVERBOSE ) << Q_FUNC_INFO; +} + +void +NewReleasesPlugin::init() +{ QVariantList source_qvarlist = TomahawkUtils::Cache::instance()->getData( "NewReleasesPlugin", "nr_sources" ).toList(); foreach( const QVariant & source, source_qvarlist ) { m_nrSources.append( source.toString() ); @@ -41,11 +65,6 @@ NewReleasesPlugin::NewReleasesPlugin() fetchNRSourcesList( true ); } -NewReleasesPlugin::~NewReleasesPlugin() -{ - tDebug ( LOGVERBOSE ) << Q_FUNC_INFO; -} - void NewReleasesPlugin::dataError ( InfoRequestData requestData ) { emit info ( requestData, QVariant() ); @@ -269,6 +288,7 @@ void NewReleasesPlugin::nrList() } } + if ( !albumNRs.isEmpty() ) newreleases.insert ( tr ( "Albums" ), QVariant::fromValue< QList< Tomahawk::InfoSystem::InfoStringHash > > ( albumNRs ) ); @@ -329,11 +349,14 @@ void NewReleasesPlugin::nrReturned() Tomahawk::InfoSystem::InfoStringHash pair; pair["artist"] = artist; pair["album"] = album; + pair["date"] = date; newreleases.append( pair ); } } - tDebug() << "NewReleasesPlugin:" << "\tgot " << newreleases.size() << " albums"; + qSort( newreleases.begin(), newreleases.end(), newReleaseSort ); + +// tDebug() << "NewReleasesPlugin:" << "\tgot " << newreleases.size() << " albums"; returnedData[ "albums" ] = QVariant::fromValue< QList< Tomahawk::InfoSystem::InfoStringHash > >( newreleases ); returnedData[ "type" ] = "albums"; Tomahawk::InfoSystem::InfoRequestData requestData = reply->property( "requestData" ).value< Tomahawk::InfoSystem::InfoRequestData >(); diff --git a/src/infoplugins/generic/newreleases/NewReleasesPlugin.h b/src/infoplugins/generic/newreleases/NewReleasesPlugin.h index 3c355a577..85b24c31d 100644 --- a/src/infoplugins/generic/newreleases/NewReleasesPlugin.h +++ b/src/infoplugins/generic/newreleases/NewReleasesPlugin.h @@ -44,6 +44,7 @@ public: virtual ~NewReleasesPlugin(); protected slots: + virtual void init(); virtual void getInfo( Tomahawk::InfoSystem::InfoRequestData requestData ); virtual void notInCacheSlot( Tomahawk::InfoSystem::InfoStringHash criteria, Tomahawk::InfoSystem::InfoRequestData requestData ); diff --git a/src/infoplugins/generic/rovi/RoviPlugin.h b/src/infoplugins/generic/rovi/RoviPlugin.h index 5c782edb2..b54c3577a 100644 --- a/src/infoplugins/generic/rovi/RoviPlugin.h +++ b/src/infoplugins/generic/rovi/RoviPlugin.h @@ -43,6 +43,8 @@ public: virtual ~RoviPlugin(); protected: + virtual void init() {} + virtual void notInCacheSlot( Tomahawk::InfoSystem::InfoStringHash criteria, Tomahawk::InfoSystem::InfoRequestData requestData ); virtual void pushInfo( Tomahawk::InfoSystem::InfoPushData pushData ) diff --git a/src/infoplugins/generic/spotify/SpotifyPlugin.h b/src/infoplugins/generic/spotify/SpotifyPlugin.h index e20e69aeb..c21600090 100644 --- a/src/infoplugins/generic/spotify/SpotifyPlugin.h +++ b/src/infoplugins/generic/spotify/SpotifyPlugin.h @@ -59,6 +59,7 @@ public slots: void chartTypes(); protected slots: + virtual void init() {} virtual void getInfo( Tomahawk::InfoSystem::InfoRequestData requestData ); virtual void notInCacheSlot( Tomahawk::InfoSystem::InfoStringHash criteria, Tomahawk::InfoSystem::InfoRequestData requestData ); virtual void pushInfo( Tomahawk::InfoSystem::InfoPushData pushData ) diff --git a/src/infoplugins/linux/fdonotify/FdoNotifyPlugin.h b/src/infoplugins/linux/fdonotify/FdoNotifyPlugin.h index fc56e6267..fc672c00a 100644 --- a/src/infoplugins/linux/fdonotify/FdoNotifyPlugin.h +++ b/src/infoplugins/linux/fdonotify/FdoNotifyPlugin.h @@ -39,6 +39,8 @@ public: virtual ~FdoNotifyPlugin(); protected slots: + virtual void init() {} + virtual void getInfo( Tomahawk::InfoSystem::InfoRequestData requestData ) { Q_UNUSED( requestData ); diff --git a/src/infoplugins/linux/mpris/MprisPlugin.cpp b/src/infoplugins/linux/mpris/MprisPlugin.cpp index 02de7e158..8f8f6610b 100644 --- a/src/infoplugins/linux/mpris/MprisPlugin.cpp +++ b/src/infoplugins/linux/mpris/MprisPlugin.cpp @@ -54,7 +54,17 @@ MprisPlugin::MprisPlugin() // Types of pushInfo we care about m_supportedPushTypes << InfoNowPlaying << InfoNowPaused << InfoNowResumed << InfoNowStopped; +} + +MprisPlugin::~MprisPlugin() +{ +} + + +void +MprisPlugin::init() +{ // DBus connection new MprisPluginRootAdaptor( this ); new MprisPluginPlayerAdaptor( this ); @@ -84,11 +94,6 @@ MprisPlugin::MprisPlugin() } -MprisPlugin::~MprisPlugin() -{ -} - - // org.mpris.MediaPlayer2 bool diff --git a/src/infoplugins/linux/mpris/MprisPlugin.h b/src/infoplugins/linux/mpris/MprisPlugin.h index 9e4d54e04..8a11fc1d4 100644 --- a/src/infoplugins/linux/mpris/MprisPlugin.h +++ b/src/infoplugins/linux/mpris/MprisPlugin.h @@ -142,6 +142,8 @@ public slots: void Stop(); protected slots: + virtual void init(); + virtual void getInfo( Tomahawk::InfoSystem::InfoRequestData requestData ) { Q_UNUSED( requestData ); diff --git a/src/infoplugins/mac/adium/AdiumPlugin.h b/src/infoplugins/mac/adium/AdiumPlugin.h index a05b0863b..a4d3d50bf 100644 --- a/src/infoplugins/mac/adium/AdiumPlugin.h +++ b/src/infoplugins/mac/adium/AdiumPlugin.h @@ -44,6 +44,8 @@ public: virtual ~AdiumPlugin(); protected slots: + virtual void init() {} + virtual void getInfo( Tomahawk::InfoSystem::InfoRequestData requestData ) { Q_UNUSED( requestData ); diff --git a/src/libtomahawk/AclRegistry.cpp b/src/libtomahawk/AclRegistry.cpp index f1554ede2..2adbe3683 100644 --- a/src/libtomahawk/AclRegistry.cpp +++ b/src/libtomahawk/AclRegistry.cpp @@ -26,10 +26,13 @@ #include "TomahawkApp.h" #include "Source.h" +#ifndef ENABLE_HEADLESS + #include "jobview/AclJobItem.h" + #include "jobview/JobStatusView.h" + #include "jobview/JobStatusModel.h" +#endif + #include "utils/Logger.h" -#include "jobview/AclJobItem.h" -#include "jobview/JobStatusView.h" -#include "jobview/JobStatusModel.h" QDataStream& operator<<( QDataStream &out, const ACLRegistry::User &user ) @@ -161,6 +164,7 @@ ACLRegistry::isAuthorizedUser( const QString& dbid, const QString &username, ACL return ACLRegistry::NotFound; } #endif + m_cache.append( user ); emit aclResult( dbid, username, user.acl ); return user.acl; @@ -168,6 +172,7 @@ ACLRegistry::isAuthorizedUser( const QString& dbid, const QString &username, ACL #ifndef ENABLE_HEADLESS + void ACLRegistry::getUserDecision( ACLRegistry::User user, const QString &username ) { @@ -176,7 +181,6 @@ ACLRegistry::getUserDecision( ACLRegistry::User user, const QString &username ) m_jobQueue.enqueue( job ); queueNextJob(); } -#endif void @@ -233,6 +237,8 @@ ACLRegistry::queueNextJob() } } +#endif + void ACLRegistry::load() diff --git a/src/libtomahawk/AclRegistry.h b/src/libtomahawk/AclRegistry.h index f4f14494a..05c4c7435 100644 --- a/src/libtomahawk/AclRegistry.h +++ b/src/libtomahawk/AclRegistry.h @@ -100,13 +100,13 @@ public slots: **/ ACLRegistry::ACL isAuthorizedUser( const QString &dbid, const QString &username, ACLRegistry::ACL globalType = ACLRegistry::NotFound, bool skipEmission = false ); - #ifndef ENABLE_HEADLESS +#ifndef ENABLE_HEADLESS void getUserDecision( ACLRegistry::User user, const QString &username ); - #endif private slots: void userDecision( ACLRegistry::User user ); void queueNextJob(); +#endif private: /** diff --git a/src/libtomahawk/ActionCollection.cpp b/src/libtomahawk/ActionCollection.cpp index e69f723bd..bc6908e30 100644 --- a/src/libtomahawk/ActionCollection.cpp +++ b/src/libtomahawk/ActionCollection.cpp @@ -32,7 +32,7 @@ ActionCollection* ActionCollection::instance() } -ActionCollection::ActionCollection( QObject *parent ) +ActionCollection::ActionCollection( QObject* parent ) : QObject( parent ) { s_instance = this; @@ -79,11 +79,11 @@ ActionCollection::initActions() m_actionCollection[ "quit" ] = new QAction( tr( "&Quit" ), this ); // connect actions to AudioEngine -// AudioEngine *ae = AudioEngine::instance(); -// connect( m_actionCollection[ "playPause" ], SIGNAL( triggered() ), ae, SLOT( playPause() ), Qt::UniqueConnection ); -// connect( m_actionCollection[ "stop" ], SIGNAL( triggered() ), ae, SLOT( stop() ), Qt::UniqueConnection ); -// connect( m_actionCollection[ "previousTrack" ], SIGNAL( triggered() ), ae, SLOT( previous() ), Qt::UniqueConnection ); -// connect( m_actionCollection[ "nextTrack" ], SIGNAL( triggered() ), ae, SLOT( next() ), Qt::UniqueConnection ); + AudioEngine *ae = AudioEngine::instance(); + connect( m_actionCollection[ "playPause" ], SIGNAL( triggered() ), ae, SLOT( playPause() ), Qt::UniqueConnection ); + connect( m_actionCollection[ "stop" ], SIGNAL( triggered() ), ae, SLOT( stop() ), Qt::UniqueConnection ); + connect( m_actionCollection[ "previousTrack" ], SIGNAL( triggered() ), ae, SLOT( previous() ), Qt::UniqueConnection ); + connect( m_actionCollection[ "nextTrack" ], SIGNAL( triggered() ), ae, SLOT( next() ), Qt::UniqueConnection ); } diff --git a/src/libtomahawk/ActionCollection.h b/src/libtomahawk/ActionCollection.h index 2eb327622..378b13cba 100644 --- a/src/libtomahawk/ActionCollection.h +++ b/src/libtomahawk/ActionCollection.h @@ -38,7 +38,7 @@ public: static ActionCollection* instance(); - ActionCollection( QObject *parent); + ActionCollection( QObject *parent ); ~ActionCollection(); void initActions(); diff --git a/src/libtomahawk/Album.cpp b/src/libtomahawk/Album.cpp index 4dcad4ac3..a639042c7 100644 --- a/src/libtomahawk/Album.cpp +++ b/src/libtomahawk/Album.cpp @@ -82,8 +82,8 @@ Album::Album( unsigned int id, const QString& name, const Tomahawk::artist_ptr& , m_id( id ) , m_name( name ) , m_artist( artist ) - , m_infoLoaded( false ) - , m_infoLoading( false ) + , m_coverLoaded( false ) + , m_coverLoading( false ) #ifndef ENABLE_HEADLESS , m_cover( 0 ) #endif @@ -110,19 +110,17 @@ Album::artist() const QPixmap Album::cover( const QSize& size, bool forceLoad ) const { - if ( !m_infoLoaded && !m_infoLoading ) + if ( !m_coverLoaded && !m_coverLoading ) { if ( !forceLoad ) return QPixmap(); - m_uuid = uuid(); - Tomahawk::InfoSystem::InfoStringHash trackInfo; trackInfo["artist"] = artist()->name(); trackInfo["album"] = name(); Tomahawk::InfoSystem::InfoRequestData requestData; - requestData.caller = m_uuid; + requestData.caller = infoid(); requestData.type = Tomahawk::InfoSystem::InfoAlbumCoverArt; requestData.input = QVariant::fromValue< Tomahawk::InfoSystem::InfoStringHash >( trackInfo ); requestData.customData = QVariantMap(); @@ -137,7 +135,7 @@ Album::cover( const QSize& size, bool forceLoad ) const Tomahawk::InfoSystem::InfoSystem::instance()->getInfo( requestData ); - m_infoLoading = true; + m_coverLoading = true; } if ( !m_cover && !m_coverBuffer.isEmpty() ) @@ -170,7 +168,7 @@ Album::cover( const QSize& size, bool forceLoad ) const void Album::infoSystemInfo( const Tomahawk::InfoSystem::InfoRequestData& requestData, const QVariant& output ) { - if ( requestData.caller != m_uuid || + if ( requestData.caller != infoid() || requestData.type != Tomahawk::InfoSystem::InfoAlbumCoverArt ) { return; @@ -183,9 +181,10 @@ Album::infoSystemInfo( const Tomahawk::InfoSystem::InfoRequestData& requestData, if ( ba.length() ) { m_coverBuffer = ba; - emit coverChanged(); } + + m_coverLoaded = true; } } @@ -193,7 +192,7 @@ Album::infoSystemInfo( const Tomahawk::InfoSystem::InfoRequestData& requestData, void Album::infoSystemFinished( const QString& target ) { - if ( target != m_uuid ) + if ( target != infoid() ) return; disconnect( Tomahawk::InfoSystem::InfoSystem::instance(), SIGNAL( info( Tomahawk::InfoSystem::InfoRequestData, QVariant ) ), @@ -202,7 +201,8 @@ Album::infoSystemFinished( const QString& target ) disconnect( Tomahawk::InfoSystem::InfoSystem::instance(), SIGNAL( finished( QString ) ), this, SLOT( infoSystemFinished( QString ) ) ); - m_infoLoaded = true; + m_coverLoading = false; + emit updated(); } @@ -230,3 +230,13 @@ Album::tracks( ModelMode mode, const Tomahawk::collection_ptr& collection ) { return playlistInterface( mode, collection )->tracks(); } + + +QString +Album::infoid() const +{ + if ( m_uuid.isEmpty() ) + m_uuid = uuid(); + + return m_uuid; +} \ No newline at end of file diff --git a/src/libtomahawk/Album.h b/src/libtomahawk/Album.h index a0fa52dd9..89c6ad09f 100644 --- a/src/libtomahawk/Album.h +++ b/src/libtomahawk/Album.h @@ -56,7 +56,7 @@ public: #ifndef ENABLE_HEADLESS QPixmap cover( const QSize& size, bool forceLoad = true ) const; #endif - bool infoLoaded() const { return m_infoLoaded; } + bool coverLoaded() const { return m_coverLoaded; } QList tracks( ModelMode mode = Mixed, const Tomahawk::collection_ptr& collection = Tomahawk::collection_ptr() ); Tomahawk::playlistinterface_ptr playlistInterface( ModelMode mode, const Tomahawk::collection_ptr& collection = Tomahawk::collection_ptr() ); @@ -77,6 +77,7 @@ private slots: private: Q_DISABLE_COPY( Album ) + QString infoid() const; unsigned int m_id; QString m_name; @@ -85,8 +86,8 @@ private: artist_ptr m_artist; QByteArray m_coverBuffer; - bool m_infoLoaded; - mutable bool m_infoLoading; + bool m_coverLoaded; + mutable bool m_coverLoading; mutable QString m_uuid; #ifndef ENABLE_HEADLESS diff --git a/src/libtomahawk/Artist.cpp b/src/libtomahawk/Artist.cpp index c70aeb593..fbd30f477 100644 --- a/src/libtomahawk/Artist.cpp +++ b/src/libtomahawk/Artist.cpp @@ -82,9 +82,10 @@ Artist::Artist( unsigned int id, const QString& name ) : QObject() , m_id( id ) , m_name( name ) - , m_infoLoaded( false ) - , m_infoLoading( false ) + , m_coverLoaded( false ) + , m_coverLoading( false ) , m_simArtistsLoaded( false ) + , m_biographyLoaded( false ) , m_infoJobs( 0 ) #ifndef ENABLE_HEADLESS , m_cover( 0 ) @@ -111,9 +112,6 @@ Artist::albums( ModelMode mode, const Tomahawk::collection_ptr& collection ) con if ( !collection.isNull() ) dbLoaded = false; - m_uuid = uuid(); - tDebug() << Q_FUNC_INFO << mode; - if ( ( mode == DatabaseMode || mode == Mixed ) && !dbLoaded ) { DatabaseCommand_AllAlbums* cmd = new DatabaseCommand_AllAlbums( collection, artist ); @@ -131,7 +129,7 @@ Artist::albums( ModelMode mode, const Tomahawk::collection_ptr& collection ) con artistInfo["artist"] = name(); Tomahawk::InfoSystem::InfoRequestData requestData; - requestData.caller = m_uuid; + requestData.caller = infoid(); requestData.input = QVariant::fromValue< Tomahawk::InfoSystem::InfoStringHash >( artistInfo ); requestData.type = Tomahawk::InfoSystem::InfoArtistReleases; @@ -171,7 +169,7 @@ Artist::similarArtists() const artistInfo["artist"] = name(); Tomahawk::InfoSystem::InfoRequestData requestData; - requestData.caller = m_uuid; + requestData.caller = infoid(); requestData.customData = QVariantMap(); requestData.input = QVariant::fromValue< Tomahawk::InfoSystem::InfoStringHash >( artistInfo ); @@ -194,6 +192,35 @@ Artist::similarArtists() const } +QString +Artist::biography() const +{ + if ( !m_biographyLoaded ) + { + Tomahawk::InfoSystem::InfoRequestData requestData; + requestData.caller = infoid(); + requestData.customData = QVariantMap(); + + requestData.input = name(); + requestData.type = Tomahawk::InfoSystem::InfoArtistBiography; + requestData.requestId = TomahawkUtils::infosystemRequestId(); + + connect( Tomahawk::InfoSystem::InfoSystem::instance(), + SIGNAL( info( Tomahawk::InfoSystem::InfoRequestData, QVariant ) ), + SLOT( infoSystemInfo( Tomahawk::InfoSystem::InfoRequestData, QVariant ) ), Qt::UniqueConnection ); + + connect( Tomahawk::InfoSystem::InfoSystem::instance(), + SIGNAL( finished( QString ) ), + SLOT( infoSystemFinished( QString ) ), Qt::UniqueConnection ); + + m_infoJobs++; + Tomahawk::InfoSystem::InfoSystem::instance()->getInfo( requestData ); + } + + return m_biography; +} + + void Artist::loadStats() { @@ -259,7 +286,7 @@ Artist::onAlbumsFound( const QList< album_ptr >& albums, const QVariant& data ) void Artist::infoSystemInfo( Tomahawk::InfoSystem::InfoRequestData requestData, QVariant output ) { - if ( requestData.caller != m_uuid ) + if ( requestData.caller != infoid() ) return; QVariantMap returnedData = output.value< QVariantMap >(); @@ -274,7 +301,6 @@ Artist::infoSystemInfo( Tomahawk::InfoSystem::InfoRequestData requestData, QVari QList< album_ptr > albums; foreach ( const QString& albumName, albumNames ) { - tDebug() << Q_FUNC_INFO << albumName; Tomahawk::album_ptr album = Tomahawk::Album::get( m_ownRef.toStrongRef(), albumName, false ); m_officialAlbums << album; albums << album; @@ -295,9 +321,10 @@ Artist::infoSystemInfo( Tomahawk::InfoSystem::InfoRequestData requestData, QVari if ( ba.length() ) { m_coverBuffer = ba; - m_infoLoaded = true; emit coverChanged(); } + + m_coverLoaded = true; } break; @@ -317,6 +344,22 @@ Artist::infoSystemInfo( Tomahawk::InfoSystem::InfoRequestData requestData, QVari break; } + case InfoSystem::InfoArtistBiography: + { + QVariantMap bmap = output.toMap(); + + foreach ( const QString& source, bmap.keys() ) + { + if ( source == "last.fm" ) + m_biography = bmap[ source ].toHash()[ "text" ].toString(); + } + + m_biographyLoaded = true; + emit biographyLoaded(); + + break; + } + default: Q_ASSERT( false ); } @@ -328,7 +371,7 @@ Artist::infoSystemFinished( QString target ) { Q_UNUSED( target ); - if ( target != m_uuid ) + if ( target != infoid() ) return; if ( --m_infoJobs == 0 ) @@ -340,6 +383,8 @@ Artist::infoSystemFinished( QString target ) this, SLOT( infoSystemFinished( QString ) ) ); } + m_coverLoading = false; + emit updated(); } @@ -348,17 +393,16 @@ Artist::infoSystemFinished( QString target ) QPixmap Artist::cover( const QSize& size, bool forceLoad ) const { - if ( !m_infoLoaded && !m_infoLoading ) + if ( !m_coverLoaded && !m_coverLoading ) { if ( !forceLoad ) return QPixmap(); - m_uuid = uuid(); Tomahawk::InfoSystem::InfoStringHash trackInfo; trackInfo["artist"] = name(); Tomahawk::InfoSystem::InfoRequestData requestData; - requestData.caller = m_uuid; + requestData.caller = infoid(); requestData.type = Tomahawk::InfoSystem::InfoArtistImages; requestData.input = QVariant::fromValue< Tomahawk::InfoSystem::InfoStringHash >( trackInfo ); requestData.customData = QVariantMap(); @@ -374,7 +418,7 @@ Artist::cover( const QSize& size, bool forceLoad ) const m_infoJobs++; Tomahawk::InfoSystem::InfoSystem::instance()->getInfo( requestData ); - m_infoLoading = true; + m_coverLoading = true; } if ( !m_cover && !m_coverBuffer.isEmpty() ) @@ -428,3 +472,13 @@ Artist::tracks( ModelMode mode, const Tomahawk::collection_ptr& collection ) { return playlistInterface( mode, collection )->tracks(); } + + +QString +Artist::infoid() const +{ + if ( m_uuid.isEmpty() ) + m_uuid = uuid(); + + return m_uuid; +} diff --git a/src/libtomahawk/Artist.h b/src/libtomahawk/Artist.h index a19f5931b..3eef077a1 100644 --- a/src/libtomahawk/Artist.h +++ b/src/libtomahawk/Artist.h @@ -49,8 +49,6 @@ public: QString name() const { return m_name; } QString sortname() const { return m_sortname; } - bool infoLoaded() const { return m_infoLoaded; } - QList albums( ModelMode mode = Mixed, const Tomahawk::collection_ptr& collection = Tomahawk::collection_ptr() ) const; QList similarArtists() const; @@ -61,10 +59,13 @@ public: QList< Tomahawk::PlaybackLog > playbackHistory( const Tomahawk::source_ptr& source = Tomahawk::source_ptr() ) const; void setPlaybackHistory( const QList< Tomahawk::PlaybackLog >& playbackData ); unsigned int playbackCount( const Tomahawk::source_ptr& source = Tomahawk::source_ptr() ); + + QString biography() const; #ifndef ENABLE_HEADLESS QPixmap cover( const QSize& size, bool forceLoad = true ) const; #endif + bool coverLoaded() const { return m_coverLoaded; } Tomahawk::playlistinterface_ptr playlistInterface(); @@ -78,6 +79,7 @@ signals: void updated(); void coverChanged(); void similarArtistsLoaded(); + void biographyLoaded(); void statsLoaded(); private slots: @@ -89,15 +91,17 @@ private slots: private: Artist(); + QString infoid() const; unsigned int m_id; QString m_name; QString m_sortname; - bool m_infoLoaded; - mutable bool m_infoLoading; + bool m_coverLoaded; + mutable bool m_coverLoading; QHash m_albumsLoaded; bool m_simArtistsLoaded; + bool m_biographyLoaded; mutable QString m_uuid; mutable int m_infoJobs; @@ -105,6 +109,7 @@ private: QList m_databaseAlbums; QList m_officialAlbums; QList m_similarArtists; + QString m_biography; bool m_playbackHistoryLoaded; QList< PlaybackLog > m_playbackHistory; diff --git a/src/libtomahawk/AtticaManager.cpp b/src/libtomahawk/AtticaManager.cpp index 3d89a7593..f0782b4d3 100644 --- a/src/libtomahawk/AtticaManager.cpp +++ b/src/libtomahawk/AtticaManager.cpp @@ -22,6 +22,7 @@ #include "TomahawkSettingsGui.h" #include "Pipeline.h" #include "Source.h" +#include "config.h" #include @@ -35,12 +36,24 @@ #include "accounts/ResolverAccount.h" #include "accounts/AccountManager.h" #include "utils/BinaryInstallerHelper.h" +#include "utils/Closure.h" using namespace Attica; AtticaManager* AtticaManager::s_instance = 0; +// Sort binary resolvers above script resolvers, and script resolvers by download count +bool +resolverSort( const Attica::Content& first, const Attica::Content& second ) +{ + if ( !first.attribute( "typeid" ).isEmpty() && second.attribute( "typeid" ).isEmpty() ) + return true; + + return first.downloads() > second.downloads(); +} + + AtticaManager::AtticaManager( QObject* parent ) : QObject( parent ) , m_resolverJobsLoaded( 0 ) @@ -48,7 +61,13 @@ AtticaManager::AtticaManager( QObject* parent ) connect( &m_manager, SIGNAL( providerAdded( Attica::Provider ) ), this, SLOT( providerAdded( Attica::Provider ) ) ); // resolvers - m_manager.addProviderFile( QUrl( "http://bakery.tomahawk-player.org/resolvers/providers.xml" ) ); +// m_manager.addProviderFile( QUrl( "http://bakery.tomahawk-player.org/resolvers/providers.xml" ) ); + + const QString url = QString( "http://bakery.tomahawk-player.org/resolvers/providers.xml?version=%1" ).arg( TomahawkUtils::appFriendlyVersion() ); + QNetworkReply* reply = TomahawkUtils::nam()->get( QNetworkRequest( QUrl( url ) ) ); + NewClosure( reply, SIGNAL( finished() ), this, SLOT( providerFetched( QNetworkReply* ) ), reply ); + connect( reply, SIGNAL( error( QNetworkReply::NetworkError ) ), this, SLOT( providerError( QNetworkReply::NetworkError ) ) ); + // m_manager.addProviderFile( QUrl( "http://lycophron/resolvers/providers.xml" ) ); qRegisterMetaType< Attica::Content >( "Attica::Content" ); @@ -58,6 +77,15 @@ AtticaManager::AtticaManager( QObject* parent ) AtticaManager::~AtticaManager() { savePixmapsToCache(); + + + foreach( const QString& id, m_resolverStates.keys() ) + { + if ( !m_resolverStates[ id ].pixmap ) + continue; + + delete m_resolverStates[ id ].pixmap; + } } @@ -243,6 +271,25 @@ AtticaManager::resolverData(const QString &atticaId) const } +void +AtticaManager::providerError( QNetworkReply::NetworkError err ) +{ + // So those who care know + emit resolversLoaded( Content::List() ); +} + + +void +AtticaManager::providerFetched( QNetworkReply* reply ) +{ + Q_ASSERT( reply ); + if ( !reply ) + return; + + m_manager.addProviderFromXml( reply->readAll() ); +} + + void AtticaManager::providerAdded( const Provider& provider ) { @@ -328,7 +375,10 @@ AtticaManager::resolversList( BaseJob* j ) syncServerData(); if ( ++m_resolverJobsLoaded == 2 ) + { + qSort( m_resolvers.begin(), m_resolvers.end(), resolverSort ); emit resolversLoaded( m_resolvers ); + } } @@ -345,6 +395,15 @@ AtticaManager::binaryResolversList( BaseJob* j ) platform = "osx"; #elif defined(Q_OS_WIN) platform = "win"; +#elif defined(Q_OS_LINUX) && defined(__GNUC__) && defined(__x86_64__) + platform = "linux-x64"; +#elif defined(Q_OS_LINUX) // Horrible assumption here... + platform = "linux-x86"; +#endif + + // Override if no binary resolvers were requested +#ifndef WITH_BINARY_ATTICA + platform = QString(); #endif foreach ( const Content& c, binaryResolvers ) @@ -370,7 +429,10 @@ AtticaManager::binaryResolversList( BaseJob* j ) } if ( ++m_resolverJobsLoaded == 2 ) + { + qSort( m_resolvers.begin(), m_resolvers.end(), resolverSort ); emit resolversLoaded( m_resolvers ); + } } @@ -434,7 +496,20 @@ AtticaManager::syncServerData() void -AtticaManager::installResolver( const Content& resolver, bool autoCreateAccount ) +AtticaManager::installResolver( const Content& resolver, bool autoCreate ) +{ + doInstallResolver( resolver, autoCreate, 0 ); +} + + +void +AtticaManager::installResolverWithHandler( const Content& resolver, Tomahawk::Accounts::AtticaResolverAccount* handler ) +{ + doInstallResolver( resolver, false, handler ); +} + + +void AtticaManager::doInstallResolver( const Content& resolver, bool autoCreate, Tomahawk::Accounts::AtticaResolverAccount* handler ) { Q_ASSERT( !resolver.id().isNull() ); @@ -450,7 +525,8 @@ AtticaManager::installResolver( const Content& resolver, bool autoCreateAccount ItemJob< DownloadItem >* job = m_resolverProvider.downloadLink( resolver.id() ); connect( job, SIGNAL( finished( Attica::BaseJob* ) ), this, SLOT( resolverDownloadFinished( Attica::BaseJob* ) ) ); job->setProperty( "resolverId", resolver.id() ); - job->setProperty( "createAccount", autoCreateAccount ); + job->setProperty( "createAccount", autoCreate ); + job->setProperty( "handler", QVariant::fromValue< QObject* >( handler ) ); job->setProperty( "binarySignature", resolver.attribute("signature")); job->start(); @@ -488,6 +564,7 @@ AtticaManager::resolverDownloadFinished ( BaseJob* j ) connect( reply, SIGNAL( finished() ), this, SLOT( payloadFetched() ) ); reply->setProperty( "resolverId", job->property( "resolverId" ) ); reply->setProperty( "createAccount", job->property( "createAccount" ) ); + reply->setProperty( "handler", job->property( "handler" ) ); reply->setProperty( "binarySignature", job->property( "binarySignature" ) ); } else @@ -509,14 +586,14 @@ AtticaManager::payloadFetched() // we got a zip file, save it to a temporary file, then unzip it to our destination data dir if ( reply->error() == QNetworkReply::NoError ) { - QTemporaryFile f( QDir::tempPath() + QDir::separator() + "tomahawkattica_XXXXXX.zip" ); - if ( !f.open() ) + QTemporaryFile* f = new QTemporaryFile( QDir::tempPath() + QDir::separator() + "tomahawkattica_XXXXXX.zip" ); + if ( !f->open() ) { - tLog() << "Failed to write zip file to temp file:" << f.fileName(); + tLog() << "Failed to write zip file to temp file:" << f->fileName(); return; } - f.write( reply->readAll() ); - f.close(); + f->write( reply->readAll() ); + f->close(); if ( m_resolverStates[ resolverId ].binary ) { @@ -526,20 +603,20 @@ AtticaManager::payloadFetched() Q_ASSERT( !signature.isEmpty() ); if ( signature.isEmpty() ) return; - if ( !TomahawkUtils::verifyFile( f.fileName(), signature ) ) + if ( !TomahawkUtils::verifyFile( f->fileName(), signature ) ) { - qWarning() << "FILE SIGNATURE FAILED FOR BINARY RESOLVER! WARNING! :" << f.fileName() << signature; + qWarning() << "FILE SIGNATURE FAILED FOR BINARY RESOLVER! WARNING! :" << f->fileName() << signature; } else { - TomahawkUtils::extractBinaryResolver( f.fileName(), new BinaryInstallerHelper( resolverId, reply->property( "createAccount" ).toBool(), this ) ); - // Don't emit success or failed yet, helpre will do that. + TomahawkUtils::extractBinaryResolver( f->fileName(), new BinaryInstallerHelper( f, resolverId, reply->property( "createAccount" ).toBool(), this ) ); + // Don't emit success or failed yet, helper will do that. return; } } else { - QDir dir( TomahawkUtils::extractScriptPayload( f.fileName(), resolverId ) ); + QDir dir( TomahawkUtils::extractScriptPayload( f->fileName(), resolverId ) ); QString resolverPath = dir.absoluteFilePath( m_resolverStates[ resolverId ].scriptPath ); if ( !resolverPath.isEmpty() ) @@ -547,7 +624,14 @@ AtticaManager::payloadFetched() // update with absolute, not relative, path m_resolverStates[ resolverId ].scriptPath = resolverPath; - if ( reply->property( "createAccount" ).toBool() ) + Tomahawk::Accounts::AtticaResolverAccount* handlerAccount = qobject_cast< Tomahawk::Accounts::AtticaResolverAccount* >( reply->property( "handler" ).value< QObject* >() ); + const bool createAccount = reply->property( "createAccount" ).toBool(); + if ( handlerAccount ) + { + handlerAccount->setPath( resolverPath ); + Tomahawk::Accounts::AccountManager::instance()->enableAccount( handlerAccount ); + } + else if ( createAccount ) { // Do the install / add to tomahawk Tomahawk::Accounts::Account* resolver = Tomahawk::Accounts::ResolverAccountFactory::createFromPath( resolverPath, "resolveraccount", true ); @@ -558,6 +642,8 @@ AtticaManager::payloadFetched() installedSuccessfully = true; } } + + delete f; } else { diff --git a/src/libtomahawk/AtticaManager.h b/src/libtomahawk/AtticaManager.h index 079672529..bca1d7440 100644 --- a/src/libtomahawk/AtticaManager.h +++ b/src/libtomahawk/AtticaManager.h @@ -24,6 +24,7 @@ #include #include #include +#include #include "DllMacro.h" #include "accounts/Account.h" @@ -32,6 +33,12 @@ #include #include +namespace Tomahawk { +namespace Accounts { +class AtticaResolverAccount; +} +} + class BinaryInstallerHelper; class DLLEXPORT AtticaManager : public QObject @@ -105,6 +112,8 @@ public: public slots: void installResolver( const Attica::Content& resolver, bool autoCreateAccount = true ); + void installResolverWithHandler( const Attica::Content& resolver, Tomahawk::Accounts::AtticaResolverAccount* handler ); + void upgradeResolver( const Attica::Content& resolver ); signals: @@ -116,7 +125,10 @@ signals: void resolverInstallationFailed( const QString& resolverId ); void startedInstalling( const QString& resolverId ); + private slots: + void providerFetched( QNetworkReply* reply ); + void providerError( QNetworkReply::NetworkError ); void providerAdded( const Attica::Provider& ); void categoriesReturned( Attica::BaseJob* ); void resolversList( Attica::BaseJob* ); @@ -131,8 +143,8 @@ private slots: void syncServerData(); private: - QString extractPayload( const QString& filename, const QString& resolverId ) const; void doResolverRemove( const QString& id ) const; + void doInstallResolver( const Attica::Content& resolver, bool autoCreate, Tomahawk::Accounts::AtticaResolverAccount* handler ); Attica::ProviderManager m_manager; @@ -162,5 +174,5 @@ protected: }; Q_DECLARE_METATYPE( Attica::Content ); - +Q_DECLARE_METATYPE( QNetworkReply* ); #endif // ATTICAMANAGER_H diff --git a/src/libtomahawk/CMakeLists.txt b/src/libtomahawk/CMakeLists.txt index 170b72524..2c0e5433c 100644 --- a/src/libtomahawk/CMakeLists.txt +++ b/src/libtomahawk/CMakeLists.txt @@ -6,6 +6,10 @@ SET( QT_USE_QTNETWORK TRUE ) SET( QT_USE_QTXML TRUE ) SET( QT_USE_QTUITOOLS TRUE ) +IF( UNIX AND NOT APPLE ) + SET( QT_USE_QTDBUS TRUE ) +ENDIF( UNIX AND NOT APPLE ) + include( ${QT_USE_FILE} ) add_definitions( ${QT_DEFINITIONS} ) @@ -48,31 +52,20 @@ set( libGuiSources playlist/TreeModel.cpp playlist/TreeProxyModel.cpp playlist/TreeProxyModelPlaylistInterface.cpp - playlist/TreeHeader.cpp playlist/TreeItemDelegate.cpp - playlist/CollectionProxyModel.cpp - playlist/CollectionProxyModelPlaylistInterface.cpp - playlist/CollectionFlatModel.cpp - playlist/CollectionView.cpp playlist/PlaylistModel.cpp - playlist/PlaylistProxyModel.cpp - playlist/PlaylistProxyModelPlaylistInterface.cpp playlist/PlaylistView.cpp playlist/PlaylistItemDelegate.cpp playlist/QueueProxyModel.cpp - playlist/QueueProxyModelPlaylistInterface.cpp playlist/QueueView.cpp playlist/PlayableModel.cpp playlist/PlayableProxyModel.cpp playlist/PlayableProxyModelPlaylistInterface.cpp playlist/TrackView.cpp - playlist/TrackHeader.cpp playlist/AlbumModel.cpp - playlist/AlbumProxyModel.cpp - playlist/AlbumProxyModelPlaylistInterface.cpp - playlist/AlbumItemDelegate.cpp - playlist/AlbumView.cpp - playlist/ArtistView.cpp + playlist/GridItemDelegate.cpp + playlist/GridView.cpp + playlist/TreeView.cpp playlist/CustomPlaylistView.cpp playlist/ViewHeader.cpp playlist/RecentlyAddedModel.cpp @@ -122,6 +115,8 @@ set( libGuiSources utils/SmartPointerList.h utils/AnimatedSpinner.cpp utils/BinaryInstallerHelper.cpp + utils/BinaryExtractWorker.cpp + utils/SharedTimeLine.cpp widgets/AnimatedCounterLabel.cpp widgets/CheckDirTree.cpp @@ -189,13 +184,25 @@ set( libSources accounts/AccountModel.cpp accounts/AccountModelFilterProxy.cpp accounts/ResolverAccount.cpp + accounts/AccountDelegate.cpp + accounts/DelegateConfigWrapper.cpp + accounts/AccountFactoryWrapper.cpp + accounts/AccountFactoryWrapperDelegate.cpp + + accounts/spotify/SpotifyAccount.cpp + accounts/spotify/SpotifyAccountConfig.cpp + accounts/spotify/SpotifyPlaylistUpdater.cpp + + accounts/lastfm/LastFmAccount.cpp + accounts/lastfm/LastFmConfig.cpp + accounts/lastfm/LastFmInfoPlugin.cpp + sip/SipPlugin.cpp sip/SipHandler.cpp sip/SipInfo.cpp audio/AudioEngine.cpp - database/Database.cpp database/FuzzyIndex.cpp database/DatabaseCollection.cpp @@ -248,6 +255,7 @@ set( libSources database/DatabaseCommand_TrackAttributes.cpp database/DatabaseCommand_SetTrackAttributes.cpp database/Database.cpp + database/TomahawkSqlQuery.cpp infosystem/InfoSystem.cpp infosystem/InfoSystemCache.cpp @@ -286,6 +294,7 @@ set( libSources utils/Qnr_IoDeviceStream.cpp utils/XspfLoader.cpp utils/TomahawkCache.cpp + utils/GuiHelpers.cpp thirdparty/kdsingleapplicationguard/kdsingleapplicationguard.cpp thirdparty/kdsingleapplicationguard/kdsharedmemorylocker.cpp @@ -309,6 +318,9 @@ set( libUI ${libUI} playlist/QueueView.ui context/ContextWidget.ui infobar/InfoBar.ui + accounts/AccountFactoryWrapper.ui + accounts/spotify/SpotifyAccountConfig.ui + accounts/lastfm/LastFmConfig.ui ) include_directories( . ${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_BINARY_DIR}/.. .. @@ -317,9 +329,10 @@ include_directories( . ${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_BINARY_DIR}/. ${QJSON_INCLUDE_DIR} ${LIBECHONEST_INCLUDE_DIR} ${LIBECHONEST_INCLUDE_DIR}/.. + ${LIBLASTFM_INCLUDE_DIRS} + ${LIBLASTFM_INCLUDE_DIRS}/.. ${CLUCENE_INCLUDE_DIRS} ${PHONON_INCLUDES} - ${CMAKE_BINARY_DIR}/thirdparty/liblastfm2/src playlist @@ -390,7 +403,7 @@ ELSE( APPLE ) ENDIF( APPLE ) IF(LIBLASTFM_FOUND) - SET(LINK_LIBRARIES ${LINK_LIBRARIES} tomahawk_lastfm2 ) + SET(LINK_LIBRARIES ${LINK_LIBRARIES} ${LIBLASTFM_LIBRARIES} ) ENDIF(LIBLASTFM_FOUND) IF(BUILD_GUI) @@ -412,6 +425,10 @@ IF(LIBATTICA_FOUND) SET( LINK_LIBRARIES ${LINK_LIBRARIES} ${LIBATTICA_LIBRARIES} ${QuaZip_LIBRARIES} ) ENDIF(LIBATTICA_FOUND) +IF( UNIX AND NOT APPLE ) + SET( LINK_LIBRARIES ${LINK_LIBRARIES} ${QT_QTDBUS_LIBRARY} ) +ENDIF( UNIX AND NOT APPLE ) + TARGET_LINK_LIBRARIES( tomahawklib # Thirdparty shipped with tomahawk ${LIBPORTFWD_LIBRARIES} @@ -425,7 +442,11 @@ TARGET_LINK_LIBRARIES( tomahawklib ${QT_QTSQL_LIBRARY} ${QT_QTUITOOLS_LIBRARY} ${QT_QTGUI_LIBRARY} + ${QT_QTWEBKIT_LIBRARY} ${QT_QTSCRIPT_LIBRARY} + ${QT_QTNETWORK_LIBRARY} + ${QT_QTXML_LIBRARY} + ${QT_QTCORE_LIBRARY} ${OS_SPECIFIC_LINK_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT} ${LINK_LIBRARIES} diff --git a/src/libtomahawk/ContextMenu.cpp b/src/libtomahawk/ContextMenu.cpp index 60eecc663..1b562b093 100644 --- a/src/libtomahawk/ContextMenu.cpp +++ b/src/libtomahawk/ContextMenu.cpp @@ -98,7 +98,6 @@ ContextMenu::setQueries( const QList& queries ) m_sigmap->setMapping( m_loveAction, ActionLove ); connect( queries.first().data(), SIGNAL( socialActionsLoaded() ), SLOT( onSocialActionsLoaded() ) ); - m_queries.first()->loadSocialActions(); onSocialActionsLoaded(); } diff --git a/src/libtomahawk/DropJob.cpp b/src/libtomahawk/DropJob.cpp index 029eb44cb..674a8840d 100644 --- a/src/libtomahawk/DropJob.cpp +++ b/src/libtomahawk/DropJob.cpp @@ -32,7 +32,6 @@ #include "utils/Logger.h" #include "utils/TomahawkUtils.h" #include "GlobalActionManager.h" -#include "infosystem/InfoSystem.h" #include "utils/XspfLoader.h" #include "jobview/JobStatusView.h" #include "jobview/JobStatusModel.h" @@ -57,7 +56,6 @@ DropJob::DropJob( QObject *parent ) , m_getWholeAlbums( false ) , m_top10( false ) , m_dropAction( Default ) - , m_dropJob( 0 ) { } @@ -294,11 +292,11 @@ DropJob::tracksFromQueryList( const QMimeData* data ) query_ptr* query = reinterpret_cast(qptr); if ( query && !query->isNull() ) { - tDebug() << "Dropped query item:" << query->data()->artist() << "-" << query->data()->track(); + tDebug() << "Dropped query item:" << query->data()->toString(); if ( m_top10 ) { - getTopTen( query->data()->artist() ); + queries << getTopTen( query->data()->artist() ); } else if ( m_getWholeArtists ) { @@ -376,7 +374,7 @@ DropJob::tracksFromAlbumMetaData( const QMimeData *data ) stream >> album; if ( m_top10 ) - getTopTen( artist ); + queries << getTopTen( artist ); else if ( m_getWholeArtists ) queries << getArtist( artist ); else @@ -405,7 +403,7 @@ DropJob::tracksFromArtistMetaData( const QMimeData *data ) } else { - getTopTen( artist ); + queries << getTopTen( artist ); } } return queries; @@ -569,6 +567,7 @@ DropJob::handleRdioUrls( const QString& urlsRaw ) rdio->parse( urls ); } + void DropJob::handleGroovesharkUrls ( const QString& urlsRaw ) { @@ -594,7 +593,6 @@ DropJob::handleGroovesharkUrls ( const QString& urlsRaw ) } - void DropJob::handleAllUrls( const QString& urls ) { @@ -672,22 +670,28 @@ DropJob::expandedUrls( QStringList urls ) void DropJob::onTracksAdded( const QList& tracksList ) { - qDebug() << Q_FUNC_INFO; - if ( m_dropJob ) + tDebug() << Q_FUNC_INFO << tracksList.count(); + +/* if ( results.isEmpty() ) { - m_dropJob->setFinished(); - m_dropJob = 0; + const QString which = album.isEmpty() ? "artist" : "album"; + JobStatusView::instance()->model()->addJob( new ErrorStatusMessage( tr( "No tracks found for given %1" ).arg( which ), 5 ) ); + }*/ + + if ( !m_dropJob.isEmpty() ) + { + m_dropJob.takeFirst()->setFinished(); } m_resultList.append( tracksList ); if ( --m_queryCount == 0 ) { - if ( m_onlyLocal ) +/* if ( m_onlyLocal ) removeRemoteSources(); if ( !m_allowDuplicates ) - removeDuplicates(); + removeDuplicates();*/ emit tracks( m_resultList ); deleteLater(); @@ -695,67 +699,6 @@ DropJob::onTracksAdded( const QList& tracksList ) } -void -DropJob::tracksFromDB( const QList< query_ptr >& tracks ) -{ - // Tracks that we get from databasecommand_alltracks are resolved only against the database and explicitly marked - // as finished. if the source they resolve to is offline they will not resolve against any resolver. - // explicitly resolve them if they fall in that case first - foreach( const query_ptr& track, tracks ) - { - if ( !track->playable() && !track->solved() && track->results().size() ) // we have offline results - { - track->setResolveFinished( false ); - Pipeline::instance()->resolve( track ); - } - } - - album_ptr albumPtr; - artist_ptr artistPtr; - if ( Tomahawk::Album* album = qobject_cast< Tomahawk::Album* >( sender() ) ) - { - foreach ( const album_ptr& ptr, m_albumsToKeep ) - if ( ptr.data() == album ) - { - albumPtr = ptr; - m_albumsToKeep.remove( ptr ); - } - } - else if ( Tomahawk::Artist* artist = qobject_cast< Tomahawk::Artist* >( sender() ) ) - { - foreach ( const artist_ptr& ptr, m_artistsToKeep ) - if ( ptr.data() == artist ) - { - artistPtr = ptr; - m_artistsToKeep.remove( ptr ); - } - } - - // If we have no tracks, this means no sources in our network have the give request (artist or album) - // Since we really do want to try to drop them, we ask the infosystem as well. - if ( tracks.isEmpty() ) - { - if ( !albumPtr.isNull() && !albumPtr->artist().isNull() ) - { - Q_ASSERT( artistPtr.isNull() ); - --m_queryCount; // This query is done. New query is infosystem query - getAlbumFromInfoystem( albumPtr->artist()->name(), albumPtr->name() ); - } - else if ( !artistPtr.isNull() ) - { - Q_ASSERT( albumPtr.isNull() ); - --m_queryCount; - getTopTen( artistPtr->name() ); - } - } - else - { - onTracksAdded( tracks ); - } - -} - - void DropJob::removeDuplicates() { @@ -803,41 +746,8 @@ DropJob::removeRemoteSources() } -void -DropJob::infoSystemInfo( Tomahawk::InfoSystem::InfoRequestData requestData, QVariant output ) -{ - if ( requestData.caller == s_dropJobInfoId ) - { - const Tomahawk::InfoSystem::InfoStringHash info = requestData.input.value< Tomahawk::InfoSystem::InfoStringHash >(); - - const QString artist = info["artist"]; - const QString album = info["album"]; - - qDebug() << "Got requestData response for artist" << artist << "and album:" << album << output; - - QList< query_ptr > results; - - int i = 0; - foreach ( const QVariant& title, output.toMap().value( "tracks" ).toList() ) - { - results << Query::get( artist, title.toString(), QString(), uuid() ); - - if ( ++i == 10 ) // Only getting top ten for now. Would make sense to make it configurable - break; - } - - if ( results.isEmpty() ) - { - const QString which = album.isEmpty() ? "artist" : "album"; - JobStatusView::instance()->model()->addJob( new ErrorStatusMessage( tr( "No tracks found for given %1" ).arg( which ), 5 ) ); - } - onTracksAdded( results ); - } -} - - QList< query_ptr > -DropJob::getArtist( const QString &artist ) +DropJob::getArtist( const QString &artist, Tomahawk::ModelMode mode ) { artist_ptr artistPtr = Artist::get( artist ); if ( artistPtr->playlistInterface( Mixed )->tracks().isEmpty() ) @@ -845,13 +755,15 @@ DropJob::getArtist( const QString &artist ) m_artistsToKeep.insert( artistPtr ); connect( artistPtr.data(), SIGNAL( tracksAdded( QList, Tomahawk::ModelMode, Tomahawk::collection_ptr ) ), - SLOT( tracksFromDB( QList ) ) ); + SLOT( onTracksAdded( QList ) ) ); + + m_dropJob << new DropJobNotifier( QPixmap( RESPATH "images/album-icon.png" ), Album ); + JobStatusView::instance()->model()->addJob( m_dropJob.last() ); m_queryCount++; - return QList< query_ptr >(); } - else - return artistPtr->playlistInterface( Mixed )->tracks(); + + return artistPtr->playlistInterface( Mixed )->tracks(); } @@ -872,62 +784,21 @@ DropJob::getAlbum( const QString& artist, const QString& album ) // the artist_ptr which means we never get the signal delivered. so we hold on to the album pointer till we're done m_albumsToKeep.insert( albumPtr ); - m_dropJob = new DropJobNotifier( QPixmap( RESPATH "images/album-icon.png" ), Album ); connect( albumPtr.data(), SIGNAL( tracksAdded( QList, Tomahawk::ModelMode, Tomahawk::collection_ptr ) ), - SLOT( tracksFromDB( QList ) ) ); - JobStatusView::instance()->model()->addJob( m_dropJob ); + SLOT( onTracksAdded( QList ) ) ); + + m_dropJob << new DropJobNotifier( QPixmap( RESPATH "images/album-icon.png" ), Album ); + JobStatusView::instance()->model()->addJob( m_dropJob.last() ); m_queryCount++; - return QList< query_ptr >(); } - else - return albumPtr->playlistInterface( Mixed )->tracks(); + + return albumPtr->playlistInterface( Mixed )->tracks(); } -void -DropJob::getTopTen( const QString &artist ) +QList< query_ptr > +DropJob::getTopTen( const QString& artist ) { - connect( Tomahawk::InfoSystem::InfoSystem::instance(), - SIGNAL( info( Tomahawk::InfoSystem::InfoRequestData, QVariant ) ), - SLOT( infoSystemInfo( Tomahawk::InfoSystem::InfoRequestData, QVariant ) ) ); - - Tomahawk::InfoSystem::InfoStringHash artistInfo; - artistInfo["artist"] = artist; - - Tomahawk::InfoSystem::InfoRequestData requestData; - requestData.caller = s_dropJobInfoId; - requestData.customData = QVariantMap(); - - requestData.input = QVariant::fromValue< Tomahawk::InfoSystem::InfoStringHash >( artistInfo ); - - requestData.type = Tomahawk::InfoSystem::InfoArtistSongs; - Tomahawk::InfoSystem::InfoSystem::instance()->getInfo( requestData ); - - m_queryCount++; + return getArtist( artist, Tomahawk::InfoSystemMode ); } - - -void -DropJob::getAlbumFromInfoystem( const QString& artist, const QString& album ) -{ - connect( Tomahawk::InfoSystem::InfoSystem::instance(), - SIGNAL( info( Tomahawk::InfoSystem::InfoRequestData, QVariant ) ), - SLOT( infoSystemInfo( Tomahawk::InfoSystem::InfoRequestData, QVariant ) ) ); - - Tomahawk::InfoSystem::InfoStringHash artistInfo; - artistInfo["artist"] = artist; - artistInfo["album"] = album; - - Tomahawk::InfoSystem::InfoRequestData requestData; - requestData.caller = s_dropJobInfoId; - requestData.customData = QVariantMap(); - - requestData.input = QVariant::fromValue< Tomahawk::InfoSystem::InfoStringHash >( artistInfo ); - - requestData.type = Tomahawk::InfoSystem::InfoAlbumSongs; - Tomahawk::InfoSystem::InfoSystem::instance()->getInfo( requestData ); - - m_queryCount++; -} - diff --git a/src/libtomahawk/DropJob.h b/src/libtomahawk/DropJob.h index 8ae990352..272a6d338 100644 --- a/src/libtomahawk/DropJob.h +++ b/src/libtomahawk/DropJob.h @@ -22,9 +22,6 @@ #include "Query.h" -#include "infosystem/InfoSystem.h" -#include "utils/XspfLoader.h" - #include #include #include @@ -120,9 +117,7 @@ signals: private slots: void expandedUrls( QStringList ); void onTracksAdded( const QList& ); - void infoSystemInfo( Tomahawk::InfoSystem::InfoRequestData requestData, QVariant output ); - void tracksFromDB( const QList< Tomahawk::query_ptr >& ); private: /// handle parsing mime data void handleAllUrls( const QString& urls ); @@ -133,11 +128,9 @@ private: QList< Tomahawk::query_ptr > tracksFromAlbumMetaData( const QMimeData* d ); QList< Tomahawk::query_ptr > tracksFromMixedData( const QMimeData* d ); - QList< Tomahawk::query_ptr > getArtist( const QString& artist ); + QList< Tomahawk::query_ptr > getArtist( const QString& artist, Tomahawk::ModelMode mode = Tomahawk::Mixed ); QList< Tomahawk::query_ptr > getAlbum( const QString& artist, const QString& album ); - - void getTopTen( const QString& artist ); - void getAlbumFromInfoystem( const QString& artist, const QString& album ); + QList< Tomahawk::query_ptr > getTopTen( const QString& artist ); void removeDuplicates(); void removeRemoteSources(); @@ -151,7 +144,7 @@ private: DropTypes m_dropTypes; DropAction m_dropAction; - Tomahawk::DropJobNotifier* m_dropJob; + QList m_dropJob; QList< Tomahawk::query_ptr > m_resultList; QSet< Tomahawk::album_ptr > m_albumsToKeep; diff --git a/src/libtomahawk/GlobalActionManager.cpp b/src/libtomahawk/GlobalActionManager.cpp index a35d4d77c..0cc4e1cd7 100644 --- a/src/libtomahawk/GlobalActionManager.cpp +++ b/src/libtomahawk/GlobalActionManager.cpp @@ -41,13 +41,15 @@ #include "utils/ShortenedLinkParser.h" #include "utils/RdioParser.h" -#include "widgets/SearchWidget.h" -#include "ViewManager.h" -#include "playlist/topbar/TopBar.h" -#include "playlist/PlaylistView.h" +#ifndef ENABLE_HEADLESS + #include "ViewManager.h" + #include "playlist/topbar/TopBar.h" + #include "playlist/PlaylistView.h" + #include "widgets/SearchWidget.h" -#include -#include + #include + #include +#endif #include #include @@ -133,6 +135,8 @@ GlobalActionManager::shortenLink( const QUrl& url, const QVariant& callbackObj ) } +#ifndef ENABLE_HEADLESS + void GlobalActionManager::getShortLink( const playlist_ptr& pl ) { @@ -162,7 +166,7 @@ GlobalActionManager::getShortLink( const playlist_ptr& pl ) // No built-in Qt facilities for doing a FORM POST. So we build the payload ourselves... const QByteArray boundary = "----------------------------2434992cccab"; - QByteArray data(QByteArray("--" + boundary + "\r\n")); + QByteArray data( QByteArray( "--" + boundary + "\r\n" ) ); data += "Content-Disposition: form-data; name=\"data\"; filename=\"playlist.jspf\"\r\n"; data += "Content-Type: application/octet-stream\r\n\r\n"; data += msg; @@ -178,6 +182,7 @@ GlobalActionManager::getShortLink( const playlist_ptr& pl ) connect( reply, SIGNAL( error( QNetworkReply::NetworkError ) ), SLOT( shortenLinkRequestError( QNetworkReply::NetworkError ) ) ); } + QString GlobalActionManager::copyPlaylistToClipboard( const dynplaylist_ptr& playlist ) { @@ -380,7 +385,7 @@ GlobalActionManager::handlePlaylistCommand( const QUrl& url ) tDebug() << "No xspf or jspf to load..."; return false; } - if ( url.hasQueryItem( "xspf") ) + if ( url.hasQueryItem( "xspf" ) ) { QUrl xspf = QUrl::fromUserInput( url.queryItemValue( "xspf" ) ); QString title = url.hasQueryItem( "title" ) ? url.queryItemValue( "title" ) : QString(); @@ -423,6 +428,7 @@ GlobalActionManager::handlePlaylistCommand( const QUrl& url ) return false; } + void GlobalActionManager::playlistCreatedToShow( const playlist_ptr& pl ) { @@ -430,7 +436,9 @@ GlobalActionManager::playlistCreatedToShow( const playlist_ptr& pl ) pl->setProperty( "sharedptr", QVariant::fromValue( pl ) ); } -void GlobalActionManager::playlistReadyToShow() + +void +GlobalActionManager::playlistReadyToShow() { playlist_ptr pl = sender()->property( "sharedptr" ).value(); if ( !pl.isNull() ) @@ -460,7 +468,7 @@ GlobalActionManager::handleCollectionCommand( const QUrl& url ) bool -GlobalActionManager::handleOpenCommand(const QUrl& url) +GlobalActionManager::handleOpenCommand( const QUrl& url ) { QStringList parts = url.path().split( "/" ).mid( 1 ); if ( parts.isEmpty() ) @@ -474,7 +482,7 @@ GlobalActionManager::handleOpenCommand(const QUrl& url) void -GlobalActionManager::handleOpenTrack ( const query_ptr& q ) +GlobalActionManager::handleOpenTrack( const query_ptr& q ) { ViewManager::instance()->queue()->model()->append( q ); ViewManager::instance()->showQueue(); @@ -486,6 +494,7 @@ GlobalActionManager::handleOpenTrack ( const query_ptr& q ) } } + void GlobalActionManager::handlePlayTrack( const query_ptr& qry ) { @@ -493,7 +502,6 @@ GlobalActionManager::handlePlayTrack( const query_ptr& qry ) } - bool GlobalActionManager::handleQueueCommand( const QUrl& url ) { @@ -996,6 +1004,8 @@ GlobalActionManager::playRdio( const QUrl& url ) return true; } +#endif + bool GlobalActionManager::handleBookmarkCommand(const QUrl& url) { @@ -1076,6 +1086,7 @@ GlobalActionManager::shortenLinkRequestFinished() if ( !shortUrl.isValid() ) error = true; +#ifndef ENABLE_HEADLESS // Success! Here is the short link if ( m_clipboardLongUrl == reply->request().url() ) { @@ -1088,6 +1099,7 @@ GlobalActionManager::shortenLinkRequestFinished() m_clipboardLongUrl.clear(); } else +#endif { if ( !error ) emit shortLinkReady( longUrl, shortUrl, callbackObj ); @@ -1099,6 +1111,8 @@ GlobalActionManager::shortenLinkRequestFinished() } +#ifndef ENABLE_HEADLESS + void GlobalActionManager::postShortenFinished() { @@ -1118,6 +1132,9 @@ GlobalActionManager::postShortenFinished() reply->deleteLater(); } +#endif + + void GlobalActionManager::shortenLinkRequestError( QNetworkReply::NetworkError error ) { @@ -1172,6 +1189,8 @@ GlobalActionManager::doBookmark( const playlist_ptr& pl, const query_ptr& q ) } +#ifndef ENABLE_HEADLESS + void GlobalActionManager::showPlaylist() { @@ -1214,13 +1233,6 @@ GlobalActionManager::waitingForResolved( bool /* success */ ) } -QString -GlobalActionManager::hostname() const -{ - return QString( "http://toma.hk" ); -} - - /// SPOTIFY URL HANDLING bool @@ -1243,3 +1255,11 @@ GlobalActionManager::openRdioLink( const QString& link ) return true; } +#endif + + +QString +GlobalActionManager::hostname() const +{ + return QString( "http://toma.hk" ); +} diff --git a/src/libtomahawk/GlobalActionManager.h b/src/libtomahawk/GlobalActionManager.h index e9a96f3d6..d28a5aa39 100644 --- a/src/libtomahawk/GlobalActionManager.h +++ b/src/libtomahawk/GlobalActionManager.h @@ -45,6 +45,11 @@ public: QUrl openLinkFromQuery( const Tomahawk::query_ptr& query ) const; QUrl openLink( const QString& title, const QString& artist, const QString& album ) const; +public slots: + void shortenLink( const QUrl& url, const QVariant &callbackObj = QVariant() ); + +#ifndef ENABLE_HEADLESS + /// Takes a spotify link and performs the default open action on it bool openSpotifyLink( const QString& link ); @@ -55,58 +60,62 @@ public: QString copyPlaylistToClipboard( const Tomahawk::dynplaylist_ptr& playlist ); void savePlaylistToFile( const Tomahawk::playlist_ptr& playlist, const QString& filename ); -public slots: - void shortenLink( const QUrl& url, const QVariant &callbackObj = QVariant() ); - void getShortLink( const Tomahawk::playlist_ptr& playlist ); - bool parseTomahawkLink( const QString& link ); + void getShortLink( const Tomahawk::playlist_ptr& playlist ); void waitingForResolved( bool ); Tomahawk::dynplaylist_ptr loadDynamicPlaylist( const QUrl& url, bool station ); void handleOpenTrack( const Tomahawk::query_ptr& qry ); void handlePlayTrack( const Tomahawk::query_ptr& qry ); +#endif signals: void shortLinkReady( const QUrl& longUrl, const QUrl& shortUrl, const QVariant& callbackObj ); private slots: void shortenLinkRequestFinished(); - void postShortenFinished(); void shortenLinkRequestError( QNetworkReply::NetworkError ); void bookmarkPlaylistCreated( const Tomahawk::playlist_ptr& pl ); + +#ifndef ENABLE_HEADLESS + void postShortenFinished(); void showPlaylist(); - void xspfCreated( const QByteArray& xspf ); - - void playOrQueueNow( const Tomahawk::query_ptr& ); - void playNow( const Tomahawk::query_ptr& ); - void playlistCreatedToShow( const Tomahawk::playlist_ptr& pl ); void playlistReadyToShow(); + void xspfCreated( const QByteArray& xspf ); + + void playOrQueueNow( const Tomahawk::query_ptr& ); + void playNow( const Tomahawk::query_ptr& ); +#endif + private: explicit GlobalActionManager( QObject* parent = 0 ); void doBookmark( const Tomahawk::playlist_ptr& pl, const Tomahawk::query_ptr& q ); /// handle opening of urls +#ifndef ENABLE_HEADLESS bool handlePlaylistCommand( const QUrl& url ); - bool handleCollectionCommand(const QUrl& url ); - bool handleQueueCommand(const QUrl& url ); - bool handleStationCommand(const QUrl& url ); - bool handleAutoPlaylistCommand(const QUrl& url ); - bool handleSearchCommand(const QUrl& url ); - bool handlePlayCommand(const QUrl& url ); - bool handleBookmarkCommand(const QUrl& url ); - bool handleOpenCommand(const QUrl& url ); - bool handleViewCommand(const QUrl& url ); + bool handleViewCommand( const QUrl& url ); + bool handleStationCommand( const QUrl& url ); + bool handleSearchCommand( const QUrl& url ); + bool handleQueueCommand( const QUrl& url ); + bool handleAutoPlaylistCommand( const QUrl& url ); bool doQueueAdd( const QStringList& parts, const QList< QPair< QString, QString > >& queryItems ); - + bool playSpotify( const QUrl& url ); bool queueSpotify( const QStringList& parts, const QList< QPair< QString, QString > >& queryItems ); bool playRdio( const QUrl& url ); bool queueRdio( const QStringList& parts, const QList< QPair< QString, QString > >& queryItems ); +#endif + + bool handleCollectionCommand( const QUrl& url ); + bool handlePlayCommand( const QUrl& url ); + bool handleBookmarkCommand( const QUrl& url ); + bool handleOpenCommand( const QUrl& url ); QString hostname() const; diff --git a/src/libtomahawk/Pipeline.cpp b/src/libtomahawk/Pipeline.cpp index 205a9e7aa..6e12e5734 100644 --- a/src/libtomahawk/Pipeline.cpp +++ b/src/libtomahawk/Pipeline.cpp @@ -106,6 +106,7 @@ Pipeline::removeResolver( Resolver* r ) { QMutexLocker lock( &m_mut ); + tDebug() << "Removed resolver:" << r->name(); m_resolvers.removeAll( r ); emit resolverRemoved( r ); } @@ -130,7 +131,7 @@ Pipeline::addExternalResolverFactory( ResolverFactoryFunc resolverFactory ) Tomahawk::ExternalResolver* -Pipeline::addScriptResolver( const QString& path, bool start ) +Pipeline::addScriptResolver( const QString& path ) { ExternalResolver* res = 0; @@ -141,8 +142,6 @@ Pipeline::addScriptResolver( const QString& path, bool start ) continue; m_scriptResolvers << QWeakPointer< ExternalResolver >( res ); - if ( start ) - res->start(); break; } @@ -203,14 +202,20 @@ Pipeline::resolve( const QList& qlist, bool prioritized, bool tempora QMutexLocker lock( &m_mut ); int i = 0; - foreach( const query_ptr& q, qlist ) + foreach ( const query_ptr& q, qlist ) { if ( q->resolvingFinished() ) continue; - if ( m_queries_pending.contains( q ) ) - continue; if ( m_qidsState.contains( q->id() ) ) continue; + if ( m_queries_pending.contains( q ) ) + { + if ( prioritized ) + { + m_queries_pending.insert( i++, m_queries_pending.takeAt( m_queries_pending.indexOf( q ) ) ); + } + continue; + } if ( !m_qids.contains( q->id() ) ) m_qids.insert( q->id(), q ); @@ -268,7 +273,7 @@ Pipeline::reportResults( QID qid, const QList< result_ptr >& results ) const query_ptr& q = m_qids.value( qid ); QList< result_ptr > cleanResults; - foreach( const result_ptr& r, results ) + foreach ( const result_ptr& r, results ) { float score = q->howSimilar( r ); r->setScore( score ); @@ -281,12 +286,12 @@ Pipeline::reportResults( QID qid, const QList< result_ptr >& results ) if ( !cleanResults.isEmpty() ) { q->addResults( cleanResults ); - foreach( const result_ptr& r, cleanResults ) + foreach ( const result_ptr& r, cleanResults ) { m_rids.insert( r->id(), r ); } - if ( q->playable() && !q->isFullTextQuery() ) + if ( q->solved() && !q->isFullTextQuery() ) { setQIDState( q, 0 ); return; @@ -312,7 +317,7 @@ Pipeline::reportAlbums( QID qid, const QList< album_ptr >& albums ) Q_ASSERT( q->isFullTextQuery() ); QList< album_ptr > cleanAlbums; - foreach( const album_ptr& r, albums ) + foreach ( const album_ptr& r, albums ) { // float score = q->howSimilar( r ); @@ -341,7 +346,7 @@ Pipeline::reportArtists( QID qid, const QList< artist_ptr >& artists ) Q_ASSERT( q->isFullTextQuery() ); QList< artist_ptr > cleanArtists; - foreach( const artist_ptr& r, artists ) + foreach ( const artist_ptr& r, artists ) { // float score = q->howSimilar( r ); diff --git a/src/libtomahawk/Pipeline.h b/src/libtomahawk/Pipeline.h index c142bb646..818c22d16 100644 --- a/src/libtomahawk/Pipeline.h +++ b/src/libtomahawk/Pipeline.h @@ -58,7 +58,7 @@ public: void reportArtists( QID qid, const QList< artist_ptr >& artists ); void addExternalResolverFactory( ResolverFactoryFunc resolverFactory ); - Tomahawk::ExternalResolver* addScriptResolver( const QString& scriptPath, bool start = true ); + Tomahawk::ExternalResolver* addScriptResolver( const QString& scriptPath ); void stopScriptResolver( const QString& scriptPath ); void removeScriptResolver( const QString& scriptPath ); QList< QWeakPointer< ExternalResolver > > scriptResolvers() const { return m_scriptResolvers; } @@ -90,8 +90,8 @@ signals: void idle(); void resolving( const Tomahawk::query_ptr& query ); - void resolverAdded( Resolver* ); - void resolverRemoved( Resolver* ); + void resolverAdded( Tomahawk::Resolver* ); + void resolverRemoved( Tomahawk::Resolver* ); private slots: void timeoutShunt( const query_ptr& q ); diff --git a/src/libtomahawk/PlaylistInterface.cpp b/src/libtomahawk/PlaylistInterface.cpp index 4cfefcab9..a8b24ebb8 100644 --- a/src/libtomahawk/PlaylistInterface.cpp +++ b/src/libtomahawk/PlaylistInterface.cpp @@ -21,6 +21,7 @@ #include "utils/Logger.h" #include "Result.h" #include "Pipeline.h" +#include "Source.h" using namespace Tomahawk; @@ -68,7 +69,7 @@ PlaylistInterface::filterTracks( const QList& queries ) break; const query_ptr& q2 = result.at( j ); - + if ( q1->track() == q2->track() ) { picked = false; diff --git a/src/libtomahawk/Query.cpp b/src/libtomahawk/Query.cpp index 94cd4a140..32b2b77b5 100644 --- a/src/libtomahawk/Query.cpp +++ b/src/libtomahawk/Query.cpp @@ -125,10 +125,7 @@ Query::Query( const QString& artist, const QString& track, const QString& album, connect( Database::instance(), SIGNAL( indexReady() ), SLOT( refreshResults() ), Qt::QueuedConnection ); } - connect( Pipeline::instance(), SIGNAL( resolverAdded( Resolver* ) ), - SLOT( onResolverAdded() ), Qt::QueuedConnection ); - connect( Pipeline::instance(), SIGNAL( resolverRemoved( Resolver* ) ), - SLOT( onResolverRemoved() ), Qt::QueuedConnection ); + connect( Pipeline::instance(), SIGNAL( resolverAdded( Tomahawk::Resolver* ) ), SLOT( onResolverAdded() ), Qt::QueuedConnection ); } @@ -216,7 +213,6 @@ Query::addResults( const QList< Tomahawk::result_ptr >& newresults ) m_results << newresults; qStableSort( m_results.begin(), m_results.end(), Query::resultSorter ); - query_ptr q = m_ownRef.toStrongRef(); // hook up signals, and check solved status foreach( const result_ptr& rp, newresults ) @@ -318,16 +314,6 @@ Query::onResolverAdded() } -void -Query::onResolverRemoved() -{ - if ( !solved() ) - { - refreshResults(); - } -} - - QList< result_ptr > Query::results() const { @@ -447,7 +433,7 @@ Query::checkResults() } } - if ( m_playable && !playable ) + if ( m_solved && !solved ) { refreshResults(); } @@ -780,7 +766,7 @@ Query::cover( const QSize& size, bool forceLoad ) const } m_albumPtr->cover( size, forceLoad ); - if ( m_albumPtr->infoLoaded() ) + if ( m_albumPtr->coverLoaded() ) { if ( !m_albumPtr->cover( size ).isNull() ) return m_albumPtr->cover( size ); @@ -790,6 +776,20 @@ Query::cover( const QSize& size, bool forceLoad ) const return QPixmap(); } + + +bool +Query::coverLoaded() const +{ + if ( m_albumPtr.isNull() ) + return false; + + if ( m_albumPtr->coverLoaded() && !m_albumPtr->cover( QSize( 0, 0 ) ).isNull() ) + return true; + + return m_artistPtr->coverLoaded(); +} + #endif diff --git a/src/libtomahawk/Query.h b/src/libtomahawk/Query.h index 78ff182f8..6eb60088c 100644 --- a/src/libtomahawk/Query.h +++ b/src/libtomahawk/Query.h @@ -145,6 +145,7 @@ public: #ifndef ENABLE_HEADLESS QPixmap cover( const QSize& size, bool forceLoad = true ) const; #endif + bool coverLoaded() const; void setResolveFinished( bool resolved ) { m_resolveFinished = resolved; } void setPlayedBy( const Tomahawk::source_ptr& source, unsigned int playtime ); @@ -198,10 +199,7 @@ public slots: void addArtists( const QList< Tomahawk::artist_ptr >& ); void onResolvingFinished(); - - // resolve if not solved() void onResolverAdded(); - void onResolverRemoved(); private slots: void infoSystemInfo( Tomahawk::InfoSystem::InfoRequestData requestData, QVariant output ); diff --git a/src/libtomahawk/Result.cpp b/src/libtomahawk/Result.cpp index c3ceaddcf..62e204058 100644 --- a/src/libtomahawk/Result.cpp +++ b/src/libtomahawk/Result.cpp @@ -20,7 +20,9 @@ #include "Album.h" #include "Collection.h" +#include "Resolver.h" #include "Source.h" +#include "Pipeline.h" #include "database/Database.h" #include "database/DatabaseCommand_Resolve.h" #include "database/DatabaseCommand_AllTracks.h" @@ -72,6 +74,7 @@ Result::Result( const QString& url ) , m_trackId( 0 ) , m_fileId( 0 ) { + connect( Pipeline::instance(), SIGNAL( resolverRemoved( Tomahawk::Resolver* ) ), SLOT( onResolverRemoved( Tomahawk::Resolver* ) ), Qt::QueuedConnection ); } @@ -94,12 +97,24 @@ Result::deleteLater() } +void +Result::onResolverRemoved( Tomahawk::Resolver* resolver ) +{ + if ( m_resolvedBy.data() == resolver ) + { + m_resolvedBy.clear(); + emit statusChanged(); + } +} + + artist_ptr Result::artist() const { return m_artist; } + artist_ptr Result::composer() const { @@ -124,18 +139,10 @@ Result::collection() const float Result::score() const { - if ( !collection().isNull() && collection()->source()->isOnline() ) - { + if ( isOnline() ) return m_score; - } else - { - // check if this a valid collection-less result (e.g. from youtube, but ignore offline sources still) - if ( collection().isNull() ) - return m_score; - else - return 0.0; - } + return 0.0; } @@ -152,7 +159,14 @@ Result::id() const bool Result::isOnline() const { - return ( ( !collection().isNull() && collection()->source()->isOnline() ) || collection().isNull() ); + if ( !collection().isNull() ) + { + return collection()->source()->isOnline(); + } + else + { + return !m_resolvedBy.isNull(); + } } @@ -274,3 +288,20 @@ Result::friendlySource() const else return collection()->source()->friendlyName(); } + + +Tomahawk::Resolver* +Result::resolvedBy() const +{ + if ( m_resolvedBy.isNull() ) + return 0; + + return m_resolvedBy.data(); +} + + +void +Result::setResolvedBy( Tomahawk::Resolver* resolver ) +{ + m_resolvedBy = QWeakPointer< Tomahawk::Resolver >( resolver ); +} diff --git a/src/libtomahawk/Result.h b/src/libtomahawk/Result.h index bfa6ded64..89a799e4e 100644 --- a/src/libtomahawk/Result.h +++ b/src/libtomahawk/Result.h @@ -36,6 +36,8 @@ class DatabaseCommand_LoadFile; namespace Tomahawk { +class Resolver; + class DLLEXPORT Result : public QObject { Q_OBJECT @@ -54,6 +56,9 @@ public: QString toString() const; Tomahawk::query_ptr toQuery(); + Tomahawk::Resolver* resolvedBy() const; + void setResolvedBy( Tomahawk::Resolver* resolver ); + float score() const; RID id() const; bool isOnline() const; @@ -110,6 +115,8 @@ signals: private slots: void onOffline(); void onOnline(); + + void onResolverRemoved( Tomahawk::Resolver* resolver ); private: // private constructor @@ -121,6 +128,7 @@ private: mutable RID m_rid; collection_ptr m_collection; Tomahawk::query_ptr m_query; + QWeakPointer< Tomahawk::Resolver > m_resolvedBy; Tomahawk::artist_ptr m_artist; Tomahawk::album_ptr m_album; diff --git a/src/libtomahawk/Source.cpp b/src/libtomahawk/Source.cpp index cd625a06b..1d781fb8f 100644 --- a/src/libtomahawk/Source.cpp +++ b/src/libtomahawk/Source.cpp @@ -23,6 +23,7 @@ #include "SourceList.h" #include "SourcePlaylistInterface.h" +#include "accounts/AccountManager.h" #include "network/ControlConnection.h" #include "database/DatabaseCommand_AddSource.h" #include "database/DatabaseCommand_CollectionStats.h" @@ -33,11 +34,15 @@ #include #include -#include "utils/Logger.h" -#include "utils/TomahawkUtilsGui.h" #include "utils/TomahawkCache.h" #include "database/DatabaseCommand_SocialAction.h" +#ifndef ENABLE_HEADLESS + #include "utils/TomahawkUtilsGui.h" +#endif + +#include "utils/Logger.h" + using namespace Tomahawk; @@ -48,6 +53,7 @@ Source::Source( int id, const QString& username ) , m_username( username ) , m_id( id ) , m_updateIndexWhenSynced( false ) + , m_avatarUpdated( true ) , m_state( DBSyncConnection::UNKNOWN ) , m_cc( 0 ) , m_commandCount( 0 ) @@ -57,13 +63,16 @@ Source::Source( int id, const QString& username ) m_scrubFriendlyName = qApp->arguments().contains( "--demo" ); if ( id == 0 ) - { m_isLocal = true; - m_online = true; - } m_currentTrackTimer.setSingleShot( true ); connect( &m_currentTrackTimer, SIGNAL( timeout() ), this, SLOT( trackTimerFired() ) ); + + if ( m_isLocal ) + { + connect( Accounts::AccountManager::instance(), SIGNAL( connected( Tomahawk::Accounts::Account* ) ), SLOT( setOnline() ) ); + connect( Accounts::AccountManager::instance(), SIGNAL( disconnected( Tomahawk::Accounts::Account* ) ), SLOT( setOffline() ) ); + } } @@ -134,15 +143,15 @@ Source::setAvatar( const QPixmap& avatar ) buffer.open( QIODevice::WriteOnly ); avatar.save( &buffer, "PNG" ); - tDebug() << Q_FUNC_INFO << friendlyName() << m_username << ba.count(); TomahawkUtils::Cache::instance()->putData( "Sources", 7776000000 /* 90 days */, m_username, ba ); + m_avatarUpdated = true; } QPixmap -Source::avatar( AvatarStyle style, const QSize& size ) const +Source::avatar( AvatarStyle style, const QSize& size ) { - if ( !m_avatar ) + if ( !m_avatar && m_avatarUpdated ) { m_avatar = new QPixmap(); QByteArray ba = TomahawkUtils::Cache::instance()->getData( "Sources", m_username ).toByteArray(); @@ -154,6 +163,7 @@ Source::avatar( AvatarStyle style, const QSize& size ) const delete m_avatar; m_avatar = 0; } + m_avatarUpdated = false; } if ( style == FancyStyle && m_avatar && !m_fancyAvatar ) @@ -191,7 +201,10 @@ Source::setFriendlyName( const QString& fname ) m_friendlyname = fname; if ( m_scrubFriendlyName ) - m_friendlyname = m_friendlyname.split( "@" ).first(); + { + if ( m_friendlyname.indexOf( "@" ) > 0 ) + m_friendlyname = m_friendlyname.split( "@" ).first(); + } } @@ -223,12 +236,15 @@ Source::setOffline() m_online = false; emit offline(); - m_currentTrack.clear(); - emit stateChanged(); + if ( !isLocal() ) + { + m_currentTrack.clear(); + emit stateChanged(); - m_cc = 0; - DatabaseCommand_SourceOffline* cmd = new DatabaseCommand_SourceOffline( id() ); - Database::instance()->enqueue( QSharedPointer< DatabaseCommand >( cmd ) ); + m_cc = 0; + DatabaseCommand_SourceOffline* cmd = new DatabaseCommand_SourceOffline( id() ); + Database::instance()->enqueue( QSharedPointer< DatabaseCommand >( cmd ) ); + } } @@ -242,11 +258,14 @@ Source::setOnline() m_online = true; emit online(); - // ensure username is in the database - DatabaseCommand_addSource* cmd = new DatabaseCommand_addSource( m_username, friendlyName() ); - connect( cmd, SIGNAL( done( unsigned int, QString ) ), - SLOT( dbLoaded( unsigned int, const QString& ) ) ); - Database::instance()->enqueue( QSharedPointer(cmd) ); + if ( !isLocal() ) + { + // ensure username is in the database + DatabaseCommand_addSource* cmd = new DatabaseCommand_addSource( m_username, friendlyName() ); + connect( cmd, SIGNAL( done( unsigned int, QString ) ), + SLOT( dbLoaded( unsigned int, const QString& ) ) ); + Database::instance()->enqueue( QSharedPointer(cmd) ); + } } @@ -357,24 +376,27 @@ Source::playlistInterface() void Source::onPlaybackStarted( const Tomahawk::query_ptr& query, unsigned int duration ) { - qDebug() << Q_FUNC_INFO << query->toString(); + tLog( LOGVERBOSE ) << Q_FUNC_INFO << query->toString(); m_currentTrack = query; m_currentTrackTimer.start( duration * 1000 + 900000 ); // duration comes in seconds if ( m_playlistInterface.isNull() ) playlistInterface(); + emit playbackStarted( query ); + emit stateChanged(); } void Source::onPlaybackFinished( const Tomahawk::query_ptr& query ) { - qDebug() << Q_FUNC_INFO << query->toString(); + tDebug() << Q_FUNC_INFO << query->toString(); emit playbackFinished( query ); - m_currentTrackTimer.start(); + m_currentTrack.clear(); + emit stateChanged(); } @@ -382,7 +404,6 @@ void Source::trackTimerFired() { m_currentTrack.clear(); - emit stateChanged(); } @@ -504,3 +525,26 @@ Source::updateIndexWhenSynced() { m_updateIndexWhenSynced = true; } + + +QString +Source::textStatus() const +{ + if ( !m_textStatus.isEmpty() ) + return m_textStatus; + + if ( !currentTrack().isNull() ) + { + return currentTrack()->artist() + " - " + currentTrack()->track(); + } + + // do not use isOnline() here - it will always return true for the local source + if ( m_online ) + { + return tr( "Online" ); + } + else + { + return tr( "Offline" ); + } +} diff --git a/src/libtomahawk/Source.h b/src/libtomahawk/Source.h index cd45bbc83..bd463ae2a 100644 --- a/src/libtomahawk/Source.h +++ b/src/libtomahawk/Source.h @@ -58,7 +58,7 @@ public: virtual ~Source(); bool isLocal() const { return m_isLocal; } - bool isOnline() const { return m_online; } + bool isOnline() const { return m_online || m_isLocal; } QString userName() const { return m_username; } QString friendlyName() const; @@ -66,7 +66,7 @@ public: #ifndef ENABLE_HEADLESS void setAvatar( const QPixmap& avatar ); - QPixmap avatar( AvatarStyle style = Original, const QSize& size = QSize() ) const; + QPixmap avatar( AvatarStyle style = Original, const QSize& size = QSize() ); #endif collection_ptr collection() const; @@ -83,7 +83,7 @@ public: unsigned int trackCount() const; Tomahawk::query_ptr currentTrack() const { return m_currentTrack; } - QString textStatus() const { return m_textStatus; } + QString textStatus() const; DBSyncConnection::State state() const { return m_state; } Tomahawk::playlistinterface_ptr playlistInterface(); @@ -147,6 +147,7 @@ private: int m_id; bool m_scrubFriendlyName; bool m_updateIndexWhenSynced; + bool m_avatarUpdated; Tomahawk::query_ptr m_currentTrack; QString m_textStatus; diff --git a/src/libtomahawk/TomahawkSettings.cpp b/src/libtomahawk/TomahawkSettings.cpp index 4d69da9be..c51f5acff 100644 --- a/src/libtomahawk/TomahawkSettings.cpp +++ b/src/libtomahawk/TomahawkSettings.cpp @@ -158,7 +158,6 @@ TomahawkSettings::doInitialSetup() // by default we add a local network resolver addAccount( "sipzeroconf_autocreated" ); - createLastFmAccount(); createSpotifyAccount(); } @@ -192,6 +191,7 @@ TomahawkSettings::createSpotifyAccount() setValue( "types", QStringList() << "ResolverType" ); setValue( "credentials", QVariantHash() ); setValue( "configuration", QVariantHash() ); + setValue( "accountfriendlyname", "Spotify" ); endGroup(); QStringList allAccounts = value( "accounts/allaccounts" ).toStringList(); @@ -484,6 +484,7 @@ TomahawkSettings::doUpgrade( int oldVersion, int newVersion ) setValue( "enabled", enabled ); setValue( "autoconnect", autoconnect ); setValue( "types", QStringList() << "ResolverType" ); + setValue( "accountfriendlyname", "Spotify" ); setValue( "configuration", configuration ); endGroup(); @@ -557,10 +558,10 @@ TomahawkSettings::doUpgrade( int oldVersion, int newVersion ) } endGroup(); - -// setPlaylistUpdaters( updaters ); - remove( "playlistupdaters" ); + + setValue( "playlists/updaters", QVariant::fromValue< SerializedUpdaters >( updaters ) ); + } else if ( oldVersion == 11 ) { @@ -712,6 +713,20 @@ TomahawkSettings::setCrashReporterEnabled( bool enable ) } +unsigned int +TomahawkSettings::volume() const +{ + return value( "audio/volume", 75 ).toUInt(); +} + + +void +TomahawkSettings::setVolume( unsigned int volume ) +{ + setValue( "audio/volume", volume ); +} + + QString TomahawkSettings::proxyHost() const { diff --git a/src/libtomahawk/TomahawkSettings.h b/src/libtomahawk/TomahawkSettings.h index 3951e9ec3..42fdac340 100644 --- a/src/libtomahawk/TomahawkSettings.h +++ b/src/libtomahawk/TomahawkSettings.h @@ -47,11 +47,13 @@ public: /// General settings virtual QString storageCacheLocation() const; + virtual QStringList scannerPaths() const; /// QDesktopServices::MusicLocation in TomahawkSettingsGui void setScannerPaths( const QStringList& paths ); bool hasScannerPaths() const; uint scannerTime() const; void setScannerTime( uint time ); + uint infoSystemCacheVersion() const; void setInfoSystemCacheVersion( uint version ); @@ -81,6 +83,10 @@ public: bool enableEchonestCatalogs() const; void setEnableEchonestCatalogs( bool enable ); + /// Audio stuff + unsigned int volume() const; + void setVolume( unsigned int volume ); + /// Playlist stuff QByteArray playlistColumnSizes( const QString& playlistid ) const; void setPlaylistColumnSizes( const QString& playlistid, const QByteArray& state ); diff --git a/src/libtomahawk/TomahawkSettingsGui.cpp b/src/libtomahawk/TomahawkSettingsGui.cpp index 8aa15b3c2..2e6932fda 100644 --- a/src/libtomahawk/TomahawkSettingsGui.cpp +++ b/src/libtomahawk/TomahawkSettingsGui.cpp @@ -61,6 +61,7 @@ inline QDataStream& operator>>(QDataStream& in, AtticaManager::StateHash& states return in; } + TomahawkSettingsGui* TomahawkSettingsGui::instanceGui() { @@ -109,12 +110,14 @@ TomahawkSettingsGui::setAtticaResolverState( const QString& resolver, AtticaMana sync(); } + AtticaManager::StateHash TomahawkSettingsGui::atticaResolverStates() const { return value( "script/atticaresolverstates" ).value< AtticaManager::StateHash >(); } + void TomahawkSettingsGui::setAtticaResolverStates( const AtticaManager::StateHash states ) { diff --git a/src/libtomahawk/Typedefs.h b/src/libtomahawk/Typedefs.h index e442f2328..730799e9a 100644 --- a/src/libtomahawk/Typedefs.h +++ b/src/libtomahawk/Typedefs.h @@ -99,10 +99,11 @@ namespace Tomahawk typedef QList< SerializedUpdater > SerializedUpdaterList; - namespace InfoSystem { - - - enum InfoType { // as items are saved in cache, mark them here to not change them + namespace InfoSystem + { + enum InfoType + { + // as items are saved in cache, mark them here to not change them InfoNoInfo = 0, //WARNING: *ALWAYS* keep this first! InfoTrackID = 1, InfoTrackArtist = 2, diff --git a/src/libtomahawk/ViewManager.cpp b/src/libtomahawk/ViewManager.cpp index 6d1255bb2..f7b198ba3 100644 --- a/src/libtomahawk/ViewManager.cpp +++ b/src/libtomahawk/ViewManager.cpp @@ -28,15 +28,12 @@ #include "topbar/TopBar.h" #include "TreeModel.h" -#include "CollectionFlatModel.h" -#include "CollectionView.h" #include "PlaylistModel.h" #include "PlaylistView.h" #include "PlayableProxyModel.h" #include "PlayableModel.h" -#include "ArtistView.h" -#include "AlbumView.h" -#include "AlbumProxyModel.h" +#include "TreeView.h" +#include "GridView.h" #include "AlbumModel.h" #include "SourceList.h" #include "TomahawkSettings.h" @@ -46,6 +43,7 @@ #include "RecentlyPlayedModel.h" #include "dynamic/widgets/DynamicWidget.h" +#include "widgets/NewReleasesWidget.h" #include "widgets/WelcomeWidget.h" #include "widgets/WhatsHotWidget.h" #include "widgets/infowidgets/SourceInfoWidget.h" @@ -79,6 +77,7 @@ ViewManager::ViewManager( QObject* parent ) , m_newReleasesWidget( new NewReleasesWidget() ) , m_topLovedWidget( 0 ) , m_recentPlaysWidget( 0 ) + , m_currentPage( 0 ) , m_currentMode( PlaylistModes::Tree ) , m_loaded( false ) { @@ -94,19 +93,15 @@ ViewManager::ViewManager( QObject* parent ) m_widget->layout()->addWidget( m_stack ); m_widget->layout()->addWidget( m_contextWidget ); - m_superCollectionView = new ArtistView(); + m_superCollectionView = new TreeView(); m_superCollectionModel = new TreeModel( m_superCollectionView ); m_superCollectionView->setTreeModel( m_superCollectionModel ); - m_superCollectionView->setFrameShape( QFrame::NoFrame ); - m_superCollectionView->setAttribute( Qt::WA_MacShowFocusRect, 0 ); m_superCollectionView->setShowModes( false ); // m_superCollectionView->proxyModel()->setShowOfflineResults( false ); - m_superAlbumView = new AlbumView(); - m_superAlbumModel = new AlbumModel( m_superAlbumView ); - m_superAlbumView->setAlbumModel( m_superAlbumModel ); - m_superAlbumView->setFrameShape( QFrame::NoFrame ); - m_superAlbumView->setAttribute( Qt::WA_MacShowFocusRect, 0 ); + m_superGridView = new GridView(); + m_superAlbumModel = new AlbumModel( m_superGridView ); + m_superGridView->setPlayableModel( m_superAlbumModel ); m_stack->setContentsMargins( 0, 0, 0, 0 ); m_widget->setContentsMargins( 0, 0, 0, 0 ); @@ -149,8 +144,6 @@ ViewManager::createPageForPlaylist( const playlist_ptr& pl ) PlaylistModel* model = new PlaylistModel(); view->setPlaylistModel( model ); model->loadPlaylist( pl ); - view->setFrameShape( QFrame::NoFrame ); - view->setAttribute( Qt::WA_MacShowFocusRect, 0 ); pl->resolve(); m_playlistViews.insert( pl, view ); @@ -284,14 +277,12 @@ ViewManager::show( const Tomahawk::collection_ptr& collection ) ViewPage* shown = 0; if ( m_currentMode == PlaylistModes::Flat ) { - CollectionView* view; +/* CollectionView* view; if ( !m_collectionViews.contains( collection ) || m_collectionViews.value( collection ).isNull() ) { view = new CollectionView(); CollectionFlatModel* model = new CollectionFlatModel(); view->setPlayableModel( model ); - view->setFrameShape( QFrame::NoFrame ); - view->setAttribute( Qt::WA_MacShowFocusRect, 0 ); model->addCollection( collection ); @@ -303,19 +294,22 @@ ViewManager::show( const Tomahawk::collection_ptr& collection ) } shown = view; - setPage( view ); + setPage( view );*/ } if ( m_currentMode == PlaylistModes::Tree ) { - ArtistView* view; + TreeView* view; if ( !m_treeViews.contains( collection ) || m_treeViews.value( collection ).isNull() ) { - view = new ArtistView(); + view = new TreeView(); TreeModel* model = new TreeModel(); view->setTreeModel( model ); - view->setFrameShape( QFrame::NoFrame ); - view->setAttribute( Qt::WA_MacShowFocusRect, 0 ); + + if ( collection && collection->source()->isLocal() ) + view->setEmptyTip( tr( "After you have scanned your music collection you will find your tracks right here." ) ); + else + view->setEmptyTip( tr( "This collection is empty." ) ); model->addCollection( collection ); @@ -332,21 +326,19 @@ ViewManager::show( const Tomahawk::collection_ptr& collection ) if ( m_currentMode == PlaylistModes::Album ) { - AlbumView* aview; - if ( !m_collectionAlbumViews.contains( collection ) || m_collectionAlbumViews.value( collection ).isNull() ) + GridView* aview; + if ( !m_collectionGridViews.contains( collection ) || m_collectionGridViews.value( collection ).isNull() ) { - aview = new AlbumView(); + aview = new GridView(); AlbumModel* amodel = new AlbumModel( aview ); - aview->setAlbumModel( amodel ); - aview->setFrameShape( QFrame::NoFrame ); - aview->setAttribute( Qt::WA_MacShowFocusRect, 0 ); + aview->setPlayableModel( amodel ); amodel->addCollection( collection ); - m_collectionAlbumViews.insert( collection, aview ); + m_collectionGridViews.insert( collection, aview ); } else { - aview = m_collectionAlbumViews.value( collection ).data(); + aview = m_collectionGridViews.value( collection ).data(); } shown = aview; @@ -419,8 +411,8 @@ ViewManager::showSuperCollection() } else if ( m_currentMode == PlaylistModes::Album ) { - shown = m_superAlbumView; - setPage( m_superAlbumView ); + shown = m_superGridView; + setPage( m_superGridView ); } emit numSourcesChanged( m_superCollections.count() ); @@ -490,8 +482,6 @@ ViewManager::showRecentPlaysPage() if ( !m_recentPlaysWidget ) { PlaylistView* pv = new PlaylistView( m_widget ); - pv->setFrameShape( QFrame::NoFrame ); - pv->setAttribute( Qt::WA_MacShowFocusRect, 0 ); RecentlyPlayedModel* raModel = new RecentlyPlayedModel( source_ptr(), pv ); raModel->setTitle( tr( "Recently Played Tracks" ) ); @@ -553,39 +543,6 @@ ViewManager::setAlbumMode() } -void -ViewManager::historyBack() -{ - if ( m_pageHistory.count() < 2 ) - return; - - ViewPage* oldPage = m_pageHistory.takeFirst(); - ViewPage* newPage = m_pageHistory.first(); - - tDebug() << "Deleting page in history:" << oldPage->widget()->metaObject()->className(); - tDebug() << "Showing page after moving backwards in history:" << newPage->widget()->metaObject()->className(); - setPage( newPage, false ); - -// delete oldPage; -} - - -void -ViewManager::removeFromHistory( ViewPage* p ) -{ - if ( currentPage() == p ) - { - historyBack(); - } - else - { - m_pageHistory.removeAll( p ); - delete p; - } - -} - - void ViewManager::setFilter( const QString& filter ) { @@ -601,13 +558,80 @@ ViewManager::setFilter( const QString& filter ) void ViewManager::applyFilter() { - qDebug() << Q_FUNC_INFO; - if ( currentPlaylistInterface() && currentPlaylistInterface()->filter() != m_filter ) currentPlaylistInterface()->setFilter( m_filter ); } +void +ViewManager::historyBack() +{ + if ( !m_pageHistoryBack.count() ) + return; + + ViewPage* page = m_pageHistoryBack.takeLast(); + + if ( m_currentPage ) + { + m_pageHistoryFwd << m_currentPage; + tDebug() << "Moved to forward history:" << m_currentPage->widget()->metaObject()->className(); + } + + tDebug() << "Showing page after moving backwards in history:" << page->widget()->metaObject()->className(); + setPage( page, false ); +} + + +void +ViewManager::historyForward() +{ + if ( !m_pageHistoryFwd.count() ) + return; + + ViewPage* page = m_pageHistoryFwd.takeLast(); + + if ( m_currentPage ) + { + m_pageHistoryBack << m_currentPage; + tDebug() << "Moved to backward history:" << m_currentPage->widget()->metaObject()->className(); + } + + tDebug() << "Showing page after moving forwards in history:" << page->widget()->metaObject()->className(); + setPage( page, false ); +} + + +QList +ViewManager::historyPages() const +{ + return m_pageHistoryBack + m_pageHistoryFwd; +} + + +void +ViewManager::destroyPage( ViewPage* page ) +{ + if ( m_currentPage == page ) + { + m_currentPage = 0; + historyBack(); + return; + } + + QList< Tomahawk::ViewPage* > p = historyPages(); + if ( p.contains( page ) ) + { + m_pageHistoryBack.removeAll( page ); + m_pageHistoryFwd.removeAll( page ); + + emit historyBackAvailable( m_pageHistoryBack.count() ); + emit historyForwardAvailable( m_pageHistoryFwd.count() ); + + delete page; + } +} + + void ViewManager::setPage( ViewPage* page, bool trackHistory ) { @@ -618,23 +642,20 @@ ViewManager::setPage( ViewPage* page, bool trackHistory ) saveCurrentPlaylistSettings(); unlinkPlaylist(); - if ( !m_pageHistory.contains( page ) ) + if ( m_stack->indexOf( page->widget() ) < 0 ) { m_stack->addWidget( page->widget() ); } - else - { - if ( trackHistory ) - m_pageHistory.removeAll( page ); - } - if ( trackHistory ) + if ( m_currentPage && trackHistory ) { - m_pageHistory.insert( 0, page ); + m_pageHistoryBack << m_currentPage; + m_pageHistoryFwd.clear(); } + m_currentPage = page; - emit historyBackAvailable( m_pageHistory.count() > 1 ); - emit historyForwardAvailable( false ); + emit historyBackAvailable( m_pageHistoryBack.count() ); + emit historyForwardAvailable( m_pageHistoryFwd.count() ); qDebug() << "View page shown:" << page->title(); emit viewPageActivated( page ); @@ -822,13 +843,14 @@ ViewManager::loadCurrentPlaylistSettings() void ViewManager::onWidgetDestroyed( QWidget* widget ) { - qDebug() << "Destroyed child:" << widget << widget->metaObject()->className(); + tDebug() << "Destroyed child:" << widget << widget->metaObject()->className(); bool resetWidget = ( m_stack->currentWidget() == widget ); - for ( int i = 0; i < m_pageHistory.count(); i++ ) + QList< Tomahawk::ViewPage* > p = historyPages(); + for ( int i = 0; i < p.count(); i++ ) { - ViewPage* page = m_pageHistory.at( i ); + ViewPage* page = p.at( i ); if ( page->widget() != widget ) continue; @@ -840,17 +862,16 @@ ViewManager::onWidgetDestroyed( QWidget* widget ) { m_dynamicWidgets.remove( dynamicPlaylistForInterface( page->playlistInterface() ) ); } - - if ( page->widget() == widget && !resetWidget ) - { - m_pageHistory.removeAt( i ); - } + + m_pageHistoryBack.removeAll( page ); + m_pageHistoryFwd.removeAll( page ); } m_stack->removeWidget( widget ); if ( resetWidget ) { + m_currentPage = 0; historyBack(); } } @@ -898,14 +919,6 @@ ViewManager::setTomahawkLoaded() } - -ViewPage* -ViewManager::pageForCollection( const collection_ptr& col ) const -{ - return m_collectionViews.value( col ).data(); -} - - ViewPage* ViewManager::pageForDynPlaylist(const dynplaylist_ptr& pl) const { @@ -923,9 +936,11 @@ ViewManager::pageForPlaylist(const playlist_ptr& pl) const ViewPage* ViewManager::pageForInterface( Tomahawk::playlistinterface_ptr interface ) const { - for ( int i = 0; i < m_pageHistory.count(); i++ ) + QList< Tomahawk::ViewPage* > pages = historyPages(); + + for ( int i = 0; i < pages.count(); i++ ) { - ViewPage* page = m_pageHistory.at( i ); + ViewPage* page = pages.at( i ); if ( page->playlistInterface() == interface ) return page; if ( page->playlistInterface() && page->playlistInterface()->hasChildInterface( interface ) ) @@ -949,7 +964,7 @@ ViewManager::currentPlaylistInterface() const Tomahawk::ViewPage* ViewManager::currentPage() const { - return m_pageHistory.isEmpty() ? 0 : m_pageHistory.front(); + return m_currentPage; } @@ -986,18 +1001,11 @@ ViewManager::dynamicPlaylistForInterface( Tomahawk::playlistinterface_ptr interf Tomahawk::collection_ptr ViewManager::collectionForInterface( Tomahawk::playlistinterface_ptr interface ) const { - foreach ( QWeakPointer view, m_collectionViews.values() ) + foreach ( QWeakPointer view, m_collectionGridViews.values() ) { if ( view.data()->playlistInterface() == interface ) { - return m_collectionViews.key( view ); - } - } - foreach ( QWeakPointer view, m_collectionAlbumViews.values() ) - { - if ( view.data()->playlistInterface() == interface ) - { - return m_collectionAlbumViews.key( view ); + return m_collectionGridViews.key( view ); } } @@ -1008,9 +1016,9 @@ ViewManager::collectionForInterface( Tomahawk::playlistinterface_ptr interface ) bool ViewManager::isSuperCollectionVisible() const { - return ( m_pageHistory.count() && + return ( currentPage() != 0 && ( currentPage()->playlistInterface() == m_superCollectionView->playlistInterface() || - currentPage()->playlistInterface() == m_superAlbumView->playlistInterface() ) ); + currentPage()->playlistInterface() == m_superGridView->playlistInterface() ) ); } @@ -1026,11 +1034,11 @@ ViewManager::showCurrentTrack() // reset the correct mode, if the user has changed it since - if ( dynamic_cast< CollectionView* >( page ) ) + if ( dynamic_cast< TrackView* >( page ) ) m_currentMode = PlaylistModes::Flat; - else if ( dynamic_cast< AlbumView* >( page ) ) + else if ( dynamic_cast< GridView* >( page ) ) m_currentMode = PlaylistModes::Album; - else if ( dynamic_cast< ArtistView* >( page ) ) + else if ( dynamic_cast< TreeView* >( page ) ) m_currentMode = PlaylistModes::Tree; else return; @@ -1039,3 +1047,44 @@ ViewManager::showCurrentTrack() } } + +Tomahawk::ViewPage* +ViewManager::welcomeWidget() const +{ + return m_welcomeWidget; +} + + +Tomahawk::ViewPage* +ViewManager::whatsHotWidget() const +{ + return m_whatsHotWidget; +} + + +Tomahawk::ViewPage* +ViewManager::newReleasesWidget() const +{ + return m_newReleasesWidget; +} + + +Tomahawk::ViewPage* +ViewManager::topLovedWidget() const +{ + return m_topLovedWidget; +} + + +Tomahawk::ViewPage* +ViewManager::recentPlaysWidget() const +{ + return m_recentPlaysWidget; +} + + +TreeView* +ViewManager::superCollectionView() const +{ + return m_superCollectionView; +} diff --git a/src/libtomahawk/ViewManager.h b/src/libtomahawk/ViewManager.h index 2ac07447f..d4fefe1bf 100644 --- a/src/libtomahawk/ViewManager.h +++ b/src/libtomahawk/ViewManager.h @@ -29,21 +29,16 @@ #include "PlaylistInterface.h" #include "playlist/QueueView.h" #include "ViewPage.h" -#include "widgets/WelcomeWidget.h" -#include "widgets/WhatsHotWidget.h" -#include "widgets/NewReleasesWidget.h" #include "DllMacro.h" class AnimatedSplitter; class AlbumModel; -class AlbumView; +class GridView; class AlbumInfoWidget; class ArtistInfoWidget; -class ArtistView; +class TreeView; class CollectionModel; -class CollectionFlatModel; -class CollectionView; class ContextWidget; class PlaylistModel; class PlaylistView; @@ -56,6 +51,7 @@ class SourceInfoWidget; class InfoBar; class TopBar; class TrackInfoWidget; +class NewReleasesWidget; class WelcomeWidget; class WhatsHotWidget; class QPushButton; @@ -91,17 +87,16 @@ public: Tomahawk::ViewPage* show( Tomahawk::ViewPage* page ); - Tomahawk::ViewPage* welcomeWidget() const { return m_welcomeWidget; } - Tomahawk::ViewPage* whatsHotWidget() const { return m_whatsHotWidget; } - Tomahawk::ViewPage* newReleasesWidget() const { return m_newReleasesWidget; } - Tomahawk::ViewPage* topLovedWidget() const { return m_topLovedWidget; } - Tomahawk::ViewPage* recentPlaysWidget() const { return m_recentPlaysWidget; } - ArtistView* superCollectionView() const { return m_superCollectionView; } + Tomahawk::ViewPage* welcomeWidget() const; + Tomahawk::ViewPage* whatsHotWidget() const; + Tomahawk::ViewPage* newReleasesWidget() const; + Tomahawk::ViewPage* topLovedWidget() const; + Tomahawk::ViewPage* recentPlaysWidget() const; + TreeView* superCollectionView() const; /// Get the view page for the given item. Not pretty... Tomahawk::ViewPage* pageForPlaylist( const Tomahawk::playlist_ptr& pl ) const; Tomahawk::ViewPage* pageForDynPlaylist( const Tomahawk::dynplaylist_ptr& pl ) const; - Tomahawk::ViewPage* pageForCollection( const Tomahawk::collection_ptr& pl ) const; /// Get a playlist (or dynamic playlist ) from a ViewPage* if the page is PlaylistView or DynamicWidget. /// Lives here but used by SourcesModel @@ -160,7 +155,10 @@ public slots: Tomahawk::ViewPage* show( const Tomahawk::source_ptr& source ); void historyBack(); - void removeFromHistory( Tomahawk::ViewPage* p ); + void historyForward(); + + QList< Tomahawk::ViewPage* > historyPages() const; + void destroyPage( Tomahawk::ViewPage* page ); void showQueue() { emit showQueueRequested(); } void hideQueue() { emit hideQueueRequested(); } @@ -204,9 +202,9 @@ private: AnimatedSplitter* m_splitter; AlbumModel* m_superAlbumModel; - AlbumView* m_superAlbumView; + GridView* m_superGridView; TreeModel* m_superCollectionModel; - ArtistView* m_superCollectionView; + TreeView* m_superCollectionView; QueueView* m_queue; WelcomeWidget* m_welcomeWidget; WhatsHotWidget* m_whatsHotWidget; @@ -217,16 +215,17 @@ private: QList< Tomahawk::collection_ptr > m_superCollections; QHash< Tomahawk::dynplaylist_ptr, QWeakPointer > m_dynamicWidgets; - QHash< Tomahawk::collection_ptr, QWeakPointer > m_collectionViews; - QHash< Tomahawk::collection_ptr, QWeakPointer > m_treeViews; - QHash< Tomahawk::collection_ptr, QWeakPointer > m_collectionAlbumViews; + QHash< Tomahawk::collection_ptr, QWeakPointer > m_treeViews; + QHash< Tomahawk::collection_ptr, QWeakPointer > m_collectionGridViews; QHash< Tomahawk::artist_ptr, QWeakPointer > m_artistViews; QHash< Tomahawk::album_ptr, QWeakPointer > m_albumViews; QHash< Tomahawk::query_ptr, QWeakPointer > m_trackViews; QHash< Tomahawk::playlist_ptr, QWeakPointer > m_playlistViews; QHash< Tomahawk::source_ptr, QWeakPointer > m_sourceViews; - QList m_pageHistory; + QList m_pageHistoryBack; + QList m_pageHistoryFwd; + Tomahawk::ViewPage* m_currentPage; Tomahawk::collection_ptr m_currentCollection; int m_currentMode; diff --git a/src/libtomahawk/accounts/Account.cpp b/src/libtomahawk/accounts/Account.cpp index 7ab25d226..e182889eb 100644 --- a/src/libtomahawk/accounts/Account.cpp +++ b/src/libtomahawk/accounts/Account.cpp @@ -64,6 +64,8 @@ Account::~Account() } +#ifndef ENABLE_HEADLESS + QWidget* Account::configurationWidget() { @@ -84,6 +86,9 @@ Account::icon() const return QPixmap(); } +#endif + + void Account::authenticate() { diff --git a/src/libtomahawk/accounts/Account.h b/src/libtomahawk/accounts/Account.h index 6b8b35cb3..cb61cdf74 100644 --- a/src/libtomahawk/accounts/Account.h +++ b/src/libtomahawk/accounts/Account.h @@ -82,17 +82,18 @@ public: /** * Configuration widgets can have a "dataError( bool )" signal to enable/disable the OK button in their wrapper dialogs. */ +#ifndef ENABLE_HEADLESS virtual QWidget* configurationWidget() = 0; virtual QWidget* aboutWidget() { return 0; } + virtual QWidget* aclWidget() = 0; + virtual QPixmap icon() const = 0; +#endif virtual void saveConfig() {} // called when the widget has been edited. save values from config widget, call sync() to write to disk account generic settings QVariantHash credentials() const { QMutexLocker locker( &m_mutex ); return m_credentials; } QVariantMap acl() const { QMutexLocker locker( &m_mutex ); return m_acl; } - virtual QWidget* aclWidget() = 0; - - virtual QPixmap icon() const = 0; virtual ConnectionState connectionState() const = 0; virtual bool isAuthenticated() const = 0; diff --git a/src/AccountDelegate.cpp b/src/libtomahawk/accounts/AccountDelegate.cpp similarity index 99% rename from src/AccountDelegate.cpp rename to src/libtomahawk/accounts/AccountDelegate.cpp index 386886a87..8996b9aa9 100644 --- a/src/AccountDelegate.cpp +++ b/src/libtomahawk/accounts/AccountDelegate.cpp @@ -60,7 +60,6 @@ AccountDelegate::AccountDelegate( QObject* parent ) , m_accountRowHeight( -1 ) , m_model( 0 ) { - m_defaultCover.load( RESPATH "images/sipplugin-online.png" ); m_ratingStarPositive.load( RESPATH "images/starred.png" ); m_ratingStarNegative.load( RESPATH "images/star-unstarred.png" ); @@ -272,7 +271,7 @@ AccountDelegate::paint ( QPainter* painter, const QStyleOptionViewItem& option, } else if ( canDelete ) { - const QString btnText = tr( "Remove Account" ); + const QString btnText = tr( "Remove" ); const int btnWidth = installMetrics.width( btnText ) + 2*PADDING; QRect btnRect; @@ -282,7 +281,10 @@ AccountDelegate::paint ( QPainter* painter, const QStyleOptionViewItem& option, btnRect = QRect( opt.rect.right() - PADDING - btnWidth, center - ( installMetrics.height() + 4 ) / 2, btnWidth, installMetrics.height() + 2*PADDING ); #ifdef Q_WS_MAC - btnRect.adjust( -4, 2, 4, -2 ); + btnRect.adjust( -4, 0, 4, 0 ); + + if ( hasConfigWrench ) + btnRect.moveTop( btnRect.top() + 2 ); #endif leftEdge = btnRect.left(); m_cachedButtonRects[ index ] = btnRect; @@ -387,7 +389,7 @@ AccountDelegate::paint ( QPainter* painter, const QStyleOptionViewItem& option, const int countW = painter->fontMetrics().width( count ); const QRect countRect( runningEdge + 50, starsTop, countW, painter->fontMetrics().height() ); count = painter->fontMetrics().elidedText( count, Qt::ElideRight, rightEdge - PADDING - countRect.left() ); - painter->drawText( countRect, Qt::AlignLeft | Qt::TextWordWrap, count ); + painter->drawText( countRect, Qt::AlignLeft, count ); // runningEdge = authorRect.x(); } @@ -560,6 +562,7 @@ AccountDelegate::drawStatus( QPainter* painter, const QPointF& rightTopEdge, Acc { QPixmap p; QString statusText; + const Account::ConnectionState state = acct->connectionState(); if ( state == Account::Connected ) { @@ -683,7 +686,6 @@ void AccountDelegate::doneInstalling ( const QPersistentModelIndex& idx ) { qDebug() << "STOP INSTALLING:" << idx.data( Qt::DisplayRole ).toString(); - Q_ASSERT( m_loadingSpinners.contains( idx ) ); if ( !m_loadingSpinners.contains( idx ) ) return; diff --git a/src/AccountDelegate.h b/src/libtomahawk/accounts/AccountDelegate.h similarity index 97% rename from src/AccountDelegate.h rename to src/libtomahawk/accounts/AccountDelegate.h index 6fbcdffdb..1b70a7df6 100644 --- a/src/AccountDelegate.h +++ b/src/libtomahawk/accounts/AccountDelegate.h @@ -19,6 +19,7 @@ #ifndef ACCOUNTDELEGATE_H #define ACCOUNTDELEGATE_H +#include "DllMacro.h" #include #include "accounts/AccountModel.h" @@ -31,7 +32,7 @@ namespace Accounts class Account; -class AccountDelegate : public QStyledItemDelegate +class DLLEXPORT AccountDelegate : public QStyledItemDelegate { Q_OBJECT public: diff --git a/src/AccountFactoryWrapper.cpp b/src/libtomahawk/accounts/AccountFactoryWrapper.cpp similarity index 99% rename from src/AccountFactoryWrapper.cpp rename to src/libtomahawk/accounts/AccountFactoryWrapper.cpp index adf5cb41d..4b1214b1c 100644 --- a/src/AccountFactoryWrapper.cpp +++ b/src/libtomahawk/accounts/AccountFactoryWrapper.cpp @@ -20,7 +20,7 @@ #include "accounts/Account.h" #include "accounts/AccountManager.h" -#include "GuiHelpers.h" +#include "utils/GuiHelpers.h" #include "AccountFactoryWrapperDelegate.h" #include "DelegateConfigWrapper.h" #include "ui_AccountFactoryWrapper.h" diff --git a/src/AccountFactoryWrapper.h b/src/libtomahawk/accounts/AccountFactoryWrapper.h similarity index 95% rename from src/AccountFactoryWrapper.h rename to src/libtomahawk/accounts/AccountFactoryWrapper.h index 00e31e672..ac8bf195d 100644 --- a/src/AccountFactoryWrapper.h +++ b/src/libtomahawk/accounts/AccountFactoryWrapper.h @@ -19,6 +19,8 @@ #ifndef ACCOUNTFACTORYWRAPPER_H #define ACCOUNTFACTORYWRAPPER_H +#include "DllMacro.h" + #include #include @@ -33,7 +35,7 @@ class Account; class Ui_AccountFactoryWrapper; // class AccountFactoryWrapper_ -class AccountFactoryWrapper : public QDialog +class DLLEXPORT AccountFactoryWrapper : public QDialog { Q_OBJECT public: diff --git a/src/AccountFactoryWrapper.ui b/src/libtomahawk/accounts/AccountFactoryWrapper.ui similarity index 100% rename from src/AccountFactoryWrapper.ui rename to src/libtomahawk/accounts/AccountFactoryWrapper.ui diff --git a/src/AccountFactoryWrapperDelegate.cpp b/src/libtomahawk/accounts/AccountFactoryWrapperDelegate.cpp similarity index 100% rename from src/AccountFactoryWrapperDelegate.cpp rename to src/libtomahawk/accounts/AccountFactoryWrapperDelegate.cpp diff --git a/src/AccountFactoryWrapperDelegate.h b/src/libtomahawk/accounts/AccountFactoryWrapperDelegate.h similarity index 100% rename from src/AccountFactoryWrapperDelegate.h rename to src/libtomahawk/accounts/AccountFactoryWrapperDelegate.h diff --git a/src/libtomahawk/accounts/AccountManager.cpp b/src/libtomahawk/accounts/AccountManager.cpp index 22ab46d78..75db452ee 100644 --- a/src/libtomahawk/accounts/AccountManager.cpp +++ b/src/libtomahawk/accounts/AccountManager.cpp @@ -234,8 +234,11 @@ AccountManager::connectAll() tDebug( LOGVERBOSE ) << Q_FUNC_INFO; foreach( Account* acc, m_accounts ) { - acc->authenticate(); - m_enabledAccounts << acc; + if ( acc->enabled() ) + { + acc->authenticate(); + m_enabledAccounts << acc; + } } m_connected = true; diff --git a/src/libtomahawk/accounts/AccountModel.cpp b/src/libtomahawk/accounts/AccountModel.cpp index d853b8c46..41a1963c1 100644 --- a/src/libtomahawk/accounts/AccountModel.cpp +++ b/src/libtomahawk/accounts/AccountModel.cpp @@ -95,12 +95,14 @@ AccountModel::loadData() if ( acct ) { m_accounts << new AccountModelNode( acct ); -#if ACCOUNTMODEL_DEBUG const int removed = allAccounts.removeAll( acct ); +#if ACCOUNTMODEL_DEBUG qDebug() << "Removed custom account from misc accounts list, found:" << removed; qDebug() << "All accounts after remove:"; foreach ( Account* acct, allAccounts ) qDebug() << acct->accountFriendlyName() << "\t" << acct->accountId(); // All other accounts we haven't dealt with yet +#else + Q_UNUSED( removed ); #endif } } else @@ -109,10 +111,14 @@ AccountModel::loadData() foreach ( Account* acct, AccountManager::instance()->accounts( Accounts::ResolverType ) ) { -// qDebug() << "Found ResolverAccount" << acct->accountFriendlyName(); +#if ACCOUNTMODEL_DEBUG + qDebug() << "Found ResolverAccount" << acct->accountFriendlyName(); +#endif if ( AtticaResolverAccount* resolver = qobject_cast< AtticaResolverAccount* >( acct ) ) { -// qDebug() << "Which is an attica resolver with id:" << resolver->atticaId(); +#if ACCOUNTMODEL_DEBUG + qDebug() << "Which is an attica resolver with id:" << resolver->atticaId(); +#endif if ( resolver->atticaId() == content.id() ) { allAccounts.removeAll( acct ); @@ -345,12 +351,15 @@ AccountModel::data( const QModelIndex& index, int role ) const Q_ASSERT( node->customAccount ); Q_ASSERT( node->factory ); - Account* account = node->customAccount; - // This is sort of ugly. CustomAccounts are pure Account*, but we know that + Attica::Content content = node->atticaContent; + // This is ugly. CustomAccounts are pure Account*, but we know that // some might also be linked to attica resolvers (not always). If that is the case // they have a Attica::Content set on the node, so we use that to display some // extra metadata and rating - const bool hasAttica = !node->atticaContent.id().isEmpty(); + Account* account = node->customAccount; + if ( node->type == AccountModelNode::CustomAccountType && qobject_cast< CustomAtticaAccount* >( account ) ) + content = qobject_cast< CustomAtticaAccount* >( node->customAccount )->atticaContent(); + const bool hasAttica = !content.id().isNull(); switch ( role ) { @@ -362,15 +371,15 @@ AccountModel::data( const QModelIndex& index, int role ) const return ShippedWithTomahawk; case Qt::ToolTipRole: case DescriptionRole: - return hasAttica ? node->atticaContent.description() : node->factory->description(); + return hasAttica ? content.description() : node->factory->description(); case CanRateRole: return hasAttica; case AuthorRole: - return hasAttica ? node->atticaContent.author() : QString(); + return hasAttica ? content.author() : QString(); case RatingRole: - return hasAttica ? node->atticaContent.rating() / 20 : 0; // rating is out of 100 + return hasAttica ? content.rating() / 20 : 0; // rating is out of 100 case DownloadCounterRole: - return hasAttica ? node->atticaContent.downloads() : QVariant(); + return hasAttica ? content.downloads() : QVariant(); case RowTypeRole: return CustomAccount; case AccountData: @@ -383,6 +392,8 @@ AccountModel::data( const QModelIndex& index, int role ) const return account->enabled() ? Qt::Checked : Qt::Unchecked; case ConnectionStateRole: return account->connectionState(); + case UserHasRatedRole: + return hasAttica ? AtticaManager::instance()->userHasRated( content ) : false; default: return QVariant(); } @@ -405,6 +416,9 @@ AccountModel::setData( const QModelIndex& index, const QVariant& value, int role if ( role == CheckboxClickedRole ) { Account* acct = 0; + + Qt::CheckState checkState = static_cast< Qt::CheckState >( value.toInt() ); + switch ( node->type ) { case AccountModelNode::UniqueFactoryType: @@ -442,9 +456,11 @@ AccountModel::setData( const QModelIndex& index, const QVariant& value, int role state = AtticaManager::Uninstalled; } - if ( state == AtticaManager::Installed ) + // Don't install if we're unchecking. This happens if e.g. the user deletes his config file + // and opens tomahawk + if ( state == AtticaManager::Installed || checkState == Qt::Unchecked ) { - qDebug() << "Already installed with resolver, just enabling"; + qDebug() << "Already installed with resolver, or unchecking, just enabling/disabling"; acct = node->atticaAccount; break; } @@ -459,7 +475,11 @@ AccountModel::setData( const QModelIndex& index, const QVariant& value, int role qDebug() << "Kicked off fetch+install, now waiting"; m_waitingForAtticaInstall.insert( resolver.id() ); - AtticaManager::instance()->installResolver( resolver ); + if ( node->atticaAccount ) + AtticaManager::instance()->installResolverWithHandler( resolver, node->atticaAccount ); + else + AtticaManager::instance()->installResolver( resolver, true ); + return true; } @@ -476,13 +496,15 @@ AccountModel::setData( const QModelIndex& index, const QVariant& value, int role if ( node->type == AccountModelNode::FactoryType ) { + tLog() << "Factory account with members:" << node->accounts << node->accounts.size(); // Turn on or off all accounts for this factory - - Qt::CheckState state = static_cast< Qt::CheckState >( value.toInt() ); - foreach ( Account* acct, node->accounts ) { - state == Qt::Checked ? AccountManager::instance()->enableAccount( acct ) + tLog() << "Account we are toggling for factory:" << acct; + if ( !acct ) + continue; + + checkState == Qt::Checked ? AccountManager::instance()->enableAccount( acct ) : AccountManager::instance()->disableAccount( acct ); } @@ -507,7 +529,7 @@ AccountModel::setData( const QModelIndex& index, const QVariant& value, int role box.setWindowTitle( tr( "Manual Install Required" ) ); box.setTextFormat( Qt::RichText ); box.setIcon( QMessageBox::Information ); - box.setText( tr( "Unfortunately, automatic installation of this resolver is not yet available on Linux.

" + box.setText( tr( "Unfortunately, automatic installation of this resolver is not available or disabled for your platform.

" "Please use \"Install from file\" above, by fetching it from your distribution or compiling it yourself. Further instructions can be found here:

http://www.tomahawk-player.org/resolvers/%1" ).arg( acct->accountServiceName() ) ); box.setStandardButtons( QMessageBox::Ok ); box.exec(); @@ -542,16 +564,29 @@ AccountModel::setData( const QModelIndex& index, const QVariant& value, int role if ( role == RatingRole ) { // We only support rating Attica resolvers for the moment. - Q_ASSERT( node->type == AccountModelNode::AtticaType ); + Attica::Content content; + if ( node->type == AccountModelNode::AtticaType ) + { + content = node->atticaContent; - AtticaManager::ResolverState state = AtticaManager::instance()->resolverState( node->atticaContent ); - // For now only allow rating if a resolver is installed! - if ( state != AtticaManager::Installed && state != AtticaManager::NeedsUpgrade ) + AtticaManager::ResolverState state = AtticaManager::instance()->resolverState( content ); + // For now only allow rating if a resolver is installed! + if ( state != AtticaManager::Installed && state != AtticaManager::NeedsUpgrade ) + return false; + } // Allow rating custom attica accounts regardless as user may have installed manually + else if ( node->type == AccountModelNode::CustomAccountType && qobject_cast< CustomAtticaAccount* >( node->customAccount ) ) + content = qobject_cast< CustomAtticaAccount* >( node->customAccount )->atticaContent(); + + Q_ASSERT( !content.id().isNull() ); + + if ( AtticaManager::instance()->userHasRated( content ) ) return false; - if ( AtticaManager::instance()->userHasRated( node->atticaContent ) ) - return false; - node->atticaContent.setRating( value.toInt() * 20 ); - AtticaManager::instance()->uploadRating( node->atticaContent ); + + content.setRating( value.toInt() * 20 ); + AtticaManager::instance()->uploadRating( content ); + + if ( node->type == AccountModelNode::AtticaType ) + node->atticaContent = content; emit dataChanged( index, index ); @@ -729,6 +764,12 @@ AccountModel::indexForAtticaId( const QString& resolverId ) const { return index( i, 0, QModelIndex() ); } + else if ( m_accounts[ i ]->type == AccountModelNode::CustomAccountType && qobject_cast< CustomAtticaAccount* >( m_accounts[ i ]->customAccount ) ) + { + const CustomAtticaAccount* atticaAcct = qobject_cast< CustomAtticaAccount* >( m_accounts[ i ]->customAccount ); + if ( atticaAcct->atticaContent().id() == resolverId ) + return index( i, 0, QModelIndex() ); + } } return QModelIndex(); diff --git a/src/libtomahawk/accounts/AccountModelNode.h b/src/libtomahawk/accounts/AccountModelNode.h index 857d57402..18486ef8b 100644 --- a/src/libtomahawk/accounts/AccountModelNode.h +++ b/src/libtomahawk/accounts/AccountModelNode.h @@ -139,9 +139,6 @@ struct AccountModelNode { init(); customAccount = account; factory = AccountManager::instance()->factoryForAccount( account ); - - if ( CustomAtticaAccount* customAtticaAccount = qobject_cast< CustomAtticaAccount* >( account ) ) - atticaContent = customAtticaAccount->atticaContent(); } void init() diff --git a/src/DelegateConfigWrapper.cpp b/src/libtomahawk/accounts/DelegateConfigWrapper.cpp similarity index 99% rename from src/DelegateConfigWrapper.cpp rename to src/libtomahawk/accounts/DelegateConfigWrapper.cpp index abd1de5ad..fccd60606 100644 --- a/src/DelegateConfigWrapper.cpp +++ b/src/libtomahawk/accounts/DelegateConfigWrapper.cpp @@ -124,12 +124,9 @@ DelegateConfigWrapper::rejected() void DelegateConfigWrapper::updateSizeHint() { - hide(); setSizeGripEnabled( false ); setMinimumSize( sizeHint() ); setMaximumSize( sizeHint() ); - - show(); } diff --git a/src/DelegateConfigWrapper.h b/src/libtomahawk/accounts/DelegateConfigWrapper.h similarity index 100% rename from src/DelegateConfigWrapper.h rename to src/libtomahawk/accounts/DelegateConfigWrapper.h diff --git a/src/libtomahawk/accounts/ResolverAccount.cpp b/src/libtomahawk/accounts/ResolverAccount.cpp index 799279df8..30a3800e8 100644 --- a/src/libtomahawk/accounts/ResolverAccount.cpp +++ b/src/libtomahawk/accounts/ResolverAccount.cpp @@ -72,20 +72,13 @@ ResolverAccountFactory::createFromPath( const QString& path, const QString& fact ResolverAccount::ResolverAccount( const QString& accountId ) : Account( accountId ) { - const QString path = configuration()[ "path" ].toString(); + setTypes( AccountType( ResolverType ) ); // We should have a valid saved path Q_ASSERT( !path.isEmpty() ); - m_resolver = QWeakPointer< ExternalResolverGui >( qobject_cast< ExternalResolverGui* >( Pipeline::instance()->addScriptResolver( path, enabled() ) ) ); - connect( m_resolver.data(), SIGNAL( changed() ), this, SLOT( resolverChanged() ) ); - - // What resolver do we have here? Should only be types that are 'real' resolvers - Q_ASSERT ( !m_resolver.isNull() ); - - setAccountFriendlyName( m_resolver.data()->name() ); - setTypes( AccountType( ResolverType ) ); + init( path ); } @@ -95,16 +88,8 @@ ResolverAccount::ResolverAccount( const QString& accountId, const QString& path QVariantHash configuration; configuration[ "path" ] = path; setConfiguration( configuration ); - setEnabled( true ); - m_resolver = QWeakPointer< ExternalResolverGui >( qobject_cast< ExternalResolverGui* >( Pipeline::instance()->addScriptResolver( path, true ) ) ); - connect( m_resolver.data(), SIGNAL( changed() ), this, SLOT( resolverChanged() ) ); - - // What resolver do we have here? Should only be types that are 'real' resolvers - Q_ASSERT ( m_resolver.data() ); - - setAccountFriendlyName( m_resolver.data()->name() ); - setTypes( AccountType( ResolverType ) ); + init( path ); sync(); } @@ -120,12 +105,44 @@ ResolverAccount::~ResolverAccount() } +void +ResolverAccount::init( const QString& path ) +{ + setTypes( AccountType( ResolverType ) ); + + if ( !QFile::exists( path ) ) + { + AccountManager::instance()->disableAccount( this ); + } + else + { + hookupResolver(); + } +} + + +void +ResolverAccount::hookupResolver() +{ + tDebug() << "Hooking up resolver:" << configuration().value( "path" ).toString() << enabled(); + + m_resolver = QWeakPointer< ExternalResolverGui >( qobject_cast< ExternalResolverGui* >( Pipeline::instance()->addScriptResolver( configuration().value( "path" ).toString() ) ) ); + connect( m_resolver.data(), SIGNAL( changed() ), this, SLOT( resolverChanged() ) ); + + // What resolver do we have here? Should only be types that are 'real' resolvers + Q_ASSERT ( m_resolver.data() ); + + setAccountFriendlyName( m_resolver.data()->name() ); +} + void ResolverAccount::authenticate() { - Q_ASSERT( !m_resolver.isNull() ); - qDebug() << Q_FUNC_INFO << "Authenticating/starting resolver, exists?" << m_resolver; + if ( m_resolver.isNull() ) + return; + + tDebug() << Q_FUNC_INFO << "Authenticating/starting resolver, exists?" << m_resolver.data()->name(); if ( !m_resolver.data()->running() ) m_resolver.data()->start(); @@ -137,14 +154,14 @@ ResolverAccount::authenticate() bool ResolverAccount::isAuthenticated() const { - return m_resolver.data()->running(); + return !m_resolver.isNull() && m_resolver.data()->running(); } void ResolverAccount::deauthenticate() { - if ( m_resolver.data()->running() ) + if ( !m_resolver.isNull() && m_resolver.data()->running() ) m_resolver.data()->stop(); emit connectionStateChanged( connectionState() ); @@ -155,7 +172,7 @@ ResolverAccount::deauthenticate() Account::ConnectionState ResolverAccount::connectionState() const { - if ( m_resolver.data()->running() ) + if ( !m_resolver.isNull() && m_resolver.data()->running() ) return Connected; else return Disconnected; @@ -165,6 +182,9 @@ ResolverAccount::connectionState() const QWidget* ResolverAccount::configurationWidget() { + if ( m_resolver.isNull() ) + return 0; + return m_resolver.data()->configUI(); } @@ -189,13 +209,17 @@ ResolverAccount::removeFromConfig() void ResolverAccount::saveConfig() { Account::saveConfig(); - m_resolver.data()->saveConfig(); + if ( !m_resolver.isNull() ) + m_resolver.data()->saveConfig(); } QString ResolverAccount::path() const { + if ( m_resolver.isNull() ) + return QString(); + return m_resolver.data()->filePath(); } @@ -236,19 +260,34 @@ AtticaResolverAccount::AtticaResolverAccount( const QString& accountId, const QS AtticaResolverAccount::~AtticaResolverAccount() { - } + void AtticaResolverAccount::loadIcon() { + if ( m_resolver.isNull() ) + return; + const QFileInfo fi( m_resolver.data()->filePath() ); QDir codeDir = fi.absoluteDir(); codeDir.cd( "../images" ); if ( codeDir.exists() && codeDir.exists( "icon.png" ) ) m_icon.load( codeDir.absoluteFilePath( "icon.png" ) ); +} + +void +AtticaResolverAccount::setPath( const QString& path ) +{ + QVariantHash config = configuration(); + config[ "path" ] = path; + setConfiguration( config ); + + hookupResolver(); + + sync(); } diff --git a/src/libtomahawk/accounts/ResolverAccount.h b/src/libtomahawk/accounts/ResolverAccount.h index bcf167640..fb3f5487e 100644 --- a/src/libtomahawk/accounts/ResolverAccount.h +++ b/src/libtomahawk/accounts/ResolverAccount.h @@ -89,8 +89,14 @@ private slots: protected: // Created by factory, when user installs a new resolver ResolverAccount( const QString& accountId, const QString& path ); + + void hookupResolver(); + QWeakPointer m_resolver; +private: + void init( const QString& path ); + friend class ResolverAccountFactory; }; @@ -110,6 +116,8 @@ public: virtual QPixmap icon() const; QString atticaId() const { return m_atticaId; } + + void setPath( const QString& path ); private: // Created by factory, when user installs a new resolver AtticaResolverAccount( const QString& accountId, const QString& path, const QString& atticaId ); diff --git a/src/accounts/lastfm/LastFmAccount.cpp b/src/libtomahawk/accounts/lastfm/LastFmAccount.cpp similarity index 98% rename from src/accounts/lastfm/LastFmAccount.cpp rename to src/libtomahawk/accounts/lastfm/LastFmAccount.cpp index 25364e3e3..44433a6a2 100644 --- a/src/accounts/lastfm/LastFmAccount.cpp +++ b/src/libtomahawk/accounts/lastfm/LastFmAccount.cpp @@ -75,7 +75,6 @@ LastFmAccount::LastFmAccount( const QString& accountId ) { infoPlugin().data()->moveToThread( Tomahawk::InfoSystem::InfoSystem::instance()->workerThread().data() ); Tomahawk::InfoSystem::InfoSystem::instance()->addInfoPlugin( infoPlugin() ); - QMetaObject::invokeMethod( infoPlugin().data(), "init", Qt::QueuedConnection ); } } @@ -289,7 +288,7 @@ LastFmAccount::hookupResolver() const AtticaManager::Resolver data = AtticaManager::instance()->resolverData( res.id() ); - m_resolver = QWeakPointer< ExternalResolverGui >( qobject_cast< ExternalResolverGui* >( Pipeline::instance()->addScriptResolver( data.scriptPath, enabled() ) ) ); + m_resolver = QWeakPointer< ExternalResolverGui >( qobject_cast< ExternalResolverGui* >( Pipeline::instance()->addScriptResolver( data.scriptPath ) ) ); connect( m_resolver.data(), SIGNAL( changed() ), this, SLOT( resolverChanged() ) ); } diff --git a/src/accounts/lastfm/LastFmAccount.h b/src/libtomahawk/accounts/lastfm/LastFmAccount.h similarity index 92% rename from src/accounts/lastfm/LastFmAccount.h rename to src/libtomahawk/accounts/lastfm/LastFmAccount.h index 90ca37737..f1b7ffc0c 100644 --- a/src/accounts/lastfm/LastFmAccount.h +++ b/src/libtomahawk/accounts/lastfm/LastFmAccount.h @@ -21,6 +21,7 @@ #include "accounts/Account.h" #include "AtticaManager.h" +#include "DllMacro.h" #include @@ -37,7 +38,7 @@ namespace Accounts { class LastFmConfig; -class LastFmAccountFactory : public AccountFactory +class DLLEXPORT LastFmAccountFactory : public AccountFactory { Q_OBJECT public: @@ -57,11 +58,11 @@ private: }; /** - * 3.Last.Fm account is special. It is both an attica resolver *and* a InfoPlugin. We always want the infoplugin, + * Last.Fm account is special. It is both an attica resolver *and* a InfoPlugin. We always want the infoplugin, * but the user can install the attica resolver on-demand. So we take care of both there. * */ -class LastFmAccount : public CustomAtticaAccount +class DLLEXPORT LastFmAccount : public CustomAtticaAccount { Q_OBJECT public: diff --git a/src/accounts/lastfm/LastFmConfig.cpp b/src/libtomahawk/accounts/lastfm/LastFmConfig.cpp similarity index 51% rename from src/accounts/lastfm/LastFmConfig.cpp rename to src/libtomahawk/accounts/lastfm/LastFmConfig.cpp index d364d7ba4..354f6b92e 100644 --- a/src/accounts/lastfm/LastFmConfig.cpp +++ b/src/libtomahawk/accounts/lastfm/LastFmConfig.cpp @@ -17,34 +17,40 @@ */ #include "LastFmConfig.h" +#include "ui_LastFmConfig.h" #include "LastFmAccount.h" -#include -#include "ui_LastFmConfig.h" +#include "database/Database.h" +#include "database/DatabaseCommand_LogPlayback.h" +#include "utils/TomahawkUtils.h" +#include "utils/Logger.h" #include "lastfm/ws.h" -#include "lastfm/XmlQuery" +#include "lastfm/User.h" +#include "lastfm/XmlQuery.h" using namespace Tomahawk::Accounts; + LastFmConfig::LastFmConfig( LastFmAccount* account ) : QWidget( 0 ) , m_account( account ) + , m_page( 1 ) + , m_lastTimeStamp( 0 ) { m_ui = new Ui_LastFmConfig; m_ui->setupUi( this ); + m_ui->progressBar->hide(); + m_ui->username->setText( m_account->username() ); m_ui->password->setText( m_account->password() ); m_ui->enable->setChecked( m_account->scrobble() ); - connect( m_ui->testLogin, SIGNAL( clicked( bool ) ), this, SLOT( testLogin( bool ) ) ); + connect( m_ui->testLogin, SIGNAL( clicked( bool ) ), SLOT( testLogin() ) ); + connect( m_ui->importHistory, SIGNAL( clicked( bool ) ), SLOT( loadHistory() ) ); - connect( m_ui->username, SIGNAL( textChanged( QString ) ), this, SLOT( enableButton() ) ); - connect( m_ui->password, SIGNAL( textChanged( QString ) ), this, SLOT( enableButton() ) ); - -// #ifdef Q_WS_MAC // FIXME -// m_ui->testLogin->setVisible( false ); -// #endif + connect( m_ui->username, SIGNAL( textChanged( QString ) ), SLOT( enableButton() ) ); + connect( m_ui->password, SIGNAL( textChanged( QString ) ), SLOT( enableButton() ) ); } @@ -70,10 +76,10 @@ LastFmConfig::username() const void -LastFmConfig::testLogin(bool ) +LastFmConfig::testLogin() { m_ui->testLogin->setEnabled( false ); - m_ui->testLogin->setText( "Testing..." ); + m_ui->testLogin->setText( tr( "Testing..." ) ); QString authToken = TomahawkUtils::md5( ( m_ui->username->text().toLower() + TomahawkUtils::md5( m_ui->password->text().toUtf8() ) ).toUtf8() ); @@ -100,6 +106,90 @@ LastFmConfig::enableButton() } +void +LastFmConfig::loadHistory() +{ + if ( m_lastTimeStamp ) + { + m_ui->importHistory->setText( tr( "Importing %1", "e.g. Importing 2012/01/01" ).arg( QDateTime::fromTime_t( m_lastTimeStamp ).toString( "MMMM d yyyy" ) ) ); + } + else + m_ui->importHistory->setText( tr( "Importing History..." ) ); + + m_ui->importHistory->setEnabled( false ); + m_ui->progressBar->show(); + + emit sizeHintChanged(); + + QNetworkReply* reply = lastfm::User( m_ui->username->text().toLower() ).getRecentTracks( 200, m_page ); + connect( reply, SIGNAL( finished() ), SLOT( onHistoryLoaded() ) ); +} + + +void +LastFmConfig::onHistoryLoaded() +{ + int total = 0; + bool finished = false; + QNetworkReply* reply = qobject_cast< QNetworkReply* >( sender() ); + + try + { + lastfm::XmlQuery lfm; + lfm.parse( reply->readAll() ); + + foreach ( lastfm::XmlQuery e, lfm.children( "track" ) ) + { +// tDebug() << "Found:" << e["artist"].text() << e["name"].text() << e["date"].attribute( "uts" ).toUInt(); + Tomahawk::query_ptr query = Query::get( e["artist"].text(), e["name"].text(), QString(), QString(), false ); + m_lastTimeStamp = e["date"].attribute( "uts" ).toUInt(); + + DatabaseCommand_LogPlayback* cmd = new DatabaseCommand_LogPlayback( query, DatabaseCommand_LogPlayback::Finished, m_lastTimeStamp ); + Database::instance()->enqueue( QSharedPointer(cmd) ); + } + + if ( !lfm.children( "recenttracks" ).isEmpty() ) + { + lastfm::XmlQuery stats = lfm.children( "recenttracks" ).first(); + + int page = stats.attribute( "page" ).toInt(); + total = stats.attribute( "totalPages" ).toInt(); + + m_ui->progressBar->setMaximum( total ); + m_ui->progressBar->setValue( page ); + + if ( page < total ) + { + m_page = page + 1; + loadHistory(); + } + else + finished = true; + } + else + finished = true; + } + catch( lastfm::ws::ParseError e ) + { + tDebug() << "XmlQuery error:" << e.message(); + finished = true; + } + + if ( finished ) + { + if ( m_page != total ) + { + m_ui->importHistory->setText( tr( "History Incomplete. Resume" ) ); + m_ui->importHistory->setEnabled( true ); + } + else + { + m_ui->importHistory->setText( tr( "Playback History Imported" ) ); + } + } +} + + void LastFmConfig::onLastFmFinished() { @@ -111,7 +201,8 @@ LastFmConfig::onLastFmFinished() } if( authJob->error() == QNetworkReply::NoError ) { - lastfm::XmlQuery lfm = lastfm::XmlQuery( authJob->readAll() ); + lastfm::XmlQuery lfm; + lfm.parse( authJob->readAll() ); if( lfm.children( "error" ).size() > 0 ) { diff --git a/src/accounts/lastfm/LastFmConfig.h b/src/libtomahawk/accounts/lastfm/LastFmConfig.h similarity index 87% rename from src/accounts/lastfm/LastFmConfig.h rename to src/libtomahawk/accounts/lastfm/LastFmConfig.h index f6e0d72be..c7c53f2b9 100644 --- a/src/accounts/lastfm/LastFmConfig.h +++ b/src/libtomahawk/accounts/lastfm/LastFmConfig.h @@ -24,6 +24,7 @@ class Ui_LastFmConfig; namespace Tomahawk { + namespace Accounts { class LastFmAccount; @@ -39,18 +40,28 @@ public: bool scrobble() const; public slots: - void testLogin( bool ); + void testLogin(); void onLastFmFinished(); private slots: void enableButton(); + + void loadHistory(); + void onHistoryLoaded(); + +signals: + void sizeHintChanged(); private: LastFmAccount* m_account; Ui_LastFmConfig* m_ui; + + unsigned int m_page; + unsigned int m_lastTimeStamp; }; } + } #endif // LASTFMCONFIG_H diff --git a/src/accounts/lastfm/LastFmConfig.ui b/src/libtomahawk/accounts/lastfm/LastFmConfig.ui similarity index 85% rename from src/accounts/lastfm/LastFmConfig.ui rename to src/libtomahawk/accounts/lastfm/LastFmConfig.ui index 5cdf0e5e8..1a75ae970 100644 --- a/src/accounts/lastfm/LastFmConfig.ui +++ b/src/libtomahawk/accounts/lastfm/LastFmConfig.ui @@ -7,7 +7,7 @@ 0 0 400 - 220 + 253
@@ -77,6 +77,20 @@ + + + + Import Playback History + + + + + + + 0 + + + diff --git a/src/accounts/lastfm/LastFmInfoPlugin.cpp b/src/libtomahawk/accounts/lastfm/LastFmInfoPlugin.cpp similarity index 98% rename from src/accounts/lastfm/LastFmInfoPlugin.cpp rename to src/libtomahawk/accounts/lastfm/LastFmInfoPlugin.cpp index 3217e9d51..40f67a9e7 100644 --- a/src/accounts/lastfm/LastFmInfoPlugin.cpp +++ b/src/libtomahawk/accounts/lastfm/LastFmInfoPlugin.cpp @@ -34,7 +34,7 @@ #include "TomahawkSettings.h" #include -#include +#include #include @@ -212,6 +212,11 @@ LastFmInfoPlugin::scrobble() return; tLog() << Q_FUNC_INFO << "Scrobbling now:" << m_track.toString(); + + // FIXME: workaround for the duration-less dilandau (and others) tracks + if ( m_track.duration() == 0 ) + m_track.setDuration( 31 ); + m_scrobbler->cache( m_track ); m_scrobbler->submit(); } @@ -866,7 +871,8 @@ LastFmInfoPlugin::onAuthenticated() if ( authJob->error() == QNetworkReply::NoError ) { - lastfm::XmlQuery lfm = lastfm::XmlQuery( authJob->readAll() ); + lastfm::XmlQuery lfm; + lfm.parse( authJob->readAll() ); if ( lfm.children( "error" ).size() > 0 ) { @@ -928,7 +934,8 @@ LastFmInfoPlugin::parseTrackList( QNetworkReply* reply ) QList tracks; try { - lastfm::XmlQuery lfm = reply->readAll(); + lastfm::XmlQuery lfm; + lfm.parse( reply->readAll() ); foreach ( lastfm::XmlQuery xq, lfm.children( "track" ) ) { tracks.append( lastfm::Track( xq ) ); @@ -936,7 +943,7 @@ LastFmInfoPlugin::parseTrackList( QNetworkReply* reply ) } catch ( lastfm::ws::ParseError& e ) { - qWarning() << e.what(); + qWarning() << e.message(); } return tracks; diff --git a/src/accounts/lastfm/LastFmInfoPlugin.h b/src/libtomahawk/accounts/lastfm/LastFmInfoPlugin.h similarity index 93% rename from src/accounts/lastfm/LastFmInfoPlugin.h rename to src/libtomahawk/accounts/lastfm/LastFmInfoPlugin.h index 443192b03..f8bbacd17 100644 --- a/src/accounts/lastfm/LastFmInfoPlugin.h +++ b/src/libtomahawk/accounts/lastfm/LastFmInfoPlugin.h @@ -22,10 +22,11 @@ #include "infosystem/InfoSystem.h" #include "infosystem/InfoSystemWorker.h" +#include "DllMacro.h" -#include -#include -#include +#include +#include +#include #include @@ -42,7 +43,7 @@ namespace Accounts namespace InfoSystem { -class LastFmInfoPlugin : public InfoPlugin +class DLLEXPORT LastFmInfoPlugin : public InfoPlugin { Q_OBJECT @@ -51,7 +52,6 @@ public: virtual ~LastFmInfoPlugin(); public slots: - void init(); void settingsChanged(); void onAuthenticated(); @@ -63,6 +63,7 @@ public slots: void similarTracksReturned(); protected slots: + virtual void init(); virtual void getInfo( Tomahawk::InfoSystem::InfoRequestData requestData ); virtual void notInCacheSlot( Tomahawk::InfoSystem::InfoStringHash criteria, Tomahawk::InfoSystem::InfoRequestData requestData ); diff --git a/src/accounts/spotify/SpotifyAccount.cpp b/src/libtomahawk/accounts/spotify/SpotifyAccount.cpp similarity index 95% rename from src/accounts/spotify/SpotifyAccount.cpp rename to src/libtomahawk/accounts/spotify/SpotifyAccount.cpp index c4f2ba289..d786be550 100644 --- a/src/accounts/spotify/SpotifyAccount.cpp +++ b/src/libtomahawk/accounts/spotify/SpotifyAccount.cpp @@ -52,8 +52,12 @@ static QPixmap* s_icon = 0; static QString s_resolverId = "spotify-osx"; #elif defined(Q_OS_WIN) static QString s_resolverId = "spotify-win"; +#elif defined(Q_OS_LINUX) && defined(__GNUC__) && defined(__x86_64__) +static QString s_resolverId = "spotify-linux-x64"; +#elif defined(Q_OS_LINUX) +static QString s_resolverId = "spotify-linux-x86"; #else -static QString s_resolverId = "spotify-linux"; +static QString s_resolverId = "spotify-unknown"; #endif Account* @@ -84,6 +88,12 @@ SpotifyAccount::SpotifyAccount( const QString& accountId ) SpotifyAccount::~SpotifyAccount() { clearUser(); + + if ( m_spotifyResolver.isNull() ) + return; + + Pipeline::instance()->removeScriptResolver( m_spotifyResolver.data()->filePath() ); + delete m_spotifyResolver.data(); } @@ -93,16 +103,24 @@ SpotifyAccount::init() setAccountFriendlyName( "Spotify" ); setAccountServiceName( "spotify" ); + AtticaManager::instance()->registerCustomAccount( s_resolverId, this ); + qRegisterMetaType< Tomahawk::Accounts::SpotifyPlaylistInfo* >( "Tomahawk::Accounts::SpotifyPlaylist*" ); + if ( !AtticaManager::instance()->resolversLoaded() ) { // If we're still waiting to load, wait for the attica resolvers to come down the pipe - connect( AtticaManager::instance(), SIGNAL( resolversLoaded( Attica::Content::List ) ), this, SLOT( init() ), Qt::UniqueConnection ); - return; + connect( AtticaManager::instance(), SIGNAL( resolversLoaded( Attica::Content::List ) ), this, SLOT( delayedInit() ), Qt::UniqueConnection ); } + else + { + delayedInit(); + } +} - qRegisterMetaType< Tomahawk::Accounts::SpotifyPlaylistInfo* >( "Tomahawk::Accounts::SpotifyPlaylist*" ); - AtticaManager::instance()->registerCustomAccount( s_resolverId, this ); +void +SpotifyAccount::delayedInit() +{ connect( AtticaManager::instance(), SIGNAL( resolverInstalled( QString ) ), this, SLOT( resolverInstalled( QString ) ) ); @@ -147,7 +165,7 @@ SpotifyAccount::hookupResolver() } qDebug() << "Starting spotify resolver with path:" << path; - m_spotifyResolver = QWeakPointer< ScriptResolver >( qobject_cast< ScriptResolver* >( Pipeline::instance()->addScriptResolver( path, enabled() ) ) ); + m_spotifyResolver = QWeakPointer< ScriptResolver >( qobject_cast< ScriptResolver* >( Pipeline::instance()->addScriptResolver( path ) ) ); connect( m_spotifyResolver.data(), SIGNAL( changed() ), this, SLOT( resolverChanged() ) ); connect( m_spotifyResolver.data(), SIGNAL( customMessage( QString,QVariantMap ) ), this, SLOT( resolverMessage( QString, QVariantMap ) ) ); @@ -171,9 +189,12 @@ SpotifyAccount::checkForResolver() const QDir path = QCoreApplication::applicationDirPath(); QFile file( path.absoluteFilePath( "spotify_tomahawkresolver" ) ); return file.exists(); -#else if defined(Q_OS_WIN) +#elif defined(Q_OS_WIN) QDir appDataDir = TomahawkUtils::appDataDir(); return appDataDir.exists( QString( "atticaresolvers/%1/spotify_tomahawkresolver.exe" ).arg( s_resolverId ) ); +#elif defined(Q_OS_LINUX) + QDir appDataDir = TomahawkUtils::appDataDir(); + return appDataDir.exists( QString( "atticaresolvers/%1/spotify_tomahawkresolver" ).arg( s_resolverId ) ); #endif return false; @@ -298,6 +319,7 @@ SpotifyAccount::setManualResolverPath( const QString &resolverPath ) if ( !m_spotifyResolver.isNull() ) { // replace + AccountManager::instance()->disableAccount( this ); NewClosure( m_spotifyResolver.data(), SIGNAL( destroyed() ), this, SLOT( hookupAfterDeletion( bool ) ), true ); m_spotifyResolver.data()->deleteLater(); } @@ -326,13 +348,16 @@ SpotifyAccount::aboutToShow( QAction* action, const playlist_ptr& playlist ) // If it's not being synced, allow the option to sync bool found = false; + bool manuallyDisabled = false; QList updaters = playlist->updaters(); foreach ( PlaylistUpdaterInterface* updater, updaters ) { if ( SpotifyPlaylistUpdater* spotifyUpdater = qobject_cast< SpotifyPlaylistUpdater* >( updater ) ) { - if ( spotifyUpdater->sync() ) - found = true; + found = true; + if ( !spotifyUpdater->sync() ) + manuallyDisabled = true; + } } @@ -340,6 +365,10 @@ SpotifyAccount::aboutToShow( QAction* action, const playlist_ptr& playlist ) { action->setText( tr( "Sync with Spotify" ) ); } + else if ( manuallyDisabled ) + { + action->setText( tr( "Re-enable syncing with Spotify" ) ); + } else { action->setText( tr( "Stop syncing with Spotify" ) ); @@ -793,7 +822,8 @@ SpotifyAccount::startPlaylistSyncWithPlaylist( const QString& msgType, const QVa */ if ( m_updaters.contains( id ) ) { - Q_ASSERT( m_updaters[ id ]->sync() == false ); /// Should have been unchecked/off before + //Q_ASSERT( m_updaters[ id ]->sync() == false ); /// Should have been unchecked/off before, but might not be if the user + // changed spotify resolver meanwhile, so allow it for now m_updaters[ id ]->setSync( true ); // m_updaters[ id ]-> // TODO diff --git a/src/accounts/spotify/SpotifyAccount.h b/src/libtomahawk/accounts/spotify/SpotifyAccount.h similarity index 95% rename from src/accounts/spotify/SpotifyAccount.h rename to src/libtomahawk/accounts/spotify/SpotifyAccount.h index af05d0be6..f31d97309 100644 --- a/src/accounts/spotify/SpotifyAccount.h +++ b/src/libtomahawk/accounts/spotify/SpotifyAccount.h @@ -26,6 +26,7 @@ #include "Playlist.h" #include "utils/TomahawkUtils.h" #include "utils/SmartPointerList.h" +#include "DllMacro.h" class QAction; class SpotifyPlaylistUpdater; @@ -51,7 +52,7 @@ struct SpotifyPlaylistInfo { }; -class SpotifyAccountFactory : public AccountFactory +class DLLEXPORT SpotifyAccountFactory : public AccountFactory { Q_OBJECT public: @@ -69,7 +70,7 @@ public: }; -class SpotifyAccount : public CustomAtticaAccount +class DLLEXPORT SpotifyAccount : public CustomAtticaAccount { Q_OBJECT public: @@ -118,10 +119,11 @@ private slots: void startPlaylistSyncWithPlaylist( const QString& msgType, const QVariantMap& msg ); void playlistCreated( const QString& msgType, const QVariantMap& msg ); - void init(); + void delayedInit(); void hookupAfterDeletion( bool autoEnable ); private: + void init(); bool checkForResolver(); void hookupResolver(); @@ -158,6 +160,6 @@ private: } } -Q_DECLARE_METATYPE( Tomahawk::Accounts::SpotifyPlaylistInfo* ); +Q_DECLARE_METATYPE( Tomahawk::Accounts::SpotifyPlaylistInfo* ) #endif // SpotifyAccount_H diff --git a/src/accounts/spotify/SpotifyAccountConfig.cpp b/src/libtomahawk/accounts/spotify/SpotifyAccountConfig.cpp similarity index 100% rename from src/accounts/spotify/SpotifyAccountConfig.cpp rename to src/libtomahawk/accounts/spotify/SpotifyAccountConfig.cpp diff --git a/src/accounts/spotify/SpotifyAccountConfig.h b/src/libtomahawk/accounts/spotify/SpotifyAccountConfig.h similarity index 100% rename from src/accounts/spotify/SpotifyAccountConfig.h rename to src/libtomahawk/accounts/spotify/SpotifyAccountConfig.h diff --git a/src/accounts/spotify/SpotifyAccountConfig.ui b/src/libtomahawk/accounts/spotify/SpotifyAccountConfig.ui similarity index 100% rename from src/accounts/spotify/SpotifyAccountConfig.ui rename to src/libtomahawk/accounts/spotify/SpotifyAccountConfig.ui diff --git a/src/accounts/spotify/SpotifyPlaylistUpdater.cpp b/src/libtomahawk/accounts/spotify/SpotifyPlaylistUpdater.cpp similarity index 100% rename from src/accounts/spotify/SpotifyPlaylistUpdater.cpp rename to src/libtomahawk/accounts/spotify/SpotifyPlaylistUpdater.cpp diff --git a/src/accounts/spotify/SpotifyPlaylistUpdater.h b/src/libtomahawk/accounts/spotify/SpotifyPlaylistUpdater.h similarity index 95% rename from src/accounts/spotify/SpotifyPlaylistUpdater.h rename to src/libtomahawk/accounts/spotify/SpotifyPlaylistUpdater.h index d07fc172a..896e507d3 100644 --- a/src/accounts/spotify/SpotifyPlaylistUpdater.h +++ b/src/libtomahawk/accounts/spotify/SpotifyPlaylistUpdater.h @@ -21,6 +21,7 @@ #include "playlist/PlaylistUpdaterInterface.h" #include "utils/Closure.h" +#include "DllMacro.h" #include #include @@ -31,7 +32,7 @@ namespace Accounts { } } -class SpotifyPlaylistUpdater : public Tomahawk::PlaylistUpdaterInterface +class DLLEXPORT SpotifyPlaylistUpdater : public Tomahawk::PlaylistUpdaterInterface { Q_OBJECT @@ -106,7 +107,7 @@ private: }; -class SpotifyUpdaterFactory : public Tomahawk::PlaylistUpdaterFactory +class DLLEXPORT SpotifyUpdaterFactory : public Tomahawk::PlaylistUpdaterFactory { public: SpotifyUpdaterFactory() {} diff --git a/src/libtomahawk/audio/AudioEngine.cpp b/src/libtomahawk/audio/AudioEngine.cpp index dc882e46b..75266df98 100644 --- a/src/libtomahawk/audio/AudioEngine.cpp +++ b/src/libtomahawk/audio/AudioEngine.cpp @@ -1,6 +1,6 @@ /* === This file is part of Tomahawk Player - === * - * Copyright 2010-2011, Christian Muehlhaeuser + * Copyright 2010-2012, Christian Muehlhaeuser * Copyright 2010-2012, Jeff Mitchell * * Tomahawk is free software: you can redistribute it and/or modify @@ -36,16 +36,18 @@ #include "HeadlessCheck.h" #include "infosystem/InfoSystem.h" #include "Album.h" +#include "Pipeline.h" #include "utils/Logger.h" - using namespace Tomahawk; -AudioEngine* AudioEngine::s_instance = 0; +#define AUDIO_VOLUME_STEP 5 static QString s_aeInfoIdentifier = QString( "AUDIOENGINE" ); +AudioEngine* AudioEngine::s_instance = 0; + AudioEngine* AudioEngine::instance() @@ -79,21 +81,22 @@ AudioEngine::AudioEngine() connect( m_audioOutput, SIGNAL( volumeChanged( qreal ) ), SLOT( onVolumeChanged( qreal ) ) ); + m_stateQueueTimer.setInterval( 5000 ); + m_stateQueueTimer.setSingleShot( true ); + connect( &m_stateQueueTimer, SIGNAL( timeout() ), SLOT( queueStateSafety() ) ); + onVolumeChanged( m_audioOutput->volume() ); -#ifndef Q_WS_X11 - // On mac & win, phonon volume is independent from system volume, so the onVolumeChanged call above just sets our volume to 100%. - // Since it's indendent, we'll set it to 75% since that's nicer. - setVolume( 75 ); -#endif + setVolume( TomahawkSettings::instance()->volume() ); } AudioEngine::~AudioEngine() { tDebug() << Q_FUNC_INFO; + m_mediaObject->stop(); -// stop(); + TomahawkSettings::instance()->setVolume( volume() ); delete m_audioOutput; delete m_mediaObject; @@ -132,9 +135,7 @@ AudioEngine::play() if ( isPaused() ) { - setVolume( m_volume ); - m_mediaObject->play(); - setVolume( m_volume ); + queueState( Playing ); emit resumed(); sendNowPlayingNotification( Tomahawk::InfoSystem::InfoNowResumed ); @@ -149,8 +150,7 @@ AudioEngine::pause() { tDebug( LOGEXTRA ) << Q_FUNC_INFO; - m_volume = volume(); - m_mediaObject->pause(); + queueState( Paused ); emit paused(); Tomahawk::InfoSystem::InfoSystem::instance()->pushInfo( Tomahawk::InfoSystem::InfoPushData( s_aeInfoIdentifier, Tomahawk::InfoSystem::InfoNowPaused, QVariant(), Tomahawk::InfoSystem::PushNoFlag ) ); @@ -184,7 +184,6 @@ AudioEngine::stop( AudioErrorCode errorCode ) sendWaitingNotification(); Tomahawk::InfoSystem::InfoPushData pushData( s_aeInfoIdentifier, Tomahawk::InfoSystem::InfoNowStopped, QVariant(), Tomahawk::InfoSystem::PushNoFlag ); - Tomahawk::InfoSystem::InfoSystem::instance()->pushInfo( pushData ); } @@ -302,6 +301,20 @@ AudioEngine::setVolume( int percentage ) } +void +AudioEngine::lowerVolume() +{ + setVolume( volume() - AUDIO_VOLUME_STEP ); +} + + +void +AudioEngine::raiseVolume() +{ + setVolume( volume() + AUDIO_VOLUME_STEP ); +} + + void AudioEngine::mute() { @@ -329,13 +342,18 @@ AudioEngine::sendWaitingNotification() const void AudioEngine::sendNowPlayingNotification( const Tomahawk::InfoSystem::InfoType type ) { + if ( m_currentTrack.isNull() ) + return; + #ifndef ENABLE_HEADLESS - if ( m_currentTrack->album().isNull() || m_currentTrack->album()->infoLoaded() ) + if ( m_currentTrack->toQuery()->coverLoaded() ) + { onNowPlayingInfoReady( type ); + } else { - NewClosure( m_currentTrack->album().data(), SIGNAL( updated() ), const_cast< AudioEngine* >( this ), SLOT( onNowPlayingInfoReady( const Tomahawk::InfoSystem::InfoType ) ), type ); - m_currentTrack->album()->cover( QSize( 0, 0 ), true ); + NewClosure( m_currentTrack->toQuery().data(), SIGNAL( coverChanged() ), const_cast< AudioEngine* >( this ), SLOT( sendNowPlayingNotification( const Tomahawk::InfoSystem::InfoType ) ), type ); + m_currentTrack->toQuery()->cover( QSize( 0, 0 ), true ); } #endif } @@ -344,7 +362,6 @@ AudioEngine::sendNowPlayingNotification( const Tomahawk::InfoSystem::InfoType ty void AudioEngine::onNowPlayingInfoReady( const Tomahawk::InfoSystem::InfoType type ) { - tDebug( LOGVERBOSE ) << Q_FUNC_INFO << type; if ( m_currentTrack.isNull() || m_currentTrack->track().isNull() || m_currentTrack->artist().isNull() ) @@ -352,36 +369,35 @@ AudioEngine::onNowPlayingInfoReady( const Tomahawk::InfoSystem::InfoType type ) QVariantMap playInfo; - if ( !m_currentTrack->album().isNull() ) - { #ifndef ENABLE_HEADLESS - QImage cover; - cover = m_currentTrack->album()->cover( QSize( 0, 0 ) ).toImage(); - if ( !cover.isNull() ) - { - playInfo["cover"] = cover; + QImage cover; + cover = m_currentTrack->toQuery()->cover( QSize( 0, 0 ) ).toImage(); + if ( !cover.isNull() ) + { + playInfo["cover"] = cover; - QTemporaryFile* coverTempFile = new QTemporaryFile( QDir::toNativeSeparators( QDir::tempPath() + "/" + m_currentTrack->artist()->name() + "_" + m_currentTrack->album()->name() + "_tomahawk_cover.png" ) ); - if ( !coverTempFile->open() ) - tDebug() << Q_FUNC_INFO << "WARNING: could not write temporary file for cover art!"; - else - { - // Finally, save the image to the new temp file - coverTempFile->setAutoRemove( false ); - if ( cover.save( coverTempFile, "PNG" ) ) - { - tDebug( LOGVERBOSE ) << Q_FUNC_INFO << "Saving cover image to:" << QFileInfo( *coverTempFile ).absoluteFilePath(); - playInfo["coveruri"] = QFileInfo( *coverTempFile ).absoluteFilePath(); - } - else - tDebug() << Q_FUNC_INFO << "failed to save cover image!"; - } - delete coverTempFile; + QTemporaryFile* coverTempFile = new QTemporaryFile( QDir::toNativeSeparators( QDir::tempPath() + "/" + m_currentTrack->artist()->name() + "_" + m_currentTrack->album()->name() + "_tomahawk_cover.png" ) ); + if ( !coverTempFile->open() ) + { + tDebug() << Q_FUNC_INFO << "WARNING: could not write temporary file for cover art!"; } else - tDebug() << Q_FUNC_INFO << "Cover from album is null!"; -#endif + { + // Finally, save the image to the new temp file + coverTempFile->setAutoRemove( false ); + if ( cover.save( coverTempFile, "PNG" ) ) + { + tDebug() << Q_FUNC_INFO << "Saving cover image to:" << QFileInfo( *coverTempFile ).absoluteFilePath(); + playInfo["coveruri"] = QFileInfo( *coverTempFile ).absoluteFilePath(); + } + else + tDebug() << Q_FUNC_INFO << "failed to save cover image!"; + } + delete coverTempFile; } + else + tDebug() << Q_FUNC_INFO << "Cover from query is null!"; +#endif Tomahawk::InfoSystem::InfoStringHash trackInfo; trackInfo["title"] = m_currentTrack->track(); @@ -395,7 +411,7 @@ AudioEngine::onNowPlayingInfoReady( const Tomahawk::InfoSystem::InfoType type ) Tomahawk::InfoSystem::InfoPushData pushData ( s_aeInfoIdentifier, type, playInfo, Tomahawk::InfoSystem::PushShortUrlFlag ); - tDebug( LOGVERBOSE ) << Q_FUNC_INFO << "pushing data with type " << type; + tDebug( LOGVERBOSE ) << Q_FUNC_INFO << "pushing data with type" << type; Tomahawk::InfoSystem::InfoSystem::instance()->pushInfo( pushData ); } @@ -470,8 +486,7 @@ AudioEngine::loadTrack( const Tomahawk::result_ptr& result ) m_input.clear(); } m_input = io; - m_mediaObject->play(); - + queueState( Playing ); emit started( m_currentTrack ); if ( TomahawkSettings::instance()->privateListeningMode() != TomahawkSettings::FullyPrivate ) @@ -594,6 +609,8 @@ AudioEngine::playItem( Tomahawk::playlistinterface_ptr playlist, const Tomahawk: } else { + Pipeline::instance()->resolve( query ); + NewClosure( query.data(), SIGNAL( resolvingFinished( bool ) ), const_cast(this), SLOT( playItem( Tomahawk::playlistinterface_ptr, Tomahawk::query_ptr ) ), playlist, query ); } @@ -670,12 +687,10 @@ AudioEngine::onStateChanged( Phonon::State newState, Phonon::State oldState ) { stop( UnknownError ); - tLog() << "Phonon Error:" << m_mediaObject->errorString() << m_mediaObject->errorType(); + tDebug() << "Phonon Error:" << m_mediaObject->errorString() << m_mediaObject->errorType(); emit error( UnknownError ); setState( Error ); - - return; } if ( newState == Phonon::PlayingState ) { @@ -719,6 +734,16 @@ AudioEngine::onStateChanged( Phonon::State newState, Phonon::State oldState ) } } } + + if ( newState == Phonon::PausedState || newState == Phonon::PlayingState || newState == Phonon::ErrorState ) + { + tDebug() << "Phonon state now:" << newState; + if ( m_stateQueue.count() ) + { + AudioState qState = m_stateQueue.dequeue(); + checkStateQueue(); + } + } } @@ -783,7 +808,7 @@ AudioEngine::setStopAfterTrack( const query_ptr& query ) if ( m_stopAfterTrack != query ) { m_stopAfterTrack = query; - emit stopAfterTrack_changed(); + emit stopAfterTrackChanged(); } } @@ -791,16 +816,15 @@ AudioEngine::setStopAfterTrack( const query_ptr& query ) void AudioEngine::setCurrentTrack( const Tomahawk::result_ptr& result ) { - Tomahawk::result_ptr lastTrack = m_currentTrack; - if ( !lastTrack.isNull() ) + if ( !m_currentTrack.isNull() ) { if ( m_state != Error && TomahawkSettings::instance()->privateListeningMode() == TomahawkSettings::PublicListening ) { - DatabaseCommand_LogPlayback* cmd = new DatabaseCommand_LogPlayback( lastTrack, DatabaseCommand_LogPlayback::Finished, m_timeElapsed ); + DatabaseCommand_LogPlayback* cmd = new DatabaseCommand_LogPlayback( m_currentTrack, DatabaseCommand_LogPlayback::Finished, m_timeElapsed ); Database::instance()->enqueue( QSharedPointer(cmd) ); } - emit finished( lastTrack ); + emit finished( m_currentTrack ); } m_currentTrack = result; @@ -821,6 +845,64 @@ AudioEngine::isLocalResult( const QString& url ) const } +void +AudioEngine::checkStateQueue() +{ + if ( m_stateQueue.count() ) + { + AudioState state = m_stateQueue.head(); + tDebug() << "Applying state command:" << state; + switch ( state ) + { + case Playing: + { + bool paused = isPaused(); + m_mediaObject->play(); + if ( paused ) + setVolume( m_volume ); + + break; + } + + case Paused: + { + m_volume = volume(); + m_mediaObject->pause(); + break; + } + } + } + else + tDebug() << "Queue is empty"; +} + + +void +AudioEngine::queueStateSafety() +{ + tDebug() << Q_FUNC_INFO; + m_stateQueue.clear(); +} + + +void +AudioEngine::queueState( AudioState state ) +{ + if ( m_stateQueueTimer.isActive() ) + m_stateQueueTimer.stop(); + + tDebug() << "Enqueuing state command:" << state << m_stateQueue.count(); + m_stateQueue.enqueue( state ); + + if ( m_stateQueue.count() == 1 ) + { + checkStateQueue(); + } + + m_stateQueueTimer.start(); +} + + void AudioEngine::setState( AudioState state ) { diff --git a/src/libtomahawk/audio/AudioEngine.h b/src/libtomahawk/audio/AudioEngine.h index ce14a397d..d8a56aed8 100644 --- a/src/libtomahawk/audio/AudioEngine.h +++ b/src/libtomahawk/audio/AudioEngine.h @@ -1,6 +1,6 @@ /* === This file is part of Tomahawk Player - === * - * Copyright 2010-2011, Christian Muehlhaeuser + * Copyright 2010-2012, Christian Muehlhaeuser * Copyright 2010-2012, Jeff Mitchell * * Tomahawk is free software: you can redistribute it and/or modify @@ -22,6 +22,7 @@ #include #include +#include #include #include @@ -29,15 +30,12 @@ #include "libtomahawk/infosystem/InfoSystem.h" -#include "Result.h" #include "Typedefs.h" +#include "Result.h" #include "PlaylistInterface.h" #include "DllMacro.h" -#define AUDIO_VOLUME_STEP 5 - - class DLLEXPORT AudioEngine : public QObject { Q_OBJECT @@ -88,8 +86,8 @@ public slots: void seek( qint64 ms ); void seek( int ms ); // for compatibility with seekbar in audiocontrols void setVolume( int percentage ); - void lowerVolume() { setVolume( volume() - AUDIO_VOLUME_STEP ); } - void raiseVolume() { setVolume( volume() + AUDIO_VOLUME_STEP ); } + void lowerVolume(); + void raiseVolume(); void mute(); void playItem( Tomahawk::playlistinterface_ptr playlist, const Tomahawk::result_ptr& result ); @@ -109,7 +107,7 @@ signals: void paused(); void resumed(); - void stopAfterTrack_changed(); + void stopAfterTrackChanged(); void seeked( qint64 ms ); @@ -138,16 +136,20 @@ private slots: void onNowPlayingInfoReady( const Tomahawk::InfoSystem::InfoType type ); void onPlaylistNextTrackReady(); + void sendNowPlayingNotification( const Tomahawk::InfoSystem::InfoType type ); void sendWaitingNotification() const; + + void queueStateSafety(); private: + void checkStateQueue(); + void queueState( AudioState state ); + void setState( AudioState state ); bool isHttpResult( const QString& ) const; bool isLocalResult( const QString& ) const; - void sendNowPlayingNotification( const Tomahawk::InfoSystem::InfoType type ); - QSharedPointer m_input; Tomahawk::query_ptr m_stopAfterTrack; @@ -164,9 +166,12 @@ private: bool m_waitingOnNewTrack; mutable QStringList m_supportedMimeTypes; - AudioState m_state; unsigned int m_volume; + AudioState m_state; + QQueue< AudioState > m_stateQueue; + QTimer m_stateQueueTimer; + static AudioEngine* s_instance; }; diff --git a/src/libtomahawk/context/ContextWidget.cpp b/src/libtomahawk/context/ContextWidget.cpp index ce6b69a05..bbf0e8334 100644 --- a/src/libtomahawk/context/ContextWidget.cpp +++ b/src/libtomahawk/context/ContextWidget.cpp @@ -29,8 +29,6 @@ #include "context/pages/TopTracksContext.h" #include "context/pages/WikipediaContext.h" -#include "playlist/ArtistView.h" -#include "playlist/TreeModel.h" #include "Source.h" #include "utils/StyleHelper.h" diff --git a/src/libtomahawk/context/pages/RelatedArtistsContext.cpp b/src/libtomahawk/context/pages/RelatedArtistsContext.cpp index 23f54d2f4..f3a7edd4a 100644 --- a/src/libtomahawk/context/pages/RelatedArtistsContext.cpp +++ b/src/libtomahawk/context/pages/RelatedArtistsContext.cpp @@ -21,7 +21,7 @@ #include -#include "playlist/ArtistView.h" +#include "playlist/TreeView.h" #include "playlist/TreeModel.h" #include "Source.h" @@ -30,13 +30,12 @@ using namespace Tomahawk; RelatedArtistsContext::RelatedArtistsContext() : ContextPage() - , m_infoId( uuid() ) { - m_relatedView = new ArtistView(); + m_relatedView = new TreeView(); m_relatedView->setGuid( "RelatedArtistsContext" ); m_relatedView->setUpdatesContextView( false ); m_relatedModel = new TreeModel( m_relatedView ); - m_relatedModel->setColumnStyle( TreeModel::TrackOnly ); + m_relatedModel->setStyle( TreeModel::Large ); m_relatedView->setTreeModel( m_relatedModel ); m_relatedView->setVerticalScrollBarPolicy( Qt::ScrollBarAlwaysOff ); m_relatedView->setSortingEnabled( false ); @@ -48,12 +47,6 @@ RelatedArtistsContext::RelatedArtistsContext() m_proxy = new QGraphicsProxyWidget(); m_proxy->setWidget( m_relatedView ); - - connect( Tomahawk::InfoSystem::InfoSystem::instance(), - SIGNAL( info( Tomahawk::InfoSystem::InfoRequestData, QVariant ) ), - SLOT( infoSystemInfo( Tomahawk::InfoSystem::InfoRequestData, QVariant ) ) ); - - connect( Tomahawk::InfoSystem::InfoSystem::instance(), SIGNAL( finished( QString ) ), SLOT( infoSystemFinished( QString ) ) ); } @@ -70,18 +63,17 @@ RelatedArtistsContext::setArtist( const Tomahawk::artist_ptr& artist ) if ( !m_artist.isNull() && m_artist->name() == artist->name() ) return; + if ( !m_artist.isNull() ) + { + disconnect( m_artist.data(), SIGNAL( similarArtistsLoaded() ), this, SLOT( onSimilarArtistsLoaded() ) ); + } + m_artist = artist; - Tomahawk::InfoSystem::InfoStringHash artistInfo; - artistInfo["artist"] = artist->name(); + connect( m_artist.data(), SIGNAL( similarArtistsLoaded() ), SLOT( onSimilarArtistsLoaded() ) ); - Tomahawk::InfoSystem::InfoRequestData requestData; - requestData.caller = m_infoId; - requestData.customData = QVariantMap(); - requestData.input = QVariant::fromValue< Tomahawk::InfoSystem::InfoStringHash >( artistInfo ); - - requestData.type = Tomahawk::InfoSystem::InfoArtistSimilars; - Tomahawk::InfoSystem::InfoSystem::instance()->getInfo( requestData ); + m_relatedModel->clear(); + onSimilarArtistsLoaded(); } @@ -106,45 +98,10 @@ RelatedArtistsContext::setAlbum( const Tomahawk::album_ptr& album ) void -RelatedArtistsContext::infoSystemInfo( Tomahawk::InfoSystem::InfoRequestData requestData, QVariant output ) +RelatedArtistsContext::onSimilarArtistsLoaded() { - if ( requestData.caller != m_infoId ) - return; - - InfoSystem::InfoStringHash trackInfo; - trackInfo = requestData.input.value< InfoSystem::InfoStringHash >(); - - if ( output.canConvert< QVariantMap >() ) + foreach ( const artist_ptr& artist, m_artist->similarArtists() ) { - if ( trackInfo["artist"] != m_artist->name() ) - { - qDebug() << "Returned info was for:" << trackInfo["artist"] << "- was looking for:" << m_artist->name(); - return; - } - } - - QVariantMap returnedData = output.value< QVariantMap >(); - switch ( requestData.type ) - { - case InfoSystem::InfoArtistSimilars: - { - m_relatedModel->clear(); - const QStringList artists = returnedData["artists"].toStringList(); - foreach ( const QString& artist, artists ) - { - m_relatedModel->addArtists( Artist::get( artist ) ); - } - break; - } - - default: - return; + m_relatedModel->addArtists( artist ); } } - - -void -RelatedArtistsContext::infoSystemFinished( QString target ) -{ - Q_UNUSED( target ); -} diff --git a/src/libtomahawk/context/pages/RelatedArtistsContext.h b/src/libtomahawk/context/pages/RelatedArtistsContext.h index 53d3c9a5e..3e45cebce 100644 --- a/src/libtomahawk/context/pages/RelatedArtistsContext.h +++ b/src/libtomahawk/context/pages/RelatedArtistsContext.h @@ -28,10 +28,9 @@ #include "Album.h" #include "Query.h" #include "context/ContextPage.h" -#include "infosystem/InfoSystem.h" class TreeModel; -class ArtistView; +class TreeView; class DLLEXPORT RelatedArtistsContext : public Tomahawk::ContextPage { @@ -56,16 +55,14 @@ public slots: virtual void setQuery( const Tomahawk::query_ptr& query ); private slots: - void infoSystemInfo( Tomahawk::InfoSystem::InfoRequestData requestData, QVariant output ); - void infoSystemFinished( QString target ); + void onSimilarArtistsLoaded(); private: - ArtistView* m_relatedView; + TreeView* m_relatedView; TreeModel* m_relatedModel; QGraphicsProxyWidget* m_proxy; - QString m_infoId; Tomahawk::artist_ptr m_artist; }; diff --git a/src/libtomahawk/context/pages/TopTracksContext.cpp b/src/libtomahawk/context/pages/TopTracksContext.cpp index 585146360..a8df51fe3 100644 --- a/src/libtomahawk/context/pages/TopTracksContext.cpp +++ b/src/libtomahawk/context/pages/TopTracksContext.cpp @@ -21,7 +21,6 @@ #include "playlist/PlaylistModel.h" #include "playlist/PlaylistView.h" -#include "playlist/TrackHeader.h" #include "Source.h" using namespace Tomahawk; @@ -29,7 +28,6 @@ using namespace Tomahawk; TopTracksContext::TopTracksContext() : ContextPage() - , m_infoId( uuid() ) { m_topHitsView = new PlaylistView(); m_topHitsView->setGuid( "TopTracksContext" ); @@ -45,12 +43,6 @@ TopTracksContext::TopTracksContext() m_proxy = new QGraphicsProxyWidget(); m_proxy->setWidget( m_topHitsView ); - - connect( Tomahawk::InfoSystem::InfoSystem::instance(), - SIGNAL( info( Tomahawk::InfoSystem::InfoRequestData, QVariant ) ), - SLOT( infoSystemInfo( Tomahawk::InfoSystem::InfoRequestData, QVariant ) ) ); - - connect( Tomahawk::InfoSystem::InfoSystem::instance(), SIGNAL( finished( QString ) ), SLOT( infoSystemFinished( QString ) ) ); } @@ -67,18 +59,19 @@ TopTracksContext::setArtist( const Tomahawk::artist_ptr& artist ) if ( !m_artist.isNull() && m_artist->name() == artist->name() ) return; + if ( !m_artist.isNull() ) + { + disconnect( m_artist.data(), SIGNAL( tracksAdded( QList, Tomahawk::ModelMode, Tomahawk::collection_ptr ) ), + this, SLOT( onTracksFound( QList, Tomahawk::ModelMode ) ) ); + } + m_artist = artist; - Tomahawk::InfoSystem::InfoStringHash artistInfo; - artistInfo["artist"] = artist->name(); + connect( m_artist.data(), SIGNAL( tracksAdded( QList, Tomahawk::ModelMode, Tomahawk::collection_ptr ) ), + SLOT( onTracksFound( QList, Tomahawk::ModelMode ) ) ); - Tomahawk::InfoSystem::InfoRequestData requestData; - requestData.caller = m_infoId; - requestData.customData = QVariantMap(); - requestData.input = QVariant::fromValue< Tomahawk::InfoSystem::InfoStringHash >( artistInfo ); - - requestData.type = Tomahawk::InfoSystem::InfoArtistSongs; - Tomahawk::InfoSystem::InfoSystem::instance()->getInfo( requestData ); + m_topHitsModel->clear(); + onTracksFound( m_artist->tracks(), Mixed ); } @@ -103,51 +96,11 @@ TopTracksContext::setQuery( const Tomahawk::query_ptr& query ) void -TopTracksContext::infoSystemInfo( Tomahawk::InfoSystem::InfoRequestData requestData, QVariant output ) +TopTracksContext::onTracksFound( const QList& queries, ModelMode mode ) { - if ( requestData.caller != m_infoId ) - return; + Q_UNUSED( mode ); - InfoSystem::InfoStringHash trackInfo; - trackInfo = requestData.input.value< InfoSystem::InfoStringHash >(); - - if ( output.canConvert< QVariantMap >() ) - { - if ( trackInfo["artist"] != m_artist->name() ) - { - qDebug() << "Returned info was for:" << trackInfo["artist"] << "- was looking for:" << m_artist->name(); - return; - } - } - - QVariantMap returnedData = output.value< QVariantMap >(); - switch ( requestData.type ) - { - case InfoSystem::InfoArtistSongs: - { - m_topHitsModel->clear(); - const QStringList tracks = returnedData["tracks"].toStringList(); - - int i = 0; - foreach ( const QString& track, tracks ) - { - query_ptr query = Query::get( m_artist->name(), track, QString(), uuid() ); - m_topHitsModel->append( query ); - - if ( ++i == 15 ) - break; - } - break; - } - - default: - return; - } + m_topHitsModel->append( queries ); } -void -TopTracksContext::infoSystemFinished( QString target ) -{ - Q_UNUSED( target ); -} diff --git a/src/libtomahawk/context/pages/TopTracksContext.h b/src/libtomahawk/context/pages/TopTracksContext.h index 662f00c02..bc8219b62 100644 --- a/src/libtomahawk/context/pages/TopTracksContext.h +++ b/src/libtomahawk/context/pages/TopTracksContext.h @@ -28,7 +28,6 @@ #include "Album.h" #include "Query.h" #include "context/ContextPage.h" -#include "infosystem/InfoSystem.h" class PlaylistModel; class PlaylistView; @@ -56,8 +55,7 @@ public slots: virtual void setQuery( const Tomahawk::query_ptr& query ); private slots: - void infoSystemInfo( Tomahawk::InfoSystem::InfoRequestData requestData, QVariant output ); - void infoSystemFinished( QString target ); + void onTracksFound( const QList& queries, Tomahawk::ModelMode mode ); private: PlaylistView* m_topHitsView; @@ -65,7 +63,6 @@ private: QGraphicsProxyWidget* m_proxy; - QString m_infoId; Tomahawk::artist_ptr m_artist; }; diff --git a/src/libtomahawk/database/Database.cpp b/src/libtomahawk/database/Database.cpp index 8ed84597f..eea51aca0 100644 --- a/src/libtomahawk/database/Database.cpp +++ b/src/libtomahawk/database/Database.cpp @@ -42,12 +42,16 @@ Database::Database( const QString& dbname, QObject* parent ) : QObject( parent ) , m_ready( false ) , m_impl( new DatabaseImpl( dbname, this ) ) - , m_workerRW( new DatabaseWorker( m_impl, this, true ) ) + , m_workerRW( new DatabaseWorker( this, true ) ) { s_instance = this; - m_maxConcurrentThreads = qBound( DEFAULT_WORKER_THREADS, QThread::idealThreadCount(), MAX_WORKER_THREADS ); - qDebug() << Q_FUNC_INFO << "Using" << m_maxConcurrentThreads << "threads"; + if ( MAX_WORKER_THREADS < DEFAULT_WORKER_THREADS ) + m_maxConcurrentThreads = MAX_WORKER_THREADS; + else + m_maxConcurrentThreads = qBound( DEFAULT_WORKER_THREADS, QThread::idealThreadCount(), MAX_WORKER_THREADS ); + + tDebug() << Q_FUNC_INFO << "Using" << m_maxConcurrentThreads << "database worker threads"; connect( m_impl, SIGNAL( indexReady() ), SIGNAL( indexReady() ) ); connect( m_impl, SIGNAL( indexReady() ), SIGNAL( ready() ) ); @@ -96,7 +100,7 @@ Database::enqueue( const QSharedPointer& lc ) // create new thread if < WORKER_THREADS if ( m_workers.count() < m_maxConcurrentThreads ) { - DatabaseWorker* worker = new DatabaseWorker( m_impl, this, false ); + DatabaseWorker* worker = new DatabaseWorker( this, false ); worker->start(); m_workers << worker; diff --git a/src/libtomahawk/database/Database.h b/src/libtomahawk/database/Database.h index b265bd39c..7bf05a09e 100644 --- a/src/libtomahawk/database/Database.h +++ b/src/libtomahawk/database/Database.h @@ -53,12 +53,13 @@ public: ~Database(); QString dbid() const; - bool indexReady() const { return m_indexReady; } void loadIndex(); - + bool indexReady() const { return m_indexReady; } bool isReady() const { return m_ready; } + DatabaseImpl* impl() const { return m_impl; } + signals: void indexReady(); // search index void ready(); @@ -74,8 +75,6 @@ private slots: void setIsReadyTrue() { m_ready = true; } private: - DatabaseImpl* impl() const { return m_impl; } - bool m_ready; DatabaseImpl* m_impl; DatabaseWorker* m_workerRW; diff --git a/src/libtomahawk/database/DatabaseCommand_AllAlbums.cpp b/src/libtomahawk/database/DatabaseCommand_AllAlbums.cpp index 5f7e8a396..cfc7c9165 100644 --- a/src/libtomahawk/database/DatabaseCommand_AllAlbums.cpp +++ b/src/libtomahawk/database/DatabaseCommand_AllAlbums.cpp @@ -73,11 +73,11 @@ DatabaseCommand_AllAlbums::execForArtist( DatabaseImpl* dbi ) QStringList sl = m_filter.split( " ", QString::SkipEmptyParts ); foreach( QString s, sl ) { - filtersql += QString( " AND ( artist.name LIKE '%%1%' OR album.name LIKE '%%1%' OR track.name LIKE '%%1%' )" ).arg( TomahawkUtils::sqlEscape( s ) ); + filtersql += QString( " AND ( artist.name LIKE '%%1%' OR album.name LIKE '%%1%' OR track.name LIKE '%%1%' )" ).arg( TomahawkSqlQuery::escape( s ) ); } filterToken = QString( "AND artist.id = file_join.artist AND file_join.track = track.id %1" ).arg( filtersql ); - tables = "artist, track, file, file_join"; + tables = "file, file_join, artist, track"; } else tables = "file, file_join"; @@ -139,7 +139,7 @@ DatabaseCommand_AllAlbums::execForCollection( DatabaseImpl* dbi ) QString sql = QString( "SELECT DISTINCT album.id, album.name, album.artist, artist.name " - "FROM album, file, file_join " + "FROM file_join, file, album " "LEFT OUTER JOIN artist ON album.artist = artist.id " "WHERE file.id = file_join.file " "AND file_join.album = album.id " diff --git a/src/libtomahawk/database/DatabaseCommand_AllArtists.cpp b/src/libtomahawk/database/DatabaseCommand_AllArtists.cpp index c9479a345..5d030d1ac 100644 --- a/src/libtomahawk/database/DatabaseCommand_AllArtists.cpp +++ b/src/libtomahawk/database/DatabaseCommand_AllArtists.cpp @@ -63,7 +63,7 @@ DatabaseCommand_AllArtists::exec( DatabaseImpl* dbi ) QStringList sl = m_filter.split( " ", QString::SkipEmptyParts ); foreach( QString s, sl ) { - filtersql += QString( " AND ( artist.name LIKE '%%1%' OR album.name LIKE '%%1%' OR track.name LIKE '%%1%' )" ).arg( TomahawkUtils::sqlEscape( s ) ); + filtersql += QString( " AND ( artist.name LIKE '%%1%' OR album.name LIKE '%%1%' OR track.name LIKE '%%1%' )" ).arg( TomahawkSqlQuery::escape( s ) ); } filterToken = QString( "AND file_join.track = track.id %1" ).arg( filtersql ); diff --git a/src/libtomahawk/database/DatabaseCommand_DeleteFiles.cpp b/src/libtomahawk/database/DatabaseCommand_DeleteFiles.cpp index 0fd08a9bd..38e968bbc 100644 --- a/src/libtomahawk/database/DatabaseCommand_DeleteFiles.cpp +++ b/src/libtomahawk/database/DatabaseCommand_DeleteFiles.cpp @@ -81,7 +81,7 @@ DatabaseCommand_DeleteFiles::exec( DatabaseImpl* dbi ) tDebug() << "Deleting" << m_dir.path() << "from db for localsource" << srcid; TomahawkSqlQuery dirquery = dbi->newquery(); QString path( "file://" + m_dir.canonicalPath() + "/%" ); - dirquery.prepare( QString( "SELECT id FROM file WHERE source IS NULL AND url LIKE '%1'" ).arg( TomahawkUtils::sqlEscape( path ) ) ); + dirquery.prepare( QString( "SELECT id FROM file WHERE source IS NULL AND url LIKE '%1'" ).arg( TomahawkSqlQuery::escape( path ) ) ); dirquery.exec(); while ( dirquery.next() ) diff --git a/src/libtomahawk/database/DatabaseCommand_LogPlayback.cpp b/src/libtomahawk/database/DatabaseCommand_LogPlayback.cpp index 81ee8fbd6..37e089940 100644 --- a/src/libtomahawk/database/DatabaseCommand_LogPlayback.cpp +++ b/src/libtomahawk/database/DatabaseCommand_LogPlayback.cpp @@ -37,31 +37,33 @@ using namespace Tomahawk; void DatabaseCommand_LogPlayback::postCommitHook() { + if ( !m_query.isNull() ) + return; + connect( this, SIGNAL( trackPlaying( Tomahawk::query_ptr, unsigned int ) ), source().data(), SLOT( onPlaybackStarted( Tomahawk::query_ptr, unsigned int ) ), Qt::QueuedConnection ); connect( this, SIGNAL( trackPlayed( Tomahawk::query_ptr ) ), source().data(), SLOT( onPlaybackFinished( Tomahawk::query_ptr ) ), Qt::QueuedConnection ); - Tomahawk::query_ptr q; - if ( !m_result.isNull() ) + if ( !m_result.isNull() && m_query.isNull() ) { - q = m_result->toQuery(); + m_query = m_result->toQuery(); } else { // do not auto resolve this track - q = Tomahawk::Query::get( m_artist, m_track, QString() ); + m_query = Tomahawk::Query::get( m_artist, m_track, QString() ); } - q->setPlayedBy( source(), m_playtime ); + m_query->setPlayedBy( source(), m_playtime ); if ( m_action == Finished ) { - emit trackPlayed( q ); + emit trackPlayed( m_query ); } // if the play time is more than 10 minutes in the past, ignore else if ( m_action == Started && QDateTime::fromTime_t( playtime() ).secsTo( QDateTime::currentDateTime() ) < STARTED_THRESHOLD ) { - emit trackPlaying( q, m_trackDuration ); + emit trackPlaying( m_query, m_trackDuration ); } if ( source()->isLocal() ) @@ -78,25 +80,36 @@ DatabaseCommand_LogPlayback::exec( DatabaseImpl* dbi ) if ( m_action != Finished ) return; - if ( m_secsPlayed < FINISHED_THRESHOLD ) + if ( m_secsPlayed < FINISHED_THRESHOLD && m_trackDuration > 0 ) + return; + if ( m_artist.isEmpty() || m_track.isEmpty() ) return; - TomahawkSqlQuery query = dbi->newquery(); - query.prepare( "INSERT INTO playback_log(source, track, playtime, secs_played) " - "VALUES (?, ?, ?, ?)" ); - QVariant srcid = source()->isLocal() ? QVariant( QVariant::Int ) : source()->id(); - qDebug() << "Logging playback of" << m_artist << "-" << m_track << "for source" << srcid; + TomahawkSqlQuery query = dbi->newquery(); + + if ( !m_query.isNull() ) + { + query.prepare( QString( "SELECT * FROM playback_log WHERE source %1 AND playtime = %2" ).arg( srcid.isNull() ? "IS NULL" : srcid.toString() ).arg( m_playtime ) ); + query.exec(); + if ( query.next() ) + { + tDebug() << "Ignoring dupe playback log for source" << srcid << "with timestamp" << m_playtime; + return; + } + } + +// tDebug() << "Logging playback of" << m_artist << "-" << m_track << "for source" << srcid << "- timestamp:" << m_playtime; + + query.prepare( "INSERT INTO playback_log(source, track, playtime, secs_played) VALUES (?, ?, ?, ?)" ); query.bindValue( 0, srcid ); - // If there's no artist, becuase it's a resolver result with bad metadata for example, don't save it - bool autoCreate = m_artist.isEmpty(); - int artid = dbi->artistId( m_artist, autoCreate ); + // If there's no artist, because it's a resolver result with bad metadata for example, don't save it + int artid = dbi->artistId( m_artist, true ); if( artid < 1 ) return; - autoCreate = true; // artistId overwrites autoCreate (reference) - int trkid = dbi->trackId( artid, m_track, autoCreate ); + int trkid = dbi->trackId( artid, m_track, true ); if( trkid < 1 ) return; diff --git a/src/libtomahawk/database/DatabaseCommand_LogPlayback.h b/src/libtomahawk/database/DatabaseCommand_LogPlayback.h index 384a07579..14912ca55 100644 --- a/src/libtomahawk/database/DatabaseCommand_LogPlayback.h +++ b/src/libtomahawk/database/DatabaseCommand_LogPlayback.h @@ -51,6 +51,17 @@ public: : DatabaseCommandLoggable( parent ), m_playtime( 0 ), m_secsPlayed( 0 ), m_trackDuration( 0 ) {} + explicit DatabaseCommand_LogPlayback( const Tomahawk::query_ptr& query, Action action, uint timeStamp, QObject* parent = 0 ) + : DatabaseCommandLoggable( parent ), m_query( query ), m_secsPlayed( 0 ), m_action( action ) + { + m_playtime = timeStamp; + m_trackDuration = 0; + setSource( SourceList::instance()->getLocal() ); + + setArtist( query->artist() ); + setTrack( query->track() ); + } + explicit DatabaseCommand_LogPlayback( const Tomahawk::result_ptr& result, Action action, unsigned int secsPlayed = 0, QObject* parent = 0 ) : DatabaseCommandLoggable( parent ), m_result( result ), m_secsPlayed( secsPlayed ), m_action( action ) { @@ -96,6 +107,7 @@ signals: private: Tomahawk::result_ptr m_result; + Tomahawk::query_ptr m_query; QString m_artist; QString m_track; diff --git a/src/libtomahawk/database/DatabaseCommand_PlaybackHistory.cpp b/src/libtomahawk/database/DatabaseCommand_PlaybackHistory.cpp index 1aa3e37c8..a2093dd25 100644 --- a/src/libtomahawk/database/DatabaseCommand_PlaybackHistory.cpp +++ b/src/libtomahawk/database/DatabaseCommand_PlaybackHistory.cpp @@ -80,6 +80,5 @@ DatabaseCommand_PlaybackHistory::exec( DatabaseImpl* dbi ) } } - if ( ql.count() ) - emit tracks( ql ); + emit tracks( ql ); } diff --git a/src/libtomahawk/database/DatabaseCommand_SetPlaylistRevision.cpp b/src/libtomahawk/database/DatabaseCommand_SetPlaylistRevision.cpp index f166d0fa0..00c8cf6bb 100644 --- a/src/libtomahawk/database/DatabaseCommand_SetPlaylistRevision.cpp +++ b/src/libtomahawk/database/DatabaseCommand_SetPlaylistRevision.cpp @@ -167,7 +167,6 @@ DatabaseCommand_SetPlaylistRevision::exec( DatabaseImpl* lib ) foreach( const plentry_ptr& e, m_entries ) { - adde.bindValue( 0, e->query()->track() ); adde.bindValue( 1, e->query()->artist() ); adde.bindValue( 2, e->query()->album() ); diff --git a/src/libtomahawk/database/DatabaseCommand_TrackAttributes.cpp b/src/libtomahawk/database/DatabaseCommand_TrackAttributes.cpp index b41e55fe4..48a313148 100644 --- a/src/libtomahawk/database/DatabaseCommand_TrackAttributes.cpp +++ b/src/libtomahawk/database/DatabaseCommand_TrackAttributes.cpp @@ -49,7 +49,6 @@ void DatabaseCommand_TrackAttributes::exec( DatabaseImpl* lib ) PairList results; if ( !m_ids.isEmpty() ) { - foreach ( const QID id, m_ids ) { query.prepare( "SELECT v FROM track_attributes WHERE id = ? AND k = ?" ); @@ -58,11 +57,13 @@ void DatabaseCommand_TrackAttributes::exec( DatabaseImpl* lib ) if ( query.exec() ) results.append( QPair< QID, QString >( id, query.value( 0 ).toString() ) ); } - } else { + } + else + { query.prepare( "SELECT id, v FROM track_attributes WHERE k = ?" ); query.bindValue( 0, k ); query.exec(); - while ( !query.next() ) + while ( query.next() ) { results.append( QPair< QID, QString >( query.value( 0 ).toString(), query.value( 1 ).toString() ) ); } diff --git a/src/libtomahawk/database/DatabaseCommand_TrackStats.cpp b/src/libtomahawk/database/DatabaseCommand_TrackStats.cpp index a85397dee..b918a4852 100644 --- a/src/libtomahawk/database/DatabaseCommand_TrackStats.cpp +++ b/src/libtomahawk/database/DatabaseCommand_TrackStats.cpp @@ -56,7 +56,7 @@ DatabaseCommand_TrackStats::exec( DatabaseImpl* dbi ) query.prepare( "SELECT * " "FROM playback_log " - "WHERE track = ?" ); + "WHERE track = ? ORDER BY playtime ASC" ); query.addBindValue( trkid ); query.exec(); } diff --git a/src/libtomahawk/database/DatabaseCommand_UpdateSearchIndex.cpp b/src/libtomahawk/database/DatabaseCommand_UpdateSearchIndex.cpp index e0bc3558a..5130d7c04 100644 --- a/src/libtomahawk/database/DatabaseCommand_UpdateSearchIndex.cpp +++ b/src/libtomahawk/database/DatabaseCommand_UpdateSearchIndex.cpp @@ -19,16 +19,20 @@ #include "DatabaseCommand_UpdateSearchIndex.h" -#include "DatabaseImpl.h" -#include "TomahawkSqlQuery.h" -#include "utils/Logger.h" -#include "jobview/IndexingJobItem.h" -#include "jobview/JobStatusView.h" -#include "jobview/JobStatusModel.h" -#include "Source.h" - #include +#include "DatabaseImpl.h" +#include "Source.h" +#include "TomahawkSqlQuery.h" +#include "jobview/IndexingJobItem.h" + +#ifndef ENABLE_HEADLESS + #include "jobview/JobStatusView.h" + #include "jobview/JobStatusModel.h" +#endif + +#include "utils/Logger.h" + DatabaseCommand_UpdateSearchIndex::DatabaseCommand_UpdateSearchIndex() : DatabaseCommand() @@ -36,14 +40,18 @@ DatabaseCommand_UpdateSearchIndex::DatabaseCommand_UpdateSearchIndex() { tLog() << Q_FUNC_INFO << "Updating index."; +#ifndef ENABLE_HEADLESS JobStatusView::instance()->model()->addJob( m_statusJob.data() ); +#endif } DatabaseCommand_UpdateSearchIndex::~DatabaseCommand_UpdateSearchIndex() { - if (! m_statusJob.isNull() ) +#ifndef ENABLE_HEADLESS + if ( ! m_statusJob.isNull() ) m_statusJob.data()->done(); +#endif } diff --git a/src/libtomahawk/database/DatabaseImpl.cpp b/src/libtomahawk/database/DatabaseImpl.cpp index d51ecea8a..4648a988a 100644 --- a/src/libtomahawk/database/DatabaseImpl.cpp +++ b/src/libtomahawk/database/DatabaseImpl.cpp @@ -27,7 +27,6 @@ #include #include "database/Database.h" -#include "DatabaseCommand_UpdateSearchIndex.h" #include "SourceList.h" #include "Result.h" #include "Artist.h" @@ -46,9 +45,7 @@ DatabaseImpl::DatabaseImpl( const QString& dbname, Database* parent ) : QObject( (QObject*) parent ) - , m_lastartid( 0 ) - , m_lastalbid( 0 ) - , m_lasttrkid( 0 ) + , m_parent( parent ) { QTime t; t.start(); @@ -67,24 +64,18 @@ DatabaseImpl::DatabaseImpl( const QString& dbname, Database* parent ) m_dbid = uuid(); query.exec( QString( "INSERT INTO settings(k,v) VALUES('dbid','%1')" ).arg( m_dbid ) ); } - tLog() << "Database ID:" << m_dbid; - // make sqlite behave how we want: - query.exec( "PRAGMA auto_vacuum = FULL" ); - query.exec( "PRAGMA synchronous = ON" ); - query.exec( "PRAGMA foreign_keys = ON" ); - //query.exec( "PRAGMA temp_store = MEMORY" ); + tLog() << "Database ID:" << m_dbid; + init(); + tDebug( LOGVERBOSE ) << "Tweaked db pragmas:" << t.elapsed(); // in case of unclean shutdown last time: query.exec( "UPDATE source SET isonline = 'false'" ); - m_fuzzyIndex = new FuzzyIndex( *this, schemaUpdated ); - if ( schemaUpdated ) - QTimer::singleShot( 0, this, SLOT( updateIndex() ) ); + m_fuzzyIndex = new FuzzyIndex( this, schemaUpdated ); tDebug( LOGVERBOSE ) << "Loaded index:" << t.elapsed(); - if ( qApp->arguments().contains( "--dumpdb" ) ) { dumpDatabase(); @@ -93,9 +84,59 @@ DatabaseImpl::DatabaseImpl( const QString& dbname, Database* parent ) } +DatabaseImpl::DatabaseImpl( Database* parent, const QString& dbname ) + : QObject( (QObject*) QThread::currentThread() ) + , m_parent( parent ) +{ + openDatabase( dbname, false ); + init(); +} + + +void +DatabaseImpl::init() +{ + m_lastartid = m_lastalbid = m_lasttrkid = 0; + + TomahawkSqlQuery query = newquery(); + + // make sqlite behave how we want: + query.exec( "PRAGMA auto_vacuum = FULL" ); + query.exec( "PRAGMA synchronous = ON" ); + query.exec( "PRAGMA foreign_keys = ON" ); + //query.exec( "PRAGMA temp_store = MEMORY" ); +} + + DatabaseImpl::~DatabaseImpl() { - delete m_fuzzyIndex; + tDebug() << "Shutting down database connection."; + +/* +#ifdef TOMAHAWK_QUERY_ANALYZE + TomahawkSqlQuery q = newquery(); + + q.exec( "ANALYZE" ); + q.exec( "SELECT * FROM sqlite_stat1" ); + while ( q.next() ) + { + tLog( LOGSQL ) << q.value( 0 ).toString() << q.value( 1 ).toString() << q.value( 2 ).toString(); + } + +#endif +*/ +} + + +DatabaseImpl* +DatabaseImpl::clone() const +{ + QMutexLocker lock( &m_mutex ); + + DatabaseImpl* impl = new DatabaseImpl( m_parent, m_db.databaseName() ); + impl->setDatabaseID( m_dbid ); + impl->setFuzzyIndex( m_fuzzyIndex ); + return impl; } @@ -665,34 +706,43 @@ DatabaseImpl::resultFromHint( const Tomahawk::query_ptr& origquery ) bool -DatabaseImpl::openDatabase( const QString& dbname ) +DatabaseImpl::openDatabase( const QString& dbname, bool checkSchema ) { + const QStringList conns = QSqlDatabase::connectionNames(); + const QString connName = QString( "tomahawk%1" ).arg( conns.count() ? QString::number( conns.count() ) : "" ); + bool schemaUpdated = false; int version = -1; { - QSqlDatabase db = QSqlDatabase::addDatabase( "QSQLITE", "tomahawk" ); + QSqlDatabase db = QSqlDatabase::addDatabase( "QSQLITE", connName ); db.setDatabaseName( dbname ); + db.setConnectOptions( "QSQLITE_ENABLE_SHARED_CACHE=1" ); if ( !db.open() ) { tLog() << "Failed to open database" << dbname; throw "failed to open db"; // TODO } - - QSqlQuery qry = QSqlQuery( db ); - qry.exec( "SELECT v FROM settings WHERE k='schema_version'" ); - if ( qry.next() ) + + if ( checkSchema ) { - version = qry.value( 0 ).toInt(); - tLog() << "Database schema of" << dbname << "is" << version; + QSqlQuery qry = QSqlQuery( db ); + qry.exec( "SELECT v FROM settings WHERE k='schema_version'" ); + if ( qry.next() ) + { + version = qry.value( 0 ).toInt(); + tLog() << "Database schema of" << dbname << "is" << version; + } } - + else + version = CURRENT_SCHEMA_VERSION; + if ( version < 0 || version == CURRENT_SCHEMA_VERSION ) m_db = db; } if ( version > 0 && version != CURRENT_SCHEMA_VERSION ) { - QSqlDatabase::removeDatabase( "tomahawk" ); + QSqlDatabase::removeDatabase( connName ); QString newname = QString( "%1.v%2" ).arg( dbname ).arg( version ); tLog() << endl << "****************************" << endl; @@ -703,7 +753,7 @@ DatabaseImpl::openDatabase( const QString& dbname ) QFile::copy( dbname, newname ); { - m_db = QSqlDatabase::addDatabase( "QSQLITE", "tomahawk" ); + m_db = QSqlDatabase::addDatabase( "QSQLITE", connName ); m_db.setDatabaseName( dbname ); if ( !m_db.open() ) throw "db moving failed"; @@ -723,11 +773,3 @@ DatabaseImpl::openDatabase( const QString& dbname ) return schemaUpdated; } - - -void -DatabaseImpl::updateIndex() -{ - DatabaseCommand* cmd = new DatabaseCommand_UpdateSearchIndex(); - Database::instance()->enqueue( QSharedPointer( cmd ) ); -} diff --git a/src/libtomahawk/database/DatabaseImpl.h b/src/libtomahawk/database/DatabaseImpl.h index f734f171f..47b921d33 100644 --- a/src/libtomahawk/database/DatabaseImpl.h +++ b/src/libtomahawk/database/DatabaseImpl.h @@ -48,7 +48,7 @@ public: DatabaseImpl( const QString& dbname, Database* parent = 0 ); ~DatabaseImpl(); - bool openDatabase( const QString& dbname ); + DatabaseImpl* clone() const; TomahawkSqlQuery newquery() { return TomahawkSqlQuery( m_db ); } QSqlDatabase& database() { return m_db; } @@ -81,14 +81,18 @@ public: signals: void indexReady(); -private slots: - void updateIndex(); - private: - QString cleanSql( const QString& sql ); + DatabaseImpl( Database* parent, const QString& dbname ); + void setFuzzyIndex( FuzzyIndex* fi ) { m_fuzzyIndex = fi; } + void setDatabaseID( const QString& dbid ) { m_dbid = dbid; } + + void init(); + bool openDatabase( const QString& dbname, bool checkSchema = true ); bool updateSchema( int oldVersion ); void dumpDatabase(); + QString cleanSql( const QString& sql ); + Database* m_parent; bool m_ready; QSqlDatabase m_db; @@ -97,6 +101,7 @@ private: QString m_dbid; FuzzyIndex* m_fuzzyIndex; + mutable QMutex m_mutex; }; #endif // DATABASEIMPL_H diff --git a/src/libtomahawk/database/DatabaseResolver.cpp b/src/libtomahawk/database/DatabaseResolver.cpp index dcdd3816a..f7791c616 100644 --- a/src/libtomahawk/database/DatabaseResolver.cpp +++ b/src/libtomahawk/database/DatabaseResolver.cpp @@ -54,7 +54,10 @@ DatabaseResolver::resolve( const Tomahawk::query_ptr& query ) void DatabaseResolver::gotResults( const Tomahawk::QID qid, QList< Tomahawk::result_ptr> results ) { - qDebug() << Q_FUNC_INFO << qid << results.length(); + tDebug( LOGVERBOSE ) << Q_FUNC_INFO << qid << results.length(); + + foreach ( const Tomahawk::result_ptr& r, results ) + r->setResolvedBy( this ); Tomahawk::Pipeline::instance()->reportResults( qid, results ); } diff --git a/src/libtomahawk/database/DatabaseWorker.cpp b/src/libtomahawk/database/DatabaseWorker.cpp index bf4972fb0..186012437 100644 --- a/src/libtomahawk/database/DatabaseWorker.cpp +++ b/src/libtomahawk/database/DatabaseWorker.cpp @@ -34,9 +34,9 @@ //#define DEBUG_TIMING TRUE #endif -DatabaseWorker::DatabaseWorker( DatabaseImpl* lib, Database* db, bool mutates ) +DatabaseWorker::DatabaseWorker( Database* db, bool mutates ) : QThread() - , m_dbimpl( lib ) + , m_db( db ) , m_outstanding( 0 ) { Q_UNUSED( db ); @@ -68,6 +68,8 @@ DatabaseWorker::~DatabaseWorker() void DatabaseWorker::run() { + m_dbimpl = m_db->impl()->clone(); + tDebug() << "New db connection with name:" << m_dbimpl->database().connectionName(); exec(); qDebug() << Q_FUNC_INFO << "DatabaseWorker finishing..."; } @@ -191,7 +193,7 @@ DatabaseWorker::doWork() if ( cmd->doesMutates() ) { qDebug() << "Committing" << cmd->commandname() << cmd->guid(); - if ( !m_dbimpl->database().commit() ) + if ( !m_dbimpl->newquery().commitTransaction() ) { tDebug() << "FAILED TO COMMIT TRANSACTION*"; throw "commit failed"; diff --git a/src/libtomahawk/database/DatabaseWorker.h b/src/libtomahawk/database/DatabaseWorker.h index 458d4d427..7da0acc6c 100644 --- a/src/libtomahawk/database/DatabaseWorker.h +++ b/src/libtomahawk/database/DatabaseWorker.h @@ -39,7 +39,7 @@ class DatabaseWorker : public QThread Q_OBJECT public: - DatabaseWorker( DatabaseImpl*, Database*, bool mutates ); + DatabaseWorker( Database*, bool mutates ); ~DatabaseWorker(); bool busy() const { return m_outstanding > 0; } @@ -59,6 +59,7 @@ private: void logOp( DatabaseCommandLoggable* command ); QMutex m_mut; + Database* m_db; DatabaseImpl* m_dbimpl; QList< QSharedPointer > m_commands; int m_outstanding; diff --git a/src/libtomahawk/database/FuzzyIndex.cpp b/src/libtomahawk/database/FuzzyIndex.cpp index 0a26de604..017e1bb4b 100644 --- a/src/libtomahawk/database/FuzzyIndex.cpp +++ b/src/libtomahawk/database/FuzzyIndex.cpp @@ -24,7 +24,9 @@ #include #include +#include "DatabaseCommand_UpdateSearchIndex.h" #include "DatabaseImpl.h" +#include "Database.h" #include "utils/TomahawkUtils.h" #include "utils/Logger.h" #include "Source.h" @@ -38,22 +40,29 @@ using namespace lucene::queryParser; using namespace lucene::search; -FuzzyIndex::FuzzyIndex( DatabaseImpl& db, bool wipeIndex ) - : QObject() - , m_db( db ) +FuzzyIndex::FuzzyIndex( QObject* parent, bool wipe ) + : QObject( parent ) , m_luceneReader( 0 ) , m_luceneSearcher( 0 ) { QString m_lucenePath = TomahawkUtils::appDataDir().absoluteFilePath( "tomahawk.lucene" ); - m_luceneDir = FSDirectory::getDirectory( m_lucenePath.toStdString().c_str() ); - m_analyzer = _CLNEW SimpleAnalyzer(); + QByteArray path = m_lucenePath.toUtf8(); + const char* cPath = path.constData(); - if ( wipeIndex ) + tDebug() << "Opening Lucene directory:" << path; + try { - tLog( LOGVERBOSE ) << "Wiping fuzzy index..."; - beginIndexing(); - endIndexing(); + m_luceneDir = FSDirectory::getDirectory( cPath ); + m_analyzer = _CLNEW SimpleAnalyzer(); } + catch ( CLuceneError& error ) + { + tDebug() << "Caught CLucene error:" << error.what(); + wipe = true; + } + + if ( wipe ) + wipeIndex(); } @@ -66,6 +75,27 @@ FuzzyIndex::~FuzzyIndex() } +bool +FuzzyIndex::wipeIndex() +{ + tLog( LOGVERBOSE ) << "Wiping fuzzy index..."; + beginIndexing(); + endIndexing(); + + QTimer::singleShot( 0, this, SLOT( updateIndex() ) ); + + return true; // FIXME +} + + +void +FuzzyIndex::updateIndex() +{ + DatabaseCommand* cmd = new DatabaseCommand_UpdateSearchIndex(); + Database::instance()->enqueue( QSharedPointer( cmd ) ); +} + + void FuzzyIndex::beginIndexing() { @@ -90,7 +120,7 @@ FuzzyIndex::beginIndexing() } catch( CLuceneError& error ) { - qDebug() << "Caught CLucene error:" << error.what(); + tDebug() << "Caught CLucene error:" << error.what(); Q_ASSERT( false ); } } @@ -158,8 +188,9 @@ FuzzyIndex::appendFields( const QMap< unsigned int, QMap< QString, QString > >& } catch( CLuceneError& error ) { - qDebug() << "Caught CLucene error:" << error.what(); - Q_ASSERT( false ); + tDebug() << "Caught CLucene error:" << error.what(); + + wipeIndex(); } } @@ -252,7 +283,8 @@ FuzzyIndex::search( const Tomahawk::query_ptr& query ) catch( CLuceneError& error ) { tDebug() << "Caught CLucene error:" << error.what(); - Q_ASSERT( false ); + + wipeIndex(); } return resultsmap; @@ -306,7 +338,8 @@ FuzzyIndex::searchAlbum( const Tomahawk::query_ptr& query ) catch( CLuceneError& error ) { tDebug() << "Caught CLucene error:" << error.what(); - Q_ASSERT( false ); + + wipeIndex(); } return resultsmap; diff --git a/src/libtomahawk/database/FuzzyIndex.h b/src/libtomahawk/database/FuzzyIndex.h index 47fe1bf5d..e1f0be693 100644 --- a/src/libtomahawk/database/FuzzyIndex.h +++ b/src/libtomahawk/database/FuzzyIndex.h @@ -55,7 +55,7 @@ class FuzzyIndex : public QObject Q_OBJECT public: - explicit FuzzyIndex( DatabaseImpl& db, bool wipeIndex = false ); + explicit FuzzyIndex( QObject* parent, bool wipe = false ); ~FuzzyIndex(); void beginIndexing(); @@ -71,8 +71,12 @@ public slots: QMap< int, float > search( const Tomahawk::query_ptr& query ); QMap< int, float > searchAlbum( const Tomahawk::query_ptr& query ); +private slots: + void updateIndex(); + private: - DatabaseImpl& m_db; + bool wipeIndex(); + QMutex m_mutex; QString m_lucenePath; diff --git a/src/libtomahawk/database/TomahawkSqlQuery.cpp b/src/libtomahawk/database/TomahawkSqlQuery.cpp new file mode 100644 index 000000000..aa75fc9e5 --- /dev/null +++ b/src/libtomahawk/database/TomahawkSqlQuery.cpp @@ -0,0 +1,131 @@ +/* === This file is part of Tomahawk Player - === + * + * Copyright 2010-2011, Christian Muehlhaeuser + * + * Tomahawk is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Tomahawk is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Tomahawk. If not, see . + */ + +#include "database/TomahawkSqlQuery.h" + +#include "database/Database.h" +#include "database/DatabaseImpl.h" +#include "utils/TomahawkUtils.h" +#include "utils/Logger.h" + +#include +#include +#include +#include + +#define QUERY_THRESHOLD 60 + + +TomahawkSqlQuery::TomahawkSqlQuery() + : QSqlQuery() +{ +} + + +TomahawkSqlQuery::TomahawkSqlQuery( const QSqlDatabase& db ) + : QSqlQuery( db ) + , m_db( db ) +{ +} + + +QString +TomahawkSqlQuery::escape( const QString& identifier, QSqlDriver::IdentifierType type ) +{ + return Database::instance()->impl()->database().driver()->escapeIdentifier( identifier, type ); +} + + +bool +TomahawkSqlQuery::exec( const QString& query ) +{ + prepare( query ); + return exec(); +} + + +bool +TomahawkSqlQuery::exec() +{ + QTime t; + t.start(); + + unsigned int retries = 0; + while ( !QSqlQuery::exec() && ++retries < 10 ) + { + if ( isBusyError( lastError() ) ) + retries = 0; + + tDebug() << "INFO: Retrying failed query:" << lastQuery() << lastError().text(); + TomahawkUtils::msleep( 10 ); + } + + bool ret = ( retries < 10 ); + if ( !ret ) + showError(); + + int e = t.elapsed(); + bool log = ( e >= QUERY_THRESHOLD ); + +#ifdef TOMAHAWK_QUERY_ANALYZE + log = true; +#endif + + if ( log ) + tLog( LOGSQL ) << "TomahawkSqlQuery (" << t.elapsed() << "ms ):" << lastQuery(); + + return ret; +} + + +bool +TomahawkSqlQuery::commitTransaction() +{ + unsigned int retries = 0; + while ( !m_db.commit() && ++retries < 10 ) + { + if ( isBusyError( lastError() ) ) + retries = 0; + + tDebug() << "INFO: Retrying failed commit:" << retries << lastQuery() << lastError().text(); + TomahawkUtils::msleep( 10 ); + } + + return ( retries < 10 ); +} + + +void +TomahawkSqlQuery::showError() +{ + tLog() << endl << "*** DATABASE ERROR ***" << endl + << lastQuery() << endl + << "boundValues:" << boundValues() << endl + << lastError().text() << endl; + + Q_ASSERT( false ); +} + + +bool +TomahawkSqlQuery::isBusyError( const QSqlError& error ) const +{ + const QString text = error.text().trimmed().toLower(); + + return ( text.contains( "locked" ) || text.contains( "busy" ) || text.isEmpty() ); +} diff --git a/src/libtomahawk/database/TomahawkSqlQuery.h b/src/libtomahawk/database/TomahawkSqlQuery.h index b88d56eb8..a54543a35 100644 --- a/src/libtomahawk/database/TomahawkSqlQuery.h +++ b/src/libtomahawk/database/TomahawkSqlQuery.h @@ -18,62 +18,34 @@ #ifndef TOMAHAWKSQLQUERY_H #define TOMAHAWKSQLQUERY_H + // subclass QSqlQuery so that it prints the error msg if a query fails +#include #include -#include -#include -#include "utils/Logger.h" - -#define TOMAHAWK_QUERY_THRESHOLD 60 +#define TOMAHAWK_QUERY_ANALYZE 1 class TomahawkSqlQuery : public QSqlQuery { public: + TomahawkSqlQuery(); + TomahawkSqlQuery( const QSqlDatabase& db ); - TomahawkSqlQuery() - : QSqlQuery() - {} + static QString escape( const QString& identifier, QSqlDriver::IdentifierType type = QSqlDriver::FieldName ); - TomahawkSqlQuery( const QSqlDatabase& db ) - : QSqlQuery( db ) - {} - - bool exec( const QString& query ) - { - prepare( query ); - - return exec(); - } - - bool exec() - { - QTime t; - t.start(); - - bool ret = QSqlQuery::exec(); - if( !ret ) - showError(); - - int e = t.elapsed(); - if ( e >= TOMAHAWK_QUERY_THRESHOLD ) - tLog( LOGVERBOSE ) << "TomahawkSqlQuery (" << lastQuery() << ") finished in" << t.elapsed() << "ms"; - - return ret; - } + bool exec( const QString& query ); + bool exec(); + + bool commitTransaction(); private: - void showError() - { - tLog() << "\n" << "*** DATABASE ERROR ***" << "\n" - << this->lastQuery() << "\n" - << "boundValues:" << this->boundValues() << "\n" - << this->lastError().text() << "\n" - ; - Q_ASSERT( false ); - } + bool isBusyError( const QSqlError& error ) const; + + void showError(); + + QSqlDatabase m_db; }; #endif // TOMAHAWKSQLQUERY_H diff --git a/src/libtomahawk/infobar/InfoBar.cpp b/src/libtomahawk/infobar/InfoBar.cpp index 0aaca0c59..84f334658 100644 --- a/src/libtomahawk/infobar/InfoBar.cpp +++ b/src/libtomahawk/infobar/InfoBar.cpp @@ -22,15 +22,16 @@ #include #include - -#include "ViewManager.h" -#include "thirdparty/Qocoa/qsearchfield.h" -#include "utils/TomahawkUtils.h" -#include "utils/Logger.h" #include #include #include -#include + +#include "ViewManager.h" +#include "thirdparty/Qocoa/qsearchfield.h" +#include "utils/TomahawkUtilsGui.h" +#include "utils/Logger.h" +#include "widgets/QueryLabel.h" +#include "Source.h" #define ANIMATION_TIME 400 #define IMAGE_HEIGHT 64 diff --git a/src/libtomahawk/infosystem/InfoSystem.h b/src/libtomahawk/infosystem/InfoSystem.h index 00a316718..324c1e352 100644 --- a/src/libtomahawk/infosystem/InfoSystem.h +++ b/src/libtomahawk/infosystem/InfoSystem.h @@ -101,6 +101,10 @@ class DLLEXPORT InfoPlugin : public QObject Q_OBJECT public: + /** + * @brief Creates the plugin. Do *not* perform any network-based setup tasks here; defer that to init(), which will be called automatically. + * + **/ InfoPlugin(); virtual ~InfoPlugin(); @@ -115,6 +119,14 @@ signals: void updateCache( Tomahawk::InfoSystem::InfoStringHash criteria, qint64 maxAge, Tomahawk::InfoSystem::InfoType type, QVariant output ); protected slots: + + /** + * @brief Called after the plugin has been moved to the appropriate thread. Do network-based setup tasks here. + * + * @return void + **/ + virtual void init() = 0; + virtual void getInfo( Tomahawk::InfoSystem::InfoRequestData requestData ) = 0; virtual void pushInfo( Tomahawk::InfoSystem::InfoPushData pushData ) = 0; virtual void notInCacheSlot( Tomahawk::InfoSystem::InfoStringHash criteria, Tomahawk::InfoSystem::InfoRequestData requestData ) = 0; diff --git a/src/libtomahawk/infosystem/InfoSystemWorker.cpp b/src/libtomahawk/infosystem/InfoSystemWorker.cpp index d80e3c594..f52ba8729 100644 --- a/src/libtomahawk/infosystem/InfoSystemWorker.cpp +++ b/src/libtomahawk/infosystem/InfoSystemWorker.cpp @@ -96,6 +96,7 @@ InfoSystemWorker::addInfoPlugin( Tomahawk::InfoSystem::InfoPluginPtr plugin ) return; } + plugin.data()->moveToThread( this->thread() ); m_plugins.append( plugin ); registerInfoTypes( plugin, plugin.data()->supportedGetTypes(), plugin.data()->supportedPushTypes() ); @@ -121,6 +122,8 @@ InfoSystemWorker::addInfoPlugin( Tomahawk::InfoSystem::InfoPluginPtr plugin ) SLOT( updateCacheSlot( Tomahawk::InfoSystem::InfoStringHash, qint64, Tomahawk::InfoSystem::InfoType, QVariant ) ), Qt::QueuedConnection ); + + QMetaObject::invokeMethod( plugin.data(), "init", Qt::QueuedConnection ); } diff --git a/src/libtomahawk/jobview/JobStatusModel.cpp b/src/libtomahawk/jobview/JobStatusModel.cpp index 8be72d328..e3ec86e9a 100644 --- a/src/libtomahawk/jobview/JobStatusModel.cpp +++ b/src/libtomahawk/jobview/JobStatusModel.cpp @@ -24,10 +24,10 @@ #include + JobStatusModel::JobStatusModel( QObject* parent ) : QAbstractListModel ( parent ) { - } @@ -52,10 +52,9 @@ JobStatusModel::addJob( JobStatusItem* item ) currentJobCount++; m_jobTypeCount[ item->type() ] = currentJobCount; } - - - connect( item, SIGNAL( statusChanged() ), this, SLOT( itemUpdated() ) ); - connect( item, SIGNAL( finished() ), this, SLOT( itemFinished() ) ); + + connect( item, SIGNAL( statusChanged() ), SLOT( itemUpdated() ) ); + connect( item, SIGNAL( finished() ), SLOT( itemFinished() ) ); if ( item->collapseItem() ) { @@ -77,6 +76,7 @@ JobStatusModel::addJob( JobStatusItem* item ) beginInsertRows( QModelIndex(), currentEndRow, currentEndRow ); m_items.append( item ); endInsertRows(); + if ( item->hasCustomDelegate() ) { tDebug( LOGVERBOSE ) << Q_FUNC_INFO << "job has custom delegate"; @@ -228,5 +228,4 @@ JobStatusModel::itemUpdated() const QModelIndex idx = index( m_items.indexOf( item ), 0, QModelIndex() ); emit dataChanged( idx, idx ); - return; } diff --git a/src/libtomahawk/jobview/PipelineStatusItem.cpp b/src/libtomahawk/jobview/PipelineStatusItem.cpp index 779287789..03296b48b 100644 --- a/src/libtomahawk/jobview/PipelineStatusItem.cpp +++ b/src/libtomahawk/jobview/PipelineStatusItem.cpp @@ -27,12 +27,11 @@ #include "JobStatusView.h" #include "Source.h" +QPixmap* PipelineStatusItem::s_pixmap = 0; PipelineStatusItem::PipelineStatusItem() : JobStatusItem() { - m_icon.load( RESPATH"images/search-icon.png" ); - connect( Tomahawk::Pipeline::instance(), SIGNAL( resolving( Tomahawk::query_ptr ) ), this, SLOT( resolving( Tomahawk::query_ptr ) ) ); connect( Tomahawk::Pipeline::instance(), SIGNAL( idle() ), this, SLOT( idle() ) ); } @@ -65,6 +64,18 @@ PipelineStatusItem::idle() } +QPixmap +PipelineStatusItem::icon() const +{ + if ( !s_pixmap ) + { + s_pixmap = new QPixmap( RESPATH"images/search-icon.png" ); + } + + return *s_pixmap; +} + + void PipelineStatusItem::resolving( const Tomahawk::query_ptr& query ) { @@ -73,6 +84,10 @@ PipelineStatusItem::resolving( const Tomahawk::query_ptr& query ) else m_latestQuery = QString( "%1 - %2" ).arg( query->artist() ).arg( query->track() ); + if ( m_latestQuery.isEmpty() ) + qDebug() << "EMPTY STRING IN STATUS ITEM:" << query->fullTextQuery() << query->track() << query->artist() << query->album(); + Q_ASSERT( !m_latestQuery.isEmpty() ); + emit statusChanged(); } diff --git a/src/libtomahawk/jobview/PipelineStatusItem.h b/src/libtomahawk/jobview/PipelineStatusItem.h index a1d7db719..da95e96fd 100644 --- a/src/libtomahawk/jobview/PipelineStatusItem.h +++ b/src/libtomahawk/jobview/PipelineStatusItem.h @@ -33,7 +33,7 @@ public: virtual QString rightColumnText() const; virtual QString mainText() const; - virtual QPixmap icon() const { return m_icon; } + virtual QPixmap icon() const; virtual QString type() const { return "pipeline"; } @@ -44,8 +44,9 @@ private slots: void idle(); private: - QPixmap m_icon; QString m_latestQuery; + + static QPixmap* s_pixmap; }; class PipelineStatusManager : public QObject diff --git a/src/libtomahawk/mac/FileHelpers.h b/src/libtomahawk/mac/FileHelpers.h index 5c0d46803..ad5fb49d0 100644 --- a/src/libtomahawk/mac/FileHelpers.h +++ b/src/libtomahawk/mac/FileHelpers.h @@ -33,6 +33,8 @@ // Will be asynchronous: Implement the delegate protocol know about the completion + (void) moveFile:(NSString *)source to:(NSString*)dest withDelegate:delegate; +// Internal ++ (void)notifyDelegate:(NSDictionary *)info; @end diff --git a/src/libtomahawk/mac/FileHelpers.mm b/src/libtomahawk/mac/FileHelpers.mm index 97ee3c4ed..ef7573761 100644 --- a/src/libtomahawk/mac/FileHelpers.mm +++ b/src/libtomahawk/mac/FileHelpers.mm @@ -85,9 +85,7 @@ static BOOL AuthorizationExecuteWithPrivilegesAndWait(AuthorizationRef authoriza + (void)performMoveWithInfo:(NSDictionary *)info { - // *** GETS CALLED ON NON-MAIN THREAD! - - CAutoreleasePool _p; + // *** GETS CALLED ON NON-MAIN THREAD! NSString* fromPath = [info objectForKey: TKCopySourceKey]; NSString* toPath = [info objectForKey: TKCopyDestinationKey]; @@ -201,7 +199,13 @@ static BOOL AuthorizationExecuteWithPrivilegesAndWait(AuthorizationRef authoriza if (!success) { NSLog( @"Failed to do non-authenticated move! Help! %@", [[error userInfo] objectForKey: NSLocalizedDescriptionKey] ); } - [self notifyDelegate:[NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithBool:success], TKInstallerResultKey, [info objectForKey:TKInstallerDelegateKey], TKInstallerDelegateKey, error, TKInstallerErrorKey, nil]]; + + NSDictionary* dict = [NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithBool:success], TKInstallerResultKey, [info objectForKey:TKInstallerDelegateKey], TKInstallerDelegateKey, error, TKInstallerErrorKey, nil]; + [self notifyDelegate:dict]; + + // TODO Do not release yet as seems to crash on some systems. +// [fromPath release]; +// [toPath release]; } diff --git a/src/libtomahawk/playlist/AlbumModel.cpp b/src/libtomahawk/playlist/AlbumModel.cpp index eae9d2b64..d7d82f98a 100644 --- a/src/libtomahawk/playlist/AlbumModel.cpp +++ b/src/libtomahawk/playlist/AlbumModel.cpp @@ -35,8 +35,7 @@ using namespace Tomahawk; AlbumModel::AlbumModel( QObject* parent ) - : QAbstractItemModel( parent ) - , m_rootItem( new PlayableItem( 0, this ) ) + : PlayableModel( parent ) , m_overwriteOnAdd( false ) { } @@ -44,197 +43,6 @@ AlbumModel::AlbumModel( QObject* parent ) AlbumModel::~AlbumModel() { - delete m_rootItem; -} - - -QModelIndex -AlbumModel::index( int row, int column, const QModelIndex& parent ) const -{ - if ( !m_rootItem || row < 0 || column < 0 ) - return QModelIndex(); - - PlayableItem* parentItem = itemFromIndex( parent ); - PlayableItem* childItem = parentItem->children.value( row ); - if ( !childItem ) - return QModelIndex(); - - return createIndex( row, column, childItem ); -} - - -int -AlbumModel::rowCount( const QModelIndex& parent ) const -{ - if ( parent.column() > 0 ) - return 0; - - PlayableItem* parentItem = itemFromIndex( parent ); - if ( !parentItem ) - return 0; - - return parentItem->children.count(); -} - - -int -AlbumModel::columnCount( const QModelIndex& parent ) const -{ - Q_UNUSED( parent ); - return 1; -} - - -QModelIndex -AlbumModel::parent( const QModelIndex& child ) const -{ - PlayableItem* entry = itemFromIndex( child ); - if ( !entry ) - return QModelIndex(); - - PlayableItem* parentEntry = entry->parent(); - if ( !parentEntry ) - return QModelIndex(); - - PlayableItem* grandparentEntry = parentEntry->parent(); - if ( !grandparentEntry ) - return QModelIndex(); - - int row = grandparentEntry->children.indexOf( parentEntry ); - return createIndex( row, 0, parentEntry ); -} - - -QVariant -AlbumModel::data( const QModelIndex& index, int role ) const -{ - if ( role == Qt::SizeHintRole ) - return m_itemSize; - - PlayableItem* entry = itemFromIndex( index ); - if ( !entry ) - return QVariant(); - - if ( role != Qt::DisplayRole ) // && role != Qt::ToolTipRole ) - return QVariant(); - - QString name; - if ( !entry->album().isNull() ) - name = entry->album()->name(); - else if ( !entry->artist().isNull() ) - name = entry->artist()->name(); - - switch( index.column() ) - { - case 0: - return name; - break; - } - - return QVariant(); -} - - -QVariant -AlbumModel::headerData( int section, Qt::Orientation orientation, int role ) const -{ - QStringList headers; - headers << tr( "Album" ); - if ( orientation == Qt::Horizontal && role == Qt::DisplayRole && section >= 0 ) - { - return headers.at( section ); - } - - return QVariant(); -} - - -Qt::ItemFlags -AlbumModel::flags( const QModelIndex& index ) const -{ - Qt::ItemFlags defaultFlags = QAbstractItemModel::flags( index ); - - if ( index.isValid() && index.column() == 0 ) - return Qt::ItemIsEditable | Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled | defaultFlags; - else - return defaultFlags; -} - - -QStringList -AlbumModel::mimeTypes() const -{ - QStringList types; - types << "application/tomahawk.query.list"; - return types; -} - - -QMimeData* -AlbumModel::mimeData( const QModelIndexList &indexes ) const -{ - QByteArray queryData; - QDataStream queryStream( &queryData, QIODevice::WriteOnly ); - - bool isAlbumData = true; - foreach ( const QModelIndex& i, indexes ) - { - if ( i.column() > 0 ) - continue; - - QModelIndex idx = index( i.row(), 0, i.parent() ); - PlayableItem* item = itemFromIndex( idx ); - if ( item && !item->album().isNull() ) - { - const album_ptr& album = item->album(); - queryStream << album->artist()->name(); - queryStream << album->name(); - - isAlbumData = true; - } - else if ( item && !item->artist().isNull() ) - { - const artist_ptr& artist = item->artist(); - queryStream << artist->name(); - - isAlbumData = false; - } - } - - QMimeData* mimeData = new QMimeData; - mimeData->setData( isAlbumData ? "application/tomahawk.metadata.album" : "application/tomahawk.metadata.artist", queryData ); - - return mimeData; -} - - -void -AlbumModel::removeIndex( const QModelIndex& index ) -{ - qDebug() << Q_FUNC_INFO; - - if ( index.column() > 0 ) - return; - - PlayableItem* item = itemFromIndex( index ); - if ( item ) - { - emit beginRemoveRows( index.parent(), index.row(), index.row() ); - delete item; - emit endRemoveRows(); - } - - emit itemCountChanged( rowCount( QModelIndex() ) ); -} - - -void -AlbumModel::removeIndexes( const QList& indexes ) -{ - foreach( const QModelIndex& idx, indexes ) - { - removeIndex( idx ); - } } @@ -254,7 +62,7 @@ AlbumModel::addCollection( const collection_ptr& collection, bool overwrite ) Database::instance()->enqueue( QSharedPointer( cmd ) ); - m_title = tr( "All albums from %1" ).arg( collection->source()->friendlyName() ); + setTitle( tr( "All albums from %1" ).arg( collection->source()->friendlyName() ) ); if ( collection.isNull() ) { @@ -296,9 +104,9 @@ AlbumModel::addFilteredCollection( const collection_ptr& collection, unsigned in Database::instance()->enqueue( QSharedPointer( cmd ) ); if ( !collection.isNull() ) - m_title = tr( "All albums from %1" ).arg( collection->source()->friendlyName() ); + setTitle( tr( "All albums from %1" ).arg( collection->source()->friendlyName() ) ); else - m_title = tr( "All albums" ); + setTitle( tr( "All albums" ) ); emit loadingStarted(); } @@ -339,8 +147,8 @@ AlbumModel::addAlbums( const QList& albums ) PlayableItem* albumitem; foreach( const album_ptr& album, trimmedAlbums ) { - albumitem = new PlayableItem( album, m_rootItem ); - albumitem->index = createIndex( m_rootItem->children.count() - 1, 0, albumitem ); + albumitem = new PlayableItem( album, rootItem() ); + albumitem->index = createIndex( rootItem()->children.count() - 1, 0, albumitem ); connect( albumitem, SIGNAL( dataChanged() ), SLOT( onDataChanged() ) ); } @@ -385,8 +193,8 @@ AlbumModel::addArtists( const QList& artists ) PlayableItem* albumitem; foreach ( const artist_ptr& artist, trimmedArtists ) { - albumitem = new PlayableItem( artist, m_rootItem ); - albumitem->index = createIndex( m_rootItem->children.count() - 1, 0, albumitem ); + albumitem = new PlayableItem( artist, rootItem() ); + albumitem->index = createIndex( rootItem()->children.count() - 1, 0, albumitem ); connect( albumitem, SIGNAL( dataChanged() ), SLOT( onDataChanged() ) ); } @@ -414,8 +222,8 @@ AlbumModel::addQueries( const QList& queries ) PlayableItem* albumitem; foreach ( const query_ptr& query, queries ) { - albumitem = new PlayableItem( query, m_rootItem ); - albumitem->index = createIndex( m_rootItem->children.count() - 1, 0, albumitem ); + albumitem = new PlayableItem( query, rootItem() ); + albumitem->index = createIndex( rootItem()->children.count() - 1, 0, albumitem ); connect( albumitem, SIGNAL( dataChanged() ), SLOT( onDataChanged() ) ); } @@ -439,24 +247,6 @@ AlbumModel::onCollectionChanged() } -void -AlbumModel::clear() -{ - beginResetModel(); - delete m_rootItem; - m_rootItem = new PlayableItem( 0, this ); - endResetModel(); -} - - -void -AlbumModel::onDataChanged() -{ - PlayableItem* p = (PlayableItem*)sender(); - emit dataChanged( p->index, p->index.sibling( p->index.row(), columnCount( QModelIndex() ) - 1 ) ); -} - - PlayableItem* AlbumModel::findItem( const artist_ptr& artist ) const { diff --git a/src/libtomahawk/playlist/AlbumModel.h b/src/libtomahawk/playlist/AlbumModel.h index c7ea509ff..0c6413786 100644 --- a/src/libtomahawk/playlist/AlbumModel.h +++ b/src/libtomahawk/playlist/AlbumModel.h @@ -20,19 +20,19 @@ #ifndef ALBUMMODEL_H #define ALBUMMODEL_H -#include #include #include "Album.h" #include "PlaylistInterface.h" #include "database/DatabaseCommand_AllAlbums.h" +#include "PlayableModel.h" #include "DllMacro.h" class PlayableItem; class QMetaData; -class DLLEXPORT AlbumModel : public QAbstractItemModel +class DLLEXPORT AlbumModel : public PlayableModel { Q_OBJECT @@ -40,87 +40,28 @@ public: explicit AlbumModel( QObject* parent = 0 ); virtual ~AlbumModel(); - virtual QModelIndex index( int row, int column, const QModelIndex& parent ) const; - virtual QModelIndex parent( const QModelIndex& child ) const; - - virtual bool isReadOnly() const { return true; } - - virtual int trackCount() const { return rowCount( QModelIndex() ); } - virtual int albumCount() const { return rowCount( QModelIndex() ); } - - virtual int rowCount( const QModelIndex& parent ) const; - virtual int columnCount( const QModelIndex& parent ) const; - - virtual QVariant data( const QModelIndex& index, int role = Qt::DisplayRole ) const; - virtual QVariant headerData( int section, Qt::Orientation orientation, int role ) const; - - virtual void removeIndex( const QModelIndex& index ); - virtual void removeIndexes( const QList& indexes ); - - virtual QMimeData* mimeData( const QModelIndexList& indexes ) const; - virtual QStringList mimeTypes() const; - virtual Qt::ItemFlags flags( const QModelIndex& index ) const; - Tomahawk::collection_ptr collection() const { return m_collection; } - void clear(); void addCollection( const Tomahawk::collection_ptr& collection, bool overwrite = false ); void addFilteredCollection( const Tomahawk::collection_ptr& collection, unsigned int amount, DatabaseCommand_AllAlbums::SortOrder order, bool overwrite = false ); - virtual QString title() const { return m_title; } - virtual QString description() const { return m_description; } - virtual void setTitle( const QString& title ) { m_title = title; } - virtual void setDescription( const QString& description ) { m_description = description; } - - QSize itemSize() const { return m_itemSize; } - void setItemSize( const QSize& size ) { m_itemSize = size; } - PlayableItem* findItem( const Tomahawk::artist_ptr& artist ) const; PlayableItem* findItem( const Tomahawk::album_ptr& album ) const; - PlayableItem* itemFromIndex( const QModelIndex& index ) const - { - if ( index.isValid() ) - return static_cast( index.internalPointer() ); - else - { - return m_rootItem; - } - } - public slots: - virtual void setRepeatMode( Tomahawk::PlaylistModes::RepeatMode /*mode*/ ) {} - virtual void setShuffled( bool /*shuffled*/ ) {} - void addAlbums( const QList& albums ); void addArtists( const QList& artists ); void addQueries( const QList& queries ); signals: - void repeatModeChanged( Tomahawk::PlaylistModes::RepeatMode mode ); - void shuffleModeChanged( bool enabled ); - - void itemCountChanged( unsigned int items ); - - void loadingStarted(); - void loadingFinished(); private slots: - void onDataChanged(); - void onSourceAdded( const Tomahawk::source_ptr& source ); void onCollectionChanged(); private: - QPersistentModelIndex m_currentIndex; - PlayableItem* m_rootItem; - - QString m_title; - QString m_description; bool m_overwriteOnAdd; - QSize m_itemSize; - Tomahawk::collection_ptr m_collection; }; diff --git a/src/libtomahawk/playlist/AlbumProxyModel.cpp b/src/libtomahawk/playlist/AlbumProxyModel.cpp deleted file mode 100644 index 528805662..000000000 --- a/src/libtomahawk/playlist/AlbumProxyModel.cpp +++ /dev/null @@ -1,154 +0,0 @@ -/* === This file is part of Tomahawk Player - === - * - * Copyright 2010-2011, Christian Muehlhaeuser - * Copyright 2010-2012, Jeff Mitchell - * - * Tomahawk is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Tomahawk is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Tomahawk. If not, see . - */ - -#include "AlbumProxyModel.h" - -#include - -#include "AlbumProxyModelPlaylistInterface.h" -#include "Artist.h" -#include "PlayableItem.h" -#include "Query.h" -#include "Source.h" -#include "utils/Logger.h" - - -AlbumProxyModel::AlbumProxyModel( QObject* parent ) - : QSortFilterProxyModel( parent ) - , m_model( 0 ) -{ - setFilterCaseSensitivity( Qt::CaseInsensitive ); - setSortCaseSensitivity( Qt::CaseInsensitive ); - setDynamicSortFilter( true ); - - setSourceAlbumModel( 0 ); -} - - -void -AlbumProxyModel::setSourceModel( QAbstractItemModel* sourceModel ) -{ - Q_UNUSED( sourceModel ); - qDebug() << "Explicitly use setSourceAlbumModel instead"; - Q_ASSERT( false ); -} - - -void -AlbumProxyModel::setSourceAlbumModel( AlbumModel* sourceModel ) -{ - m_model = sourceModel; - - if ( m_model && m_model->metaObject()->indexOfSignal( "trackCountChanged(uint)" ) > -1 ) - connect( m_model, SIGNAL( trackCountChanged( unsigned int ) ), SIGNAL( sourceTrackCountChanged( unsigned int ) ) ); - - QSortFilterProxyModel::setSourceModel( sourceModel ); -} - - -bool -AlbumProxyModel::filterAcceptsRow( int sourceRow, const QModelIndex& sourceParent ) const -{ - if ( filterRegExp().isEmpty() ) - return true; - - PlayableItem* pi = sourceModel()->itemFromIndex( sourceModel()->index( sourceRow, 0, sourceParent ) ); - if ( !pi ) - return false; - - const Tomahawk::album_ptr& q = pi->album(); - - QStringList sl = filterRegExp().pattern().split( " ", QString::SkipEmptyParts ); - - bool found = true; - foreach( const QString& s, sl ) - { - if ( !q->name().contains( s, Qt::CaseInsensitive ) && !q->artist()->name().contains( s, Qt::CaseInsensitive ) ) - { - found = false; - } - } - - return found; -} - - -bool -AlbumProxyModel::lessThan( const QModelIndex& left, const QModelIndex& right ) const -{ - PlayableItem* p1 = sourceModel()->itemFromIndex( left ); - PlayableItem* p2 = sourceModel()->itemFromIndex( right ); - - if ( !p1 ) - return true; - if ( !p2 ) - return false; - - if ( p1->album().isNull() || p1->album()->artist().isNull() ) - return true; - - if ( p2->album().isNull() || p2->album()->artist().isNull() ) - return false; - - if ( p1->album()->artist()->name() == p2->album()->artist()->name() ) - { - return QString::localeAwareCompare( p1->album()->name(), p2->album()->name() ) < 0; - } - - return QString::localeAwareCompare( p1->album()->artist()->name(), p2->album()->artist()->name() ) < 0; -} - - -void -AlbumProxyModel::removeIndex( const QModelIndex& index ) -{ - qDebug() << Q_FUNC_INFO; - - if ( !sourceModel() ) - return; - if ( index.column() > 0 ) - return; - - sourceModel()->removeIndex( mapToSource( index ) ); -} - - -void -AlbumProxyModel::removeIndexes( const QList& indexes ) -{ - if ( !sourceModel() ) - return; - - foreach( const QModelIndex& idx, indexes ) - { - removeIndex( idx ); - } -} - - -Tomahawk::playlistinterface_ptr -AlbumProxyModel::playlistInterface() -{ - if ( m_playlistInterface.isNull() ) - { - m_playlistInterface = Tomahawk::playlistinterface_ptr( new Tomahawk::AlbumProxyModelPlaylistInterface( this ) ); - } - - return m_playlistInterface; -} diff --git a/src/libtomahawk/playlist/AlbumProxyModel.h b/src/libtomahawk/playlist/AlbumProxyModel.h deleted file mode 100644 index c0973caaa..000000000 --- a/src/libtomahawk/playlist/AlbumProxyModel.h +++ /dev/null @@ -1,64 +0,0 @@ -/* === This file is part of Tomahawk Player - === - * - * Copyright 2010-2011, Christian Muehlhaeuser - * Copyright 2010-2012, Jeff Mitchell - * - * Tomahawk is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Tomahawk is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Tomahawk. If not, see . - */ - -#ifndef ALBUMPROXYMODEL_H -#define ALBUMPROXYMODEL_H - -#include - -#include "PlaylistInterface.h" -#include "playlist/AlbumModel.h" - -#include "DllMacro.h" - -class DLLEXPORT AlbumProxyModel : public QSortFilterProxyModel -{ -Q_OBJECT - -public: - explicit AlbumProxyModel( QObject* parent = 0 ); - virtual ~AlbumProxyModel() {} - - virtual AlbumModel* sourceModel() const { return m_model; } - virtual void setSourceAlbumModel( AlbumModel* sourceModel ); - virtual void setSourceModel( QAbstractItemModel* sourceModel ); - - virtual int albumCount() const { return rowCount( QModelIndex() ); } - - virtual void removeIndex( const QModelIndex& index ); - virtual void removeIndexes( const QList& indexes ); - - virtual void emitFilterChanged( const QString &pattern ) { emit filterChanged( pattern ); } - - virtual Tomahawk::playlistinterface_ptr playlistInterface(); - -signals: - void filterChanged( const QString& filter ); - -protected: - bool filterAcceptsRow( int sourceRow, const QModelIndex& sourceParent ) const; - bool lessThan( const QModelIndex& left, const QModelIndex& right ) const; - -private: - AlbumModel* m_model; - - Tomahawk::playlistinterface_ptr m_playlistInterface; -}; - -#endif // ALBUMPROXYMODEL_H diff --git a/src/libtomahawk/playlist/AlbumProxyModelPlaylistInterface.cpp b/src/libtomahawk/playlist/AlbumProxyModelPlaylistInterface.cpp deleted file mode 100644 index 3ede9ef7f..000000000 --- a/src/libtomahawk/playlist/AlbumProxyModelPlaylistInterface.cpp +++ /dev/null @@ -1,101 +0,0 @@ -/* === This file is part of Tomahawk Player - === - * - * Copyright 2010-2011, Christian Muehlhaeuser - * Copyright 2010-2011, Jeff Mitchell - * - * Tomahawk is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Tomahawk is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Tomahawk. If not, see . - */ - -#include "AlbumProxyModelPlaylistInterface.h" - -#include "AlbumProxyModel.h" -#include "Artist.h" -#include "Query.h" -#include "Source.h" -#include "utils/Logger.h" - -using namespace Tomahawk; - -AlbumProxyModelPlaylistInterface::AlbumProxyModelPlaylistInterface( AlbumProxyModel *proxyModel ) - : Tomahawk::PlaylistInterface() - , m_proxyModel( proxyModel ) - , m_repeatMode( PlaylistModes::NoRepeat ) - , m_shuffled( false ) -{ -} - - -AlbumProxyModelPlaylistInterface::~AlbumProxyModelPlaylistInterface() -{ - m_proxyModel.clear(); -} - - -QList< Tomahawk::query_ptr > -AlbumProxyModelPlaylistInterface::tracks() -{ - Q_ASSERT( FALSE ); - QList queries; - return queries; -} - - -int -AlbumProxyModelPlaylistInterface::unfilteredTrackCount() const -{ - return ( m_proxyModel.isNull() ? 0 : m_proxyModel.data()->sourceModel()->rowCount( QModelIndex() ) ); -} - - -int -AlbumProxyModelPlaylistInterface::trackCount() const -{ - return ( m_proxyModel.isNull() ? 0 : m_proxyModel.data()->rowCount( QModelIndex() ) ); -} - - -Tomahawk::result_ptr -AlbumProxyModelPlaylistInterface::currentItem() const -{ - return Tomahawk::result_ptr(); -} - - -QString -AlbumProxyModelPlaylistInterface::filter() const -{ - return ( m_proxyModel.isNull() ? QString() : m_proxyModel.data()->filterRegExp().pattern() ); -} - - -void -AlbumProxyModelPlaylistInterface::setFilter( const QString& pattern ) -{ - qDebug() << Q_FUNC_INFO; - - if ( m_proxyModel.isNull() ) - return; - - m_proxyModel.data()->setFilterRegExp( pattern ); - m_proxyModel.data()->emitFilterChanged( pattern ); -} - - -Tomahawk::result_ptr -AlbumProxyModelPlaylistInterface::siblingItem( int itemsAway ) -{ - Q_UNUSED( itemsAway ); - qDebug() << Q_FUNC_INFO; - return Tomahawk::result_ptr( 0 ); -} diff --git a/src/libtomahawk/playlist/AlbumProxyModelPlaylistInterface.h b/src/libtomahawk/playlist/AlbumProxyModelPlaylistInterface.h deleted file mode 100644 index c04791306..000000000 --- a/src/libtomahawk/playlist/AlbumProxyModelPlaylistInterface.h +++ /dev/null @@ -1,78 +0,0 @@ -/* === This file is part of Tomahawk Player - === - * - * Copyright 2010-2011, Christian Muehlhaeuser - * Copyright 2010-2012, Jeff Mitchell - * - * Tomahawk is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Tomahawk is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Tomahawk. If not, see . - */ - -#ifndef ALBUMPROXYMODELPLAYLISTINTERFACE_H -#define ALBUMPROXYMODELPLAYLISTINTERFACE_H - -#include "PlaylistInterface.h" -#include "playlist/AlbumModel.h" - -#include "DllMacro.h" - -class AlbumProxyModel; - -namespace Tomahawk -{ - -class DLLEXPORT AlbumProxyModelPlaylistInterface : public Tomahawk::PlaylistInterface -{ -Q_OBJECT - -public: - explicit AlbumProxyModelPlaylistInterface( AlbumProxyModel *proxyModel ); - virtual ~AlbumProxyModelPlaylistInterface(); - - virtual QList tracks(); - - virtual int unfilteredTrackCount() const; - virtual int trackCount() const; - - virtual bool hasNextItem() { return true; } - virtual Tomahawk::result_ptr currentItem() const; - virtual Tomahawk::result_ptr siblingItem( int direction ); - - virtual QString filter() const; - virtual void setFilter( const QString& pattern ); - - virtual Tomahawk::PlaylistModes::RepeatMode repeatMode() const { return m_repeatMode; } - virtual bool shuffled() const { return m_shuffled; } - virtual Tomahawk::PlaylistModes::ViewMode viewMode() const { return Tomahawk::PlaylistModes::Album; } - -signals: - void repeatModeChanged( Tomahawk::PlaylistModes::RepeatMode mode ); - void shuffleModeChanged( bool enabled ); - - void trackCountChanged( unsigned int tracks ); - void sourceTrackCountChanged( unsigned int tracks ); - - void nextTrackReady(); - -public slots: - virtual void setRepeatMode( Tomahawk::PlaylistModes::RepeatMode mode ) { m_repeatMode = mode; emit repeatModeChanged( mode ); } - virtual void setShuffled( bool enabled ) { m_shuffled = enabled; emit shuffleModeChanged( enabled ); } - -private: - QWeakPointer< AlbumProxyModel > m_proxyModel; - PlaylistModes::RepeatMode m_repeatMode; - bool m_shuffled; -}; - -} //ns - -#endif // ALBUMPROXYMODELPLAYLISTINTERFACE_H diff --git a/src/libtomahawk/playlist/CollectionFlatModel.cpp b/src/libtomahawk/playlist/CollectionFlatModel.cpp deleted file mode 100644 index 746d3c7d1..000000000 --- a/src/libtomahawk/playlist/CollectionFlatModel.cpp +++ /dev/null @@ -1,141 +0,0 @@ -/* === This file is part of Tomahawk Player - === - * - * Copyright 2010-2011, Christian Muehlhaeuser - * - * Tomahawk is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Tomahawk is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Tomahawk. If not, see . - */ - -#include "CollectionFlatModel.h" - -#include "database/Database.h" -#include "SourceList.h" -#include "PlayableItem.h" -#include "utils/Logger.h" - -using namespace Tomahawk; - - -CollectionFlatModel::CollectionFlatModel( QObject* parent ) - : PlayableModel( parent ) -{ -} - - -CollectionFlatModel::~CollectionFlatModel() -{ -} - - -void -CollectionFlatModel::addCollections( const QList< collection_ptr >& collections ) -{ - foreach( const collection_ptr& col, collections ) - { - addCollection( col ); - } - - // we are waiting for some to load - if( !m_loadingCollections.isEmpty() ) - emit loadingStarted(); -} - - -void -CollectionFlatModel::addCollection( const collection_ptr& collection, bool sendNotifications ) -{ - qDebug() << Q_FUNC_INFO << collection->name() - << collection->source()->id() - << collection->source()->userName(); - - if ( sendNotifications ) - emit loadingStarted(); - - DatabaseCommand_AllTracks* cmd = new DatabaseCommand_AllTracks( collection ); - connect( cmd, SIGNAL( tracks( QList, QVariant ) ), - SLOT( onTracksAdded( QList ) ), Qt::QueuedConnection ); - - Database::instance()->enqueue( QSharedPointer( cmd ) ); - - m_loadingCollections << collection.data(); - - if ( collection->source()->isLocal() ) - setTitle( tr( "My Collection" ) ); - else - setTitle( tr( "Collection of %1" ).arg( collection->source()->friendlyName() ) ); -} - - -void -CollectionFlatModel::addFilteredCollection( const collection_ptr& collection, unsigned int amount, DatabaseCommand_AllTracks::SortOrder order ) -{ - qDebug() << Q_FUNC_INFO << collection->name() - << collection->source()->id() - << collection->source()->userName() - << amount << order; - - DatabaseCommand_AllTracks* cmd = new DatabaseCommand_AllTracks( collection ); - cmd->setLimit( amount ); - cmd->setSortOrder( order ); - cmd->setSortDescending( true ); - - connect( cmd, SIGNAL( tracks( QList, QVariant ) ), - SLOT( onTracksAdded( QList ) ), Qt::QueuedConnection ); - - Database::instance()->enqueue( QSharedPointer( cmd ) ); -} - - -void -CollectionFlatModel::onTracksAdded( const QList& tracks ) -{ - qDebug() << Q_FUNC_INFO << tracks.count() << rowCount( QModelIndex() ); - - if ( !m_loadingCollections.isEmpty() && sender() && qobject_cast< Collection* >( sender() ) ) - { - // we are keeping track and are called as a slot - m_loadingCollections.removeAll( qobject_cast< Collection* >( sender() ) ); - } - - append( tracks ); - - if ( m_loadingCollections.isEmpty() ) - emit loadingFinished(); -} - - -void -CollectionFlatModel::onTracksRemoved( const QList& tracks ) -{ - QList t = tracks; - for ( int i = rowCount( QModelIndex() ); i >= 0 && t.count(); i-- ) - { - QModelIndex idx = index( i, 0, QModelIndex() ); - PlayableItem* item = itemFromIndex( idx ); - if ( !item ) - continue; - - int j = 0; - foreach ( const query_ptr& query, t ) - { - if ( item->query().data() == query.data() ) - { - remove( idx ); - t.removeAt( j ); - break; - } - - j++; - } - } -} diff --git a/src/libtomahawk/playlist/CollectionFlatModel.h b/src/libtomahawk/playlist/CollectionFlatModel.h deleted file mode 100644 index d158196de..000000000 --- a/src/libtomahawk/playlist/CollectionFlatModel.h +++ /dev/null @@ -1,72 +0,0 @@ -/* === This file is part of Tomahawk Player - === - * - * Copyright 2010-2011, Christian Muehlhaeuser - * Copyright 2010-2011, Jeff Mitchell - * - * Tomahawk is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Tomahawk is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Tomahawk. If not, see . - */ - -#ifndef COLLECTIONFLATMODEL_H -#define COLLECTIONFLATMODEL_H - -#include -#include -#include - -#include "Typedefs.h" -#include "PlayableModel.h" -#include "Query.h" -#include "Source.h" -#include "PlaylistInterface.h" - -#include "database/DatabaseCommand_AllTracks.h" - -#include "DllMacro.h" - -class QMetaData; - -class DLLEXPORT CollectionFlatModel : public PlayableModel -{ -Q_OBJECT - -public: - explicit CollectionFlatModel( QObject* parent = 0 ); - ~CollectionFlatModel(); - - virtual int trackCount() const { return rowCount( QModelIndex() ) + m_tracksToAdd.count(); } - - void addCollections( const QList< Tomahawk::collection_ptr >& collections ); - void addCollection( const Tomahawk::collection_ptr& collection, bool sendNotifications = true ); - void addFilteredCollection( const Tomahawk::collection_ptr& collection, unsigned int amount, DatabaseCommand_AllTracks::SortOrder order ); - -signals: - void repeatModeChanged( Tomahawk::PlaylistModes::RepeatMode mode ); - void shuffleModeChanged( bool enabled ); - - void loadingStarted(); - void loadingFinished(); - void trackCountChanged( unsigned int tracks ); - -private slots: - void onTracksAdded( const QList& tracks ); - void onTracksRemoved( const QList& tracks ); - -private: - QMap< Tomahawk::collection_ptr, QPair< int, int > > m_collectionRows; - QList m_tracksToAdd; - // just to keep track of what we are waiting to be loaded - QList m_loadingCollections; -}; - -#endif // COLLECTIONFLATMODEL_H diff --git a/src/libtomahawk/playlist/CollectionProxyModel.cpp b/src/libtomahawk/playlist/CollectionProxyModel.cpp deleted file mode 100644 index 960409717..000000000 --- a/src/libtomahawk/playlist/CollectionProxyModel.cpp +++ /dev/null @@ -1,46 +0,0 @@ -/* === This file is part of Tomahawk Player - === - * - * Copyright 2010-2011, Christian Muehlhaeuser - * Copyright 2010-2012, Jeff Mitchell - * - * Tomahawk is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Tomahawk is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Tomahawk. If not, see . - */ - -#include "CollectionProxyModel.h" - -#include "CollectionProxyModelPlaylistInterface.h" - -#include - -#include "Album.h" -#include "Query.h" -#include "utils/Logger.h" -#include "Source.h" - - -CollectionProxyModel::CollectionProxyModel( QObject* parent ) - : PlayableProxyModel( parent ) -{ -} - -Tomahawk::playlistinterface_ptr -CollectionProxyModel::playlistInterface() -{ - if ( m_playlistInterface.isNull() ) - { - m_playlistInterface = Tomahawk::playlistinterface_ptr( new Tomahawk::CollectionProxyModelPlaylistInterface( this ) ); - } - - return m_playlistInterface; -} diff --git a/src/libtomahawk/playlist/CollectionProxyModelPlaylistInterface.cpp b/src/libtomahawk/playlist/CollectionProxyModelPlaylistInterface.cpp deleted file mode 100644 index b3144c343..000000000 --- a/src/libtomahawk/playlist/CollectionProxyModelPlaylistInterface.cpp +++ /dev/null @@ -1,38 +0,0 @@ -/* === This file is part of Tomahawk Player - === - * - * Copyright 2010-2011, Christian Muehlhaeuser - * Copyright 2010-2011, Jeff Mitchell - * - * Tomahawk is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Tomahawk is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Tomahawk. If not, see . - */ - -#include "CollectionProxyModelPlaylistInterface.h" - -#include "CollectionProxyModel.h" -#include "Album.h" -#include "Query.h" -#include "Source.h" -#include "utils/Logger.h" - -using namespace Tomahawk; - -CollectionProxyModelPlaylistInterface::CollectionProxyModelPlaylistInterface( CollectionProxyModel *proxyModel ) - : PlayableProxyModelPlaylistInterface( proxyModel ) -{ -} - -CollectionProxyModelPlaylistInterface::~CollectionProxyModelPlaylistInterface() -{ - m_proxyModel.clear(); -} diff --git a/src/libtomahawk/playlist/CollectionProxyModelPlaylistInterface.h b/src/libtomahawk/playlist/CollectionProxyModelPlaylistInterface.h deleted file mode 100644 index 386cd25ee..000000000 --- a/src/libtomahawk/playlist/CollectionProxyModelPlaylistInterface.h +++ /dev/null @@ -1,46 +0,0 @@ -/* === This file is part of Tomahawk Player - === - * - * Copyright 2010-2011, Christian Muehlhaeuser - * Copyright 2010-2011, Jeff Mitchell - * - * Tomahawk is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Tomahawk is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Tomahawk. If not, see . - */ - -#ifndef COLLECTIONPROXYMODELPLAYLISTINTERFACE_H -#define COLLECTIONPROXYMODELPLAYLISTINTERFACE_H - -#include "PlayableProxyModel.h" -#include "PlayableProxyModelPlaylistInterface.h" - -#include "DllMacro.h" - -class CollectionProxyModel; - -namespace Tomahawk -{ - -class DLLEXPORT CollectionProxyModelPlaylistInterface : public PlayableProxyModelPlaylistInterface -{ -Q_OBJECT - -public: - explicit CollectionProxyModelPlaylistInterface( CollectionProxyModel* proxyModel ); - virtual ~CollectionProxyModelPlaylistInterface(); - - virtual PlaylistModes::ViewMode viewMode() const { return PlaylistModes::Flat; } -}; - -} //ns - -#endif // COLLECTIONPROXYMODELPLAYLISTINTERFACE_H diff --git a/src/libtomahawk/playlist/CollectionView.cpp b/src/libtomahawk/playlist/CollectionView.cpp deleted file mode 100644 index 0054c16e7..000000000 --- a/src/libtomahawk/playlist/CollectionView.cpp +++ /dev/null @@ -1,99 +0,0 @@ -/* === This file is part of Tomahawk Player - === - * - * Copyright 2010-2011, Christian Muehlhaeuser - * Copyright 2010-2011, Jeff Mitchell - * - * Tomahawk is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Tomahawk is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Tomahawk. If not, see . - */ - -#include "CollectionView.h" - -#include -#include - -#include "CollectionProxyModel.h" -#include "PlayableModel.h" -#include "widgets/OverlayWidget.h" -#include "utils/Logger.h" -#include "Source.h" - -using namespace Tomahawk; - - -CollectionView::CollectionView( QWidget* parent ) - : TrackView( parent ) -{ - setProxyModel( new CollectionProxyModel( this ) ); - - setDragDropMode( QAbstractItemView::DragOnly ); -} - - -CollectionView::~CollectionView() -{ - qDebug() << Q_FUNC_INFO; -} - - -void -CollectionView::setModel( QAbstractItemModel* model ) -{ - Q_UNUSED( model ); - qDebug() << "Explicitly use setPlayableModel instead"; - Q_ASSERT( false ); -} - - -void -CollectionView::setPlayableModel( PlayableModel* model ) -{ - TrackView::setPlayableModel( model ); - - setColumnHidden( PlayableModel::Score, true ); // Hide score column per default - setColumnHidden( PlayableModel::Origin, true ); // Hide origin column per default - setColumnHidden( PlayableModel::Composer, true ); //Hide composer column per default - - setGuid( QString( "collectionview/%1" ).arg( model->columnCount() ) ); - sortByColumn( PlayableModel::Artist, Qt::AscendingOrder ); - - connect( model, SIGNAL( trackCountChanged( unsigned int ) ), SLOT( onTrackCountChanged( unsigned int ) ) ); -} - - -void -CollectionView::dragEnterEvent( QDragEnterEvent* event ) -{ - event->ignore(); -} - - -void -CollectionView::onTrackCountChanged( unsigned int tracks ) -{ - if ( tracks == 0 ) - { - overlay()->setText( tr( "This collection is empty." ) ); - overlay()->show(); - } - else - overlay()->hide(); -} - - -bool -CollectionView::jumpToCurrentTrack() -{ - scrollTo( proxyModel()->currentIndex(), QAbstractItemView::PositionAtCenter ); - return true; -} diff --git a/src/libtomahawk/playlist/CollectionView.h b/src/libtomahawk/playlist/CollectionView.h deleted file mode 100644 index 40f3ac76f..000000000 --- a/src/libtomahawk/playlist/CollectionView.h +++ /dev/null @@ -1,60 +0,0 @@ -/* === This file is part of Tomahawk Player - === - * - * Copyright 2010-2011, Christian Muehlhaeuser - * Copyright 2010-2012, Jeff Mitchell - * - * Tomahawk is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Tomahawk is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Tomahawk. If not, see . - */ - -#ifndef COLLECTIONVIEW_H -#define COLLECTIONVIEW_H - -#include "PlayableModel.h" -#include "PlayableProxyModel.h" -#include "TrackView.h" -#include "ViewPage.h" - -#include "DllMacro.h" - -class DLLEXPORT CollectionView : public TrackView, public Tomahawk::ViewPage -{ -Q_OBJECT - -public: - explicit CollectionView( QWidget* parent = 0 ); - ~CollectionView(); - - virtual void setPlayableModel( PlayableModel* model ); - virtual void setModel( QAbstractItemModel* model ); - - virtual QWidget* widget() { return this; } - virtual Tomahawk::playlistinterface_ptr playlistInterface() const { return proxyModel()->playlistInterface(); } - - virtual QString title() const { return model()->title(); } - virtual QString description() const { return model()->description(); } - virtual QPixmap pixmap() const { return QPixmap( RESPATH "images/music-icon.png" ); } - - virtual bool showModes() const { return true; } - virtual bool showFilter() const { return true; } - - virtual bool jumpToCurrentTrack(); - -private slots: - void onTrackCountChanged( unsigned int tracks ); - -protected: - virtual void dragEnterEvent( QDragEnterEvent* event ); -}; - -#endif // COLLECTIONVIEW_H diff --git a/src/libtomahawk/playlist/CustomPlaylistView.cpp b/src/libtomahawk/playlist/CustomPlaylistView.cpp index 742e8f443..40f81ffdc 100644 --- a/src/libtomahawk/playlist/CustomPlaylistView.cpp +++ b/src/libtomahawk/playlist/CustomPlaylistView.cpp @@ -34,9 +34,6 @@ CustomPlaylistView::CustomPlaylistView( CustomPlaylistView::PlaylistType type, c , m_model( new PlaylistModel( this ) ) { // Generate the tracks, add them to the playlist - setFrameShape( QFrame::NoFrame ); - setAttribute( Qt::WA_MacShowFocusRect, 0 ); - m_model->setStyle( PlayableModel::Large ); setPlaylistModel( m_model ); generateTracks(); @@ -76,6 +73,8 @@ CustomPlaylistView::jumpToCurrentTrack() void CustomPlaylistView::generateTracks() { + m_model->startLoading(); + QString sql; switch ( m_type ) { @@ -106,8 +105,9 @@ void CustomPlaylistView::tracksGenerated( QList< query_ptr > tracks ) { bool changed = false; - QList< query_ptr > newTracks = TomahawkUtils::mergePlaylistChanges( m_model->queries(), tracks, changed); + QList< query_ptr > newTracks = TomahawkUtils::mergePlaylistChanges( m_model->queries(), tracks, changed ); + m_model->finishLoading(); if ( !changed ) return; diff --git a/src/libtomahawk/playlist/AlbumItemDelegate.cpp b/src/libtomahawk/playlist/GridItemDelegate.cpp similarity index 75% rename from src/libtomahawk/playlist/AlbumItemDelegate.cpp rename to src/libtomahawk/playlist/GridItemDelegate.cpp index 980454817..4568c1705 100644 --- a/src/libtomahawk/playlist/AlbumItemDelegate.cpp +++ b/src/libtomahawk/playlist/GridItemDelegate.cpp @@ -17,12 +17,13 @@ * along with Tomahawk. If not, see . */ -#include "AlbumItemDelegate.h" +#include "GridItemDelegate.h" #include #include #include #include +#include #include "Artist.h" #include "Query.h" @@ -30,33 +31,37 @@ #include "Source.h" #include "audio/AudioEngine.h" -#include "utils/TomahawkUtils.h" +#include "utils/TomahawkUtilsGui.h" #include "utils/PixmapDelegateFader.h" #include #include "playlist/PlayableItem.h" -#include "playlist/AlbumProxyModel.h" -#include "AlbumView.h" +#include "playlist/PlayableProxyModel.h" +#include "GridView.h" #include "ViewManager.h" #include "utils/AnimatedSpinner.h" #include "widgets/ImageButton.h" #include "utils/Logger.h" +namespace { + static const int FADE_DURATION = 200; +}; -AlbumItemDelegate::AlbumItemDelegate( QAbstractItemView* parent, AlbumProxyModel* proxy ) + +GridItemDelegate::GridItemDelegate( QAbstractItemView* parent, PlayableProxyModel* proxy ) : QStyledItemDelegate( (QObject*)parent ) , m_view( parent ) , m_model( proxy ) { if ( m_view && m_view->metaObject()->indexOfSignal( "modelChanged()" ) > -1 ) connect( m_view, SIGNAL( modelChanged() ), this, SLOT( modelChanged() ) ); - + connect( m_view, SIGNAL( scrolledContents( int, int ) ), SLOT( onScrolled( int, int ) ) ); } QSize -AlbumItemDelegate::sizeHint( const QStyleOptionViewItem& option, const QModelIndex& index ) const +GridItemDelegate::sizeHint( const QStyleOptionViewItem& option, const QModelIndex& index ) const { QSize size = QStyledItemDelegate::sizeHint( option, index ); return size; @@ -64,7 +69,7 @@ AlbumItemDelegate::sizeHint( const QStyleOptionViewItem& option, const QModelInd void -AlbumItemDelegate::paint( QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index ) const +GridItemDelegate::paint( QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index ) const { PlayableItem* item = m_model->sourceModel()->itemFromIndex( m_model->mapToSource( index ) ); if ( !item ) @@ -111,7 +116,7 @@ AlbumItemDelegate::paint( QPainter* painter, const QStyleOptionViewItem& option, m_covers.insert( index, QSharedPointer< Tomahawk::PixmapDelegateFader >( new Tomahawk::PixmapDelegateFader( item->query(), r.size(), TomahawkUtils::Grid ) ) ); } - _detail::Closure* closure = NewClosure( m_covers[ index ], SIGNAL( repaintRequest() ), const_cast(this), SLOT( doUpdateIndex( QPersistentModelIndex ) ), QPersistentModelIndex( index ) ); + _detail::Closure* closure = NewClosure( m_covers[ index ], SIGNAL( repaintRequest() ), const_cast(this), SLOT( doUpdateIndex( QPersistentModelIndex ) ), QPersistentModelIndex( index ) ); closure->setAutoDelete( false ); } @@ -120,34 +125,26 @@ AlbumItemDelegate::paint( QPainter* painter, const QStyleOptionViewItem& option, fader->setSize( r.size() ); const QPixmap cover = fader->currentPixmap(); - - if ( false && option.state & QStyle::State_Selected ) - { -#if defined(Q_WS_MAC) || defined(Q_WS_WIN) - painter->save(); - - QPainterPath border; - border.addRoundedRect( r.adjusted( -2, -2, 2, 2 ), 3, 3 ); - QPen borderPen( QColor( 86, 170, 243 ) ); - borderPen.setWidth( 5 ); - painter->setPen( borderPen ); - painter->drawPath( border ); - - painter->restore(); -#else - opt.palette.setColor( QPalette::Text, opt.palette.color( QPalette::HighlightedText ) ); -#endif - } - painter->drawPixmap( r, cover ); - if ( m_hoverIndex == index ) + qreal opacity = -1.; + if ( m_hoverFaders.contains( index ) ) + { + const qreal pct = ( m_hoverFaders[ index ]->currentFrame() / 100. ); + opacity = 0.35 - pct * 0.35; + } + else if ( m_hoverIndex == index ) + { + opacity = 0.35; + } + + if ( opacity > -1. ) { painter->save(); painter->setPen( QColor( 33, 33, 33 ) ); painter->setBrush( QColor( 33, 33, 33 ) ); - painter->setOpacity( 0.5 ); + painter->setOpacity( opacity ); painter->drawRect( r ); painter->restore(); @@ -221,7 +218,7 @@ AlbumItemDelegate::paint( QPainter* painter, const QStyleOptionViewItem& option, void -AlbumItemDelegate::onPlayClicked( const QPersistentModelIndex& index ) +GridItemDelegate::onPlayClicked( const QPersistentModelIndex& index ) { QPoint pos = m_playButton[ index ]->pos(); foreach ( ImageButton* button, m_playButton ) @@ -236,17 +233,17 @@ AlbumItemDelegate::onPlayClicked( const QPersistentModelIndex& index ) spinner->installEventFilter( this ); m_spinner[ index ] = spinner; - + PlayableItem* item = m_model->sourceModel()->itemFromIndex( m_model->mapToSource( index ) ); if ( item ) { _detail::Closure* closure; - + closure = NewClosure( AudioEngine::instance(), SIGNAL( loading( Tomahawk::result_ptr ) ), - const_cast(this), SLOT( onPlaybackStarted( QPersistentModelIndex ) ), QPersistentModelIndex( index ) ); + const_cast(this), SLOT( onPlaybackStarted( QPersistentModelIndex ) ), QPersistentModelIndex( index ) ); closure = NewClosure( AudioEngine::instance(), SIGNAL( started( Tomahawk::result_ptr ) ), - const_cast(this), SLOT( onPlaylistChanged( QPersistentModelIndex ) ), QPersistentModelIndex( index ) ); + const_cast(this), SLOT( onPlaylistChanged( QPersistentModelIndex ) ), QPersistentModelIndex( index ) ); closure->setAutoDelete( false ); connect( AudioEngine::instance(), SIGNAL( stopped() ), SLOT( onPlaybackFinished() ) ); @@ -262,7 +259,7 @@ AlbumItemDelegate::onPlayClicked( const QPersistentModelIndex& index ) bool -AlbumItemDelegate::editorEvent( QEvent* event, QAbstractItemModel* model, const QStyleOptionViewItem& option, const QModelIndex& index ) +GridItemDelegate::editorEvent( QEvent* event, QAbstractItemModel* model, const QStyleOptionViewItem& option, const QModelIndex& index ) { Q_UNUSED( model ); Q_UNUSED( option ); @@ -276,19 +273,24 @@ AlbumItemDelegate::editorEvent( QEvent* event, QAbstractItemModel* model, const bool hoveringArtist = false; if ( m_artistNameRects.contains( index ) ) { - QRect artistNameRect = m_artistNameRects[ index ]; - QMouseEvent* ev = static_cast< QMouseEvent* >( event ); + const QRect artistNameRect = m_artistNameRects[ index ]; + const QMouseEvent* ev = static_cast< QMouseEvent* >( event ); hoveringArtist = artistNameRect.contains( ev->pos() ); } if ( event->type() == QEvent::MouseMove ) { + if ( hoveringArtist ) + m_view->setCursor( Qt::PointingHandCursor ); + else + m_view->setCursor( Qt::ArrowCursor ); + foreach ( const QModelIndex& idx, m_playButton.keys() ) { if ( index != idx ) m_playButton.take( idx )->deleteLater(); } - + if ( !m_playButton.contains( index ) && !m_spinner.contains( index ) && !m_pauseButton.contains( index ) ) { foreach ( ImageButton* button, m_playButton ) @@ -304,9 +306,9 @@ AlbumItemDelegate::editorEvent( QEvent* event, QAbstractItemModel* model, const button->setFocusPolicy( Qt::NoFocus ); button->installEventFilter( this ); button->show(); - + NewClosure( button, SIGNAL( clicked( bool ) ), - const_cast(this), SLOT( onPlayClicked( QPersistentModelIndex ) ), QPersistentModelIndex( index ) ); + const_cast(this), SLOT( onPlayClicked( QPersistentModelIndex ) ), QPersistentModelIndex( index ) ); m_playButton[ index ] = button; } @@ -325,17 +327,42 @@ AlbumItemDelegate::editorEvent( QEvent* event, QAbstractItemModel* model, const if ( m_hoverIndex != index ) { + if ( m_hoverIndex.isValid() ) + { + QTimeLine* fadeOut = createTimeline( QTimeLine::Forward ); + _detail::Closure* c = NewClosure( fadeOut, SIGNAL( frameChanged( int ) ), this, SLOT( fadingFrameChanged( QPersistentModelIndex ) ), QPersistentModelIndex( m_hoverIndex ) ); + c->setAutoDelete( false ); + c = NewClosure( fadeOut, SIGNAL( finished() ), this, SLOT( fadingFrameFinished( QPersistentModelIndex ) ), QPersistentModelIndex( m_hoverIndex ) ); + c->setAutoDelete( false ); + m_hoverFaders[ m_hoverIndex ] = fadeOut; + fadeOut->start(); + } + emit updateIndex( m_hoverIndex ); m_hoverIndex = index; + + QTimeLine* fadeIn = createTimeline( QTimeLine::Backward ); + _detail::Closure* c = NewClosure( fadeIn, SIGNAL( frameChanged( int ) ), this, SLOT( fadingFrameChanged( QPersistentModelIndex ) ), QPersistentModelIndex( index ) ); + c->setAutoDelete( false ); + c = NewClosure( fadeIn, SIGNAL( finished() ), this, SLOT( fadingFrameFinished( QPersistentModelIndex ) ), QPersistentModelIndex( index ) ); + c->setAutoDelete( false ); + + m_hoverFaders[ index ] = fadeIn; + fadeIn->start(); + emit updateIndex( index ); } - + event->accept(); return true; } + // reset mouse cursor. we switch to a pointing hand cursor when hovering an artist name + m_view->setCursor( Qt::ArrowCursor ); + if ( hoveringArtist ) { + if ( event->type() == QEvent::MouseButtonRelease ) { PlayableItem* item = m_model->sourceModel()->itemFromIndex( m_model->mapToSource( index ) ); @@ -363,7 +390,7 @@ AlbumItemDelegate::editorEvent( QEvent* event, QAbstractItemModel* model, const void -AlbumItemDelegate::modelChanged() +GridItemDelegate::modelChanged() { m_artistNameRects.clear(); m_hoveringOver = QPersistentModelIndex(); @@ -379,13 +406,13 @@ AlbumItemDelegate::modelChanged() widget->deleteLater(); m_spinner.clear(); - if ( AlbumView* view = qobject_cast< AlbumView* >( m_view ) ) + if ( GridView* view = qobject_cast< GridView* >( m_view ) ) m_model = view->proxyModel(); } void -AlbumItemDelegate::doUpdateIndex( const QPersistentModelIndex& idx ) +GridItemDelegate::doUpdateIndex( const QPersistentModelIndex& idx ) { if ( !idx.isValid() ) return; @@ -394,7 +421,7 @@ AlbumItemDelegate::doUpdateIndex( const QPersistentModelIndex& idx ) void -AlbumItemDelegate::onScrolled( int dx, int dy ) +GridItemDelegate::onScrolled( int dx, int dy ) { foreach ( QWidget* widget, m_spinner.values() ) { @@ -412,7 +439,7 @@ AlbumItemDelegate::onScrolled( int dx, int dy ) void -AlbumItemDelegate::onPlaybackFinished() +GridItemDelegate::onPlaybackFinished() { foreach ( ImageButton* button, m_pauseButton ) button->deleteLater(); @@ -421,7 +448,7 @@ AlbumItemDelegate::onPlaybackFinished() void -AlbumItemDelegate::onPlaylistChanged( const QPersistentModelIndex& index ) +GridItemDelegate::onPlaylistChanged( const QPersistentModelIndex& index ) { PlayableItem* item = m_model->sourceModel()->itemFromIndex( m_model->mapToSource( index ) ); if ( item ) @@ -443,7 +470,7 @@ AlbumItemDelegate::onPlaylistChanged( const QPersistentModelIndex& index ) if ( AudioEngine::instance()->currentTrackPlaylist() != item->artist()->playlistInterface( Tomahawk::Mixed ) ) finished = true; } - + if ( finished ) { if ( m_pauseButton.contains( index ) ) @@ -457,7 +484,7 @@ AlbumItemDelegate::onPlaylistChanged( const QPersistentModelIndex& index ) void -AlbumItemDelegate::onPlaybackStarted( const QPersistentModelIndex& index ) +GridItemDelegate::onPlaybackStarted( const QPersistentModelIndex& index ) { if ( !m_spinner.contains( index ) ) return; @@ -468,7 +495,7 @@ AlbumItemDelegate::onPlaybackStarted( const QPersistentModelIndex& index ) delete widget; } m_spinner.clear(); - + ImageButton* button = new ImageButton( m_view ); button->setPixmap( RESPATH "images/pause-rest.png" ); button->setPixmap( RESPATH "images/pause-pressed.png", QIcon::Off, QIcon::Active ); @@ -478,15 +505,47 @@ AlbumItemDelegate::onPlaybackStarted( const QPersistentModelIndex& index ) button->setFocusPolicy( Qt::NoFocus ); button->installEventFilter( this ); button->show(); - + connect( button, SIGNAL( clicked( bool ) ), AudioEngine::instance(), SLOT( playPause() ) ); m_pauseButton[ index ] = button; } +void +GridItemDelegate::fadingFrameChanged( const QPersistentModelIndex& idx ) +{ + emit updateIndex( idx ); +} + + +void +GridItemDelegate::fadingFrameFinished( const QPersistentModelIndex& idx ) +{ + if ( m_hoverFaders.contains( idx ) ) + { + m_hoverFaders.take( idx )->deleteLater(); + emit updateIndex( idx ); + } +} + + +QTimeLine* +GridItemDelegate::createTimeline( QTimeLine::Direction direction ) +{ + QTimeLine* timeline = new QTimeLine( FADE_DURATION, this ); + timeline->setDirection( direction ); + timeline->setCurveShape( QTimeLine::LinearCurve ); + timeline->setUpdateInterval( 30 ); + timeline->setStartFrame( 0 ); + timeline->setEndFrame( 100 ); + + return timeline; +} + + bool -AlbumItemDelegate::eventFilter( QObject* obj, QEvent* event ) +GridItemDelegate::eventFilter( QObject* obj, QEvent* event ) { if ( event->type() == QEvent::Wheel ) { diff --git a/src/libtomahawk/playlist/AlbumItemDelegate.h b/src/libtomahawk/playlist/GridItemDelegate.h similarity index 80% rename from src/libtomahawk/playlist/AlbumItemDelegate.h rename to src/libtomahawk/playlist/GridItemDelegate.h index 0715e781d..d2caa9999 100644 --- a/src/libtomahawk/playlist/AlbumItemDelegate.h +++ b/src/libtomahawk/playlist/GridItemDelegate.h @@ -17,10 +17,11 @@ * along with Tomahawk. If not, see . */ -#ifndef ALBUMITEMDELEGATE_H -#define ALBUMITEMDELEGATE_H +#ifndef GRIDITEMDELEGATE_H +#define GRIDITEMDELEGATE_H #include +#include #include "DllMacro.h" @@ -29,15 +30,16 @@ namespace Tomahawk { } class QEvent; -class AlbumProxyModel; +class QTimeLine; +class PlayableProxyModel; class ImageButton; -class DLLEXPORT AlbumItemDelegate : public QStyledItemDelegate +class DLLEXPORT GridItemDelegate : public QStyledItemDelegate { Q_OBJECT public: - AlbumItemDelegate( QAbstractItemView* parent = 0, AlbumProxyModel* proxy = 0 ); + GridItemDelegate( QAbstractItemView* parent = 0, PlayableProxyModel* proxy = 0 ); protected: void paint( QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index ) const; @@ -52,17 +54,21 @@ signals: private slots: void modelChanged(); void doUpdateIndex( const QPersistentModelIndex& idx ); - + void onScrolled( int dx, int dy ); void onPlaybackStarted( const QPersistentModelIndex& index ); void onPlaybackFinished(); - + void onPlayClicked( const QPersistentModelIndex& index ); void onPlaylistChanged( const QPersistentModelIndex& index ); + void fadingFrameChanged( const QPersistentModelIndex& ); + void fadingFrameFinished( const QPersistentModelIndex& ); private: + QTimeLine* createTimeline( QTimeLine::Direction direction ); + QAbstractItemView* m_view; - AlbumProxyModel* m_model; + PlayableProxyModel* m_model; mutable QHash< QPersistentModelIndex, QRect > m_artistNameRects; mutable QHash< QPersistentModelIndex, QSharedPointer< Tomahawk::PixmapDelegateFader > > m_covers; @@ -75,6 +81,8 @@ private: mutable QHash< QPersistentModelIndex, QWidget* > m_spinner; mutable QHash< QPersistentModelIndex, ImageButton* > m_playButton; mutable QHash< QPersistentModelIndex, ImageButton* > m_pauseButton; + + mutable QHash< QPersistentModelIndex, QTimeLine* > m_hoverFaders; }; -#endif // ALBUMITEMDELEGATE_H +#endif // GRIDITEMDELEGATE_H diff --git a/src/libtomahawk/playlist/AlbumView.cpp b/src/libtomahawk/playlist/GridView.cpp similarity index 78% rename from src/libtomahawk/playlist/AlbumView.cpp rename to src/libtomahawk/playlist/GridView.cpp index 779afd97f..3d935b876 100644 --- a/src/libtomahawk/playlist/AlbumView.cpp +++ b/src/libtomahawk/playlist/GridView.cpp @@ -17,7 +17,7 @@ * along with Tomahawk. If not, see . */ -#include "AlbumView.h" +#include "GridView.h" #include #include @@ -29,29 +29,35 @@ #include "context/ContextWidget.h" #include "TomahawkSettings.h" #include "Artist.h" +#include "Source.h" #include "PlayableItem.h" -#include "AlbumItemDelegate.h" +#include "GridItemDelegate.h" #include "AlbumModel.h" +#include "PlayableModel.h" #include "ContextMenu.h" #include "ViewManager.h" #include "utils/Logger.h" #include "utils/AnimatedSpinner.h" +#include "utils/TomahawkUtilsGui.h" #define SCROLL_TIMEOUT 280 using namespace Tomahawk; -AlbumView::AlbumView( QWidget* parent ) +GridView::GridView( QWidget* parent ) : QListView( parent ) , m_model( 0 ) , m_proxyModel( 0 ) , m_delegate( 0 ) - , m_loadingSpinner( new AnimatedSpinner( this ) ) + , m_loadingSpinner( new LoadingSpinner( this ) ) , m_overlay( new OverlayWidget( this ) ) , m_contextMenu( new ContextMenu( this ) ) , m_inited( false ) { + setFrameShape( QFrame::NoFrame ); + setAttribute( Qt::WA_MacShowFocusRect, 0 ); + setDragEnabled( true ); setDropIndicatorShown( false ); setDragDropOverwriteMode( false ); @@ -68,25 +74,30 @@ AlbumView::AlbumView( QWidget* parent ) setStyleSheet( "QListView { background-color: #323435; }" ); setAutoFitItems( true ); - setProxyModel( new AlbumProxyModel( this ) ); + setAutoResize( false ); + setProxyModel( new PlayableProxyModel( this ) ); + +/* m_overlay->setText( tr( "After you have scanned your music collection you will find your latest album additions right here." ) ); + m_overlay->setText( tr( "This collection doesn't have any recent albums." ) );*/ connect( this, SIGNAL( doubleClicked( QModelIndex ) ), SLOT( onItemActivated( QModelIndex ) ) ); connect( this, SIGNAL( customContextMenuRequested( QPoint ) ), SLOT( onCustomContextMenu( QPoint ) ) ); + connect( proxyModel(), SIGNAL( modelReset() ), SLOT( layoutItems() ) ); // connect( m_contextMenu, SIGNAL( triggered( int ) ), SLOT( onMenuTriggered( int ) ) ); } -AlbumView::~AlbumView() +GridView::~GridView() { qDebug() << Q_FUNC_INFO; } void -AlbumView::setProxyModel( AlbumProxyModel* model ) +GridView::setProxyModel( PlayableProxyModel* model ) { m_proxyModel = model; - m_delegate = new AlbumItemDelegate( this, m_proxyModel ); + m_delegate = new GridItemDelegate( this, m_proxyModel ); connect( m_delegate, SIGNAL( updateIndex( QModelIndex ) ), this, SLOT( update( QModelIndex ) ) ); setItemDelegate( m_delegate ); @@ -95,7 +106,7 @@ AlbumView::setProxyModel( AlbumProxyModel* model ) void -AlbumView::setModel( QAbstractItemModel* model ) +GridView::setModel( QAbstractItemModel* model ) { Q_UNUSED( model ); qDebug() << "Explicitly use setAlbumModel instead"; @@ -104,28 +115,33 @@ AlbumView::setModel( QAbstractItemModel* model ) void -AlbumView::setAlbumModel( AlbumModel* model ) +GridView::setPlayableModel( PlayableModel* model ) { + m_inited = false; m_model = model; if ( m_proxyModel ) { - m_proxyModel->setSourceAlbumModel( m_model ); + m_proxyModel->setSourcePlayableModel( m_model ); m_proxyModel->sort( 0 ); } connect( m_proxyModel, SIGNAL( filterChanged( QString ) ), SLOT( onFilterChanged( QString ) ) ); - connect( m_model, SIGNAL( itemCountChanged( unsigned int ) ), SLOT( onItemCountChanged( unsigned int ) ) ); - connect( m_model, SIGNAL( loadingStarted() ), m_loadingSpinner, SLOT( fadeIn() ) ); - connect( m_model, SIGNAL( loadingFinished() ), m_loadingSpinner, SLOT( fadeOut() ) ); - emit modelChanged(); } void -AlbumView::currentChanged( const QModelIndex& current, const QModelIndex& previous ) +GridView::setEmptyTip( const QString& tip ) +{ + m_emptyTip = tip; + m_overlay->setText( tip ); +} + + +void +GridView::currentChanged( const QModelIndex& current, const QModelIndex& previous ) { QListView::currentChanged( current, previous ); @@ -139,7 +155,7 @@ AlbumView::currentChanged( const QModelIndex& current, const QModelIndex& previo void -AlbumView::onItemActivated( const QModelIndex& index ) +GridView::onItemActivated( const QModelIndex& index ) { PlayableItem* item = m_model->itemFromIndex( m_proxyModel->mapToSource( index ) ); if ( item ) @@ -158,24 +174,7 @@ AlbumView::onItemActivated( const QModelIndex& index ) void -AlbumView::onItemCountChanged( unsigned int items ) -{ - if ( items == 0 ) - { - if ( m_model->collection().isNull() || ( !m_model->collection().isNull() && m_model->collection()->source()->isLocal() ) ) - m_overlay->setText( tr( "After you have scanned your music collection you will find your latest album additions right here." ) ); - else - m_overlay->setText( tr( "This collection doesn't have any recent albums." ) ); - - m_overlay->show(); - } - else - m_overlay->hide(); -} - - -void -AlbumView::scrollContentsBy( int dx, int dy ) +GridView::scrollContentsBy( int dx, int dy ) { QListView::scrollContentsBy( dx, dy ); emit scrolledContents( dx, dy ); @@ -183,7 +182,7 @@ AlbumView::scrollContentsBy( int dx, int dy ) void -AlbumView::paintEvent( QPaintEvent* event ) +GridView::paintEvent( QPaintEvent* event ) { if ( !autoFitItems() || m_inited || !m_proxyModel->rowCount() ) QListView::paintEvent( event ); @@ -191,11 +190,17 @@ AlbumView::paintEvent( QPaintEvent* event ) void -AlbumView::resizeEvent( QResizeEvent* event ) +GridView::resizeEvent( QResizeEvent* event ) { QListView::resizeEvent( event ); + layoutItems(); +} - if ( autoFitItems() ) + +void +GridView::layoutItems() +{ + if ( autoFitItems() && m_model ) { #ifdef Q_WS_X11 // int scrollbar = verticalScrollBar()->isVisible() ? verticalScrollBar()->width() + 16 : 0; @@ -205,8 +210,7 @@ AlbumView::resizeEvent( QResizeEvent* event ) #endif int rectWidth = contentsRect().width() - scrollbar - 3; int itemWidth = 160; - QSize itemSize = m_proxyModel->data( QModelIndex(), Qt::SizeHintRole ).toSize(); - Q_UNUSED( itemSize ); // looks obsolete +// QSize itemSize = m_proxyModel->data( QModelIndex(), Qt::SizeHintRole ).toSize(); int itemsPerRow = qMax( 1, qFloor( rectWidth / itemWidth ) ); // int rightSpacing = rectWidth - ( itemsPerRow * ( itemSize.width() + 16 ) ); @@ -215,8 +219,16 @@ AlbumView::resizeEvent( QResizeEvent* event ) int remSpace = rectWidth - ( itemsPerRow * itemWidth ); int extraSpace = remSpace / itemsPerRow; int newItemWidth = itemWidth + extraSpace; + m_model->setItemSize( QSize( newItemWidth, newItemWidth ) ); + if ( autoResize() ) + { + int rows = ceil( (double)m_proxyModel->rowCount( QModelIndex() ) / (double)itemsPerRow ); + int newHeight = rows * newItemWidth; + setFixedHeight( newHeight ); + } + if ( !m_inited ) { m_inited = true; @@ -227,7 +239,7 @@ AlbumView::resizeEvent( QResizeEvent* event ) void -AlbumView::onFilterChanged( const QString& ) +GridView::onFilterChanged( const QString& ) { if ( selectedIndexes().count() ) scrollTo( selectedIndexes().at( 0 ), QAbstractItemView::PositionAtCenter ); @@ -235,7 +247,7 @@ AlbumView::onFilterChanged( const QString& ) void -AlbumView::startDrag( Qt::DropActions supportedActions ) +GridView::startDrag( Qt::DropActions supportedActions ) { QList pindexes; QModelIndexList indexes; @@ -267,7 +279,7 @@ AlbumView::startDrag( Qt::DropActions supportedActions ) void -AlbumView::onCustomContextMenu( const QPoint& pos ) +GridView::onCustomContextMenu( const QPoint& pos ) { m_contextMenu->clear(); diff --git a/src/libtomahawk/playlist/AlbumView.h b/src/libtomahawk/playlist/GridView.h similarity index 75% rename from src/libtomahawk/playlist/AlbumView.h rename to src/libtomahawk/playlist/GridView.h index e72b2fa2a..ffb5befa9 100644 --- a/src/libtomahawk/playlist/AlbumView.h +++ b/src/libtomahawk/playlist/GridView.h @@ -17,15 +17,15 @@ * along with Tomahawk. If not, see . */ -#ifndef ALBUMVIEW_H -#define ALBUMVIEW_H +#ifndef GRIDVIEW_H +#define GRIDVIEW_H #include #include #include #include "ViewPage.h" -#include "AlbumProxyModel.h" +#include "PlayableProxyModel.h" #include "widgets/OverlayWidget.h" #include "DllMacro.h" @@ -34,30 +34,34 @@ namespace Tomahawk class ContextMenu; }; -class AlbumModel; class AnimatedSpinner; -class AlbumItemDelegate; +class GridItemDelegate; +class PlayableModel; -class DLLEXPORT AlbumView : public QListView, public Tomahawk::ViewPage +class DLLEXPORT GridView : public QListView, public Tomahawk::ViewPage { Q_OBJECT public: - explicit AlbumView( QWidget* parent = 0 ); - ~AlbumView(); + explicit GridView( QWidget* parent = 0 ); + ~GridView(); - void setProxyModel( AlbumProxyModel* model ); + void setProxyModel( PlayableProxyModel* model ); - AlbumModel* model() const { return m_model; } - AlbumProxyModel* proxyModel() const { return m_proxyModel; } -// PlaylistItemDelegate* delegate() { return m_delegate; } + PlayableModel* model() const { return m_model; } + PlayableProxyModel* proxyModel() const { return m_proxyModel; } bool autoFitItems() const { return m_autoFitItems; } void setAutoFitItems( bool b ) { m_autoFitItems = b; } - void setAlbumModel( AlbumModel* model ); + bool autoResize() const { return m_autoResize; } + void setAutoResize( bool b ) { m_autoResize = b; } + + void setPlayableModel( PlayableModel* model ); void setModel( QAbstractItemModel* model ); + void setEmptyTip( const QString& tip ); + virtual QWidget* widget() { return this; } virtual Tomahawk::playlistinterface_ptr playlistInterface() const { return proxyModel()->playlistInterface(); } @@ -86,26 +90,27 @@ protected slots: virtual void currentChanged( const QModelIndex& current, const QModelIndex& previous ); private slots: - void onItemCountChanged( unsigned int items ); void onFilterChanged( const QString& filter ); void onCustomContextMenu( const QPoint& pos ); -private: - void adjustItemSize( const QRect& rect ); + void layoutItems(); - AlbumModel* m_model; - AlbumProxyModel* m_proxyModel; - AlbumItemDelegate* m_delegate; +private: + PlayableModel* m_model; + PlayableProxyModel* m_proxyModel; + GridItemDelegate* m_delegate; AnimatedSpinner* m_loadingSpinner; OverlayWidget* m_overlay; QModelIndex m_contextMenuIndex; Tomahawk::ContextMenu* m_contextMenu; + QString m_emptyTip; bool m_inited; bool m_autoFitItems; + bool m_autoResize; QRect m_paintRect; }; -#endif // ALBUMVIEW_H +#endif // GRIDVIEW_H diff --git a/src/libtomahawk/playlist/PlayableModel.cpp b/src/libtomahawk/playlist/PlayableModel.cpp index 5a6206399..d068fde54 100644 --- a/src/libtomahawk/playlist/PlayableModel.cpp +++ b/src/libtomahawk/playlist/PlayableModel.cpp @@ -37,14 +37,21 @@ using namespace Tomahawk; -PlayableModel::PlayableModel( QObject* parent ) +PlayableModel::PlayableModel( QObject* parent, bool loading ) : QAbstractItemModel( parent ) , m_rootItem( new PlayableItem( 0, this ) ) , m_readOnly( true ) , m_style( Detailed ) + , m_loading( loading ) { connect( AudioEngine::instance(), SIGNAL( started( Tomahawk::result_ptr ) ), SLOT( onPlaybackStarted( Tomahawk::result_ptr ) ), Qt::DirectConnection ); connect( AudioEngine::instance(), SIGNAL( stopped() ), SLOT( onPlaybackStopped() ), Qt::DirectConnection ); + + m_header << tr( "Artist" ) << tr( "Title" ) << tr( "Composer" ) << tr( "Album" ) << tr( "Track" ) << tr( "Duration" ) + << tr( "Bitrate" ) << tr( "Age" ) << tr( "Year" ) << tr( "Size" ) << tr( "Origin" ) << tr( "Score" ) << tr( "Name" ); + + m_headerStyle[ Detailed ] << Artist << Track << Composer << Album << AlbumPos << Duration << Bitrate << Age << Year << Filesize << Origin << Score; + m_headerStyle[ Collection ] << Name << Composer << Duration << Bitrate << Age << Year << Filesize << Origin; } @@ -95,6 +102,10 @@ PlayableModel::columnCount( const QModelIndex& parent ) const return 1; break; + case Collection: + return 8; + break; + case Detailed: default: return 12; @@ -103,6 +114,20 @@ PlayableModel::columnCount( const QModelIndex& parent ) const } +bool +PlayableModel::hasChildren( const QModelIndex& parent ) const +{ + PlayableItem* parentItem = itemFromIndex( parent ); + if ( !parentItem ) + return false; + + if ( parentItem == m_rootItem ) + return true; + + return ( !parentItem->artist().isNull() || !parentItem->album().isNull() ); +} + + QModelIndex PlayableModel::parent( const QModelIndex& child ) const { @@ -124,42 +149,50 @@ PlayableModel::parent( const QModelIndex& child ) const QVariant -PlayableModel::data( const QModelIndex& index, int role ) const +PlayableModel::artistData( const artist_ptr& artist, int role ) const { - PlayableItem* entry = itemFromIndex( index ); - if ( !entry ) - return QVariant(); - - if ( role == Qt::DecorationRole ) - { - return QVariant(); - } - if ( role == Qt::SizeHintRole ) - { - return QSize( 0, 18 ); - } - - if ( role == Qt::TextAlignmentRole ) - { - return QVariant( columnAlignment( index.column() ) ); - } - - if ( role == StyleRole ) - { - return m_style; - } + return QSize( 0, 44 ); if ( role != Qt::DisplayRole ) // && role != Qt::ToolTipRole ) return QVariant(); - const query_ptr& query = entry->query()->displayQuery(); - switch( index.column() ) + return artist->name(); +} + + +QVariant +PlayableModel::albumData( const album_ptr& album, int role ) const +{ + if ( role == Qt::SizeHintRole ) + return QSize( 0, 32 ); + + if ( role != Qt::DisplayRole ) // && role != Qt::ToolTipRole ) + return QVariant(); + + return album->name(); +} + + +QVariant +PlayableModel::queryData( const query_ptr& query, int column, int role ) const +{ + if ( role == Qt::SizeHintRole ) + return QSize( 0, 18 ); + + if ( role != Qt::DisplayRole ) // && role != Qt::ToolTipRole ) + return QVariant(); + + if ( !m_headerStyle.contains( m_style ) ) + return query->track(); + + switch( m_headerStyle[ m_style ].at( column ) ) { case Artist: return query->artist(); break; + case Name: case Track: return query->track(); break; @@ -177,6 +210,7 @@ PlayableModel::data( const QModelIndex& index, int role ) const break; case AlbumPos: + { QString tPos; if ( query->albumpos() != 0 ) { @@ -187,11 +221,15 @@ PlayableModel::data( const QModelIndex& index, int role ) const return QString( "%1.%2" ).arg( QString::number( query->discnumber() ) ) .arg( tPos ); } + } + break; + + default: break; } if ( query->numResults() ) { - switch( index.column() ) + switch( m_headerStyle[ m_style ].at( column ) ) { case Bitrate: if ( query->results().first()->bitrate() > 0 ) @@ -218,6 +256,9 @@ PlayableModel::data( const QModelIndex& index, int role ) const case Score: return query->results().first()->score(); break; + + default: + break; } } @@ -225,16 +266,63 @@ PlayableModel::data( const QModelIndex& index, int role ) const } +QVariant +PlayableModel::data( const QModelIndex& index, int role ) const +{ + PlayableItem* entry = itemFromIndex( index ); + if ( !entry ) + return QVariant(); + + if ( role == Qt::DecorationRole ) + { + return QVariant(); + } + + if ( role == Qt::TextAlignmentRole ) + { + return QVariant( columnAlignment( index.column() ) ); + } + + if ( role == StyleRole ) + { + return m_style; + } + + if ( role == Qt::SizeHintRole && !m_itemSize.isEmpty() ) + { + return m_itemSize; + } + + if ( !entry->query().isNull() ) + { + return queryData( entry->query()->displayQuery(), index.column(), role ); + } + else if ( !entry->artist().isNull() ) + { + return artistData( entry->artist(), role ); + } + else if ( !entry->album().isNull() ) + { + return albumData( entry->album(), role ); + } + + return QVariant(); +} + + QVariant PlayableModel::headerData( int section, Qt::Orientation orientation, int role ) const { Q_UNUSED( orientation ); - QStringList headers; - headers << tr( "Artist" ) << tr( "Title" ) << tr( "Composer" ) << tr( "Album" ) << tr( "Track" ) << tr( "Duration" ) << tr( "Bitrate" ) << tr( "Age" ) << tr( "Year" ) << tr( "Size" ) << tr( "Origin" ) << tr( "Score" ); if ( role == Qt::DisplayRole && section >= 0 ) { - return headers.at( section ); + if ( m_headerStyle.contains( m_style ) ) + { + return m_header.at( m_headerStyle[ m_style ].at( section ) ); + } + else + return tr( "Name" ); } if ( role == Qt::TextAlignmentRole ) @@ -315,7 +403,7 @@ QStringList PlayableModel::mimeTypes() const { QStringList types; - types << "application/tomahawk.query.list"; + types << "application/tomahawk.mixed"; return types; } @@ -325,26 +413,134 @@ PlayableModel::mimeData( const QModelIndexList &indexes ) const { qDebug() << Q_FUNC_INFO; - QByteArray queryData; - QDataStream queryStream( &queryData, QIODevice::WriteOnly ); + QByteArray resultData; + QDataStream resultStream( &resultData, QIODevice::WriteOnly ); - foreach ( const QModelIndex& i, indexes ) + // lets try with artist only + bool fail = false; + foreach ( const QModelIndex& i, indexes) { - if ( i.column() > 0 ) + if ( i.column() > 0 || indexes.contains( i.parent() ) ) continue; - QModelIndex idx = index( i.row(), 0, i.parent() ); - PlayableItem* item = itemFromIndex( idx ); - if ( item ) + PlayableItem* item = itemFromIndex( i ); + if ( !item ) + continue; + + if ( !item->artist().isNull() ) + { + const artist_ptr& artist = item->artist(); + resultStream << artist->name(); + } + else + { + fail = true; + break; + } + } + if ( !fail ) + { + QMimeData* mimeData = new QMimeData(); + mimeData->setData( "application/tomahawk.metadata.artist", resultData ); + return mimeData; + } + + // lets try with album only + fail = false; + resultData.clear(); + foreach ( const QModelIndex& i, indexes ) + { + if ( i.column() > 0 || indexes.contains( i.parent() ) ) + continue; + + PlayableItem* item = itemFromIndex( i ); + if ( !item ) + continue; + + if ( !item->album().isNull() ) + { + const album_ptr& album = item->album(); + resultStream << album->artist()->name(); + resultStream << album->name(); + } + else + { + fail = true; + break; + } + } + if ( !fail ) + { + QMimeData* mimeData = new QMimeData(); + mimeData->setData( "application/tomahawk.metadata.album", resultData ); + return mimeData; + } + + // lets try with tracks only + fail = false; + resultData.clear(); + foreach ( const QModelIndex& i, indexes ) + { + if ( i.column() > 0 || indexes.contains( i.parent() ) ) + continue; + + PlayableItem* item = itemFromIndex( i ); + if ( !item ) + continue; + + if ( !item->result().isNull() ) + { + const result_ptr& result = item->result(); + resultStream << qlonglong( &result ); + } + else + { + fail = true; + break; + } + } + if ( !fail ) + { + QMimeData* mimeData = new QMimeData(); + mimeData->setData( "application/tomahawk.result.list", resultData ); + return mimeData; + } + + // Ok... we have to use mixed + resultData.clear(); + foreach ( const QModelIndex& i, indexes ) + { + if ( i.column() > 0 || indexes.contains( i.parent() ) ) + continue; + + PlayableItem* item = itemFromIndex( i ); + if ( !item ) + continue; + + if ( !item->artist().isNull() ) + { + const artist_ptr& artist = item->artist(); + resultStream << QString( "application/tomahawk.metadata.artist" ) << artist->name(); + } + else if ( !item->album().isNull() ) + { + const album_ptr& album = item->album(); + resultStream << QString( "application/tomahawk.metadata.album" ) << album->artist()->name() << album->name(); + } + else if ( !item->result().isNull() ) + { + const result_ptr& result = item->result(); + resultStream << QString( "application/tomahawk.result.list" ) << qlonglong( &result ); + } + else if ( !item->result().isNull() ) { const query_ptr& query = item->query(); - queryStream << qlonglong( &query ); + resultStream << QString( "application/tomahawk.query.list" ) << qlonglong( &query ); } } QMimeData* mimeData = new QMimeData(); - mimeData->setData( "application/tomahawk.query.list", queryData ); - + mimeData->setData( "application/tomahawk.mixed", resultData ); return mimeData; } @@ -354,7 +550,7 @@ PlayableModel::clear() { if ( rowCount( QModelIndex() ) ) { - emit loadingFinished(); + finishLoading(); emit beginResetModel(); delete m_rootItem; @@ -380,65 +576,57 @@ PlayableModel::queries() const } +template void -PlayableModel::append( const Tomahawk::query_ptr& query ) +PlayableModel::insertInternal( const T& item, int row ) { - insert( query, rowCount( QModelIndex() ) ); -} - - -void -PlayableModel::append( const QList< Tomahawk::query_ptr >& queries ) -{ - insert( queries, rowCount( QModelIndex() ) ); -} - - -void -PlayableModel::insert( const Tomahawk::query_ptr& query, int row ) -{ - if ( query.isNull() ) + if ( item.isNull() ) return; - QList< Tomahawk::query_ptr > ql; - ql << query; + QList< T > list; + list << item; - insert( ql, row ); + insert( list, row ); } +template void -PlayableModel::insert( const QList< Tomahawk::query_ptr >& queries, int row ) +PlayableModel::insertInternal( const QList< T >& items, int row ) { - if ( !queries.count() ) + if ( !items.count() ) { emit trackCountChanged( rowCount( QModelIndex() ) ); + emit itemCountChanged( rowCount( QModelIndex() ) ); + + finishLoading(); return; } int c = row; QPair< int, int > crows; crows.first = c; - crows.second = c + queries.count() - 1; + crows.second = c + items.count() - 1; emit beginInsertRows( QModelIndex(), crows.first, crows.second ); int i = 0; PlayableItem* plitem; - foreach( const query_ptr& query, queries ) + foreach( const T& item, items ) { - plitem = new PlayableItem( query, m_rootItem, row + i ); + plitem = new PlayableItem( item, m_rootItem, row + i ); plitem->index = createIndex( row + i, 0, plitem ); i++; - if ( query->id() == currentItemUuid() ) - setCurrentItem( plitem->index ); +/* if ( item->id() == currentItemUuid() ) + setCurrentItem( plitem->index );*/ connect( plitem, SIGNAL( dataChanged() ), SLOT( onDataChanged() ) ); } emit endInsertRows(); emit trackCountChanged( rowCount( QModelIndex() ) ); + finishLoading(); } @@ -508,20 +696,6 @@ PlayableModel::remove( const QList& indexes ) } -PlayableItem* -PlayableModel::itemFromIndex( const QModelIndex& index ) const -{ - if ( index.isValid() ) - { - return static_cast( index.internalPointer() ); - } - else - { - return m_rootItem; - } -} - - void PlayableModel::onPlaybackStarted( const Tomahawk::result_ptr& result ) { @@ -564,10 +738,40 @@ PlayableModel::setStyle( PlayableModel::PlayableItemStyle style ) } +QList< double > +PlayableModel::columnWeights() const +{ + QList< double > w; + + switch ( m_style ) + { + case Short: + case ShortWithAvatars: + case Large: + w << 1.0; + break; + + case Collection: + w << 0.42 << 0.12 << 0.07 << 0.07 << 0.07 << 0.07 << 0.07; // << 0.11; + break; + + case Detailed: + default: + w << 0.16 << 0.16 << 0.14 << 0.12 << 0.05 << 0.05 << 0.05 << 0.05 << 0.05 << 0.05 << 0.09; // << 0.03; + break; + } + + return w; +} + + Qt::Alignment PlayableModel::columnAlignment( int column ) const { - switch( column ) + if ( !m_headerStyle.contains( m_style ) ) + return Qt::AlignLeft; + + switch( m_headerStyle[ m_style ].at( column ) ) { case Age: case AlbumPos: @@ -591,3 +795,117 @@ PlayableModel::onDataChanged() if ( p && p->index.isValid() ) emit dataChanged( p->index, p->index.sibling( p->index.row(), columnCount() - 1 ) ); } + + +void +PlayableModel::startLoading() +{ + m_loading = true; + emit loadingStarted(); +} + + +void +PlayableModel::finishLoading() +{ + m_loading = false; + emit loadingFinished(); +} + + +PlayableItem* +PlayableModel::itemFromIndex( const QModelIndex& index ) const +{ + if ( index.isValid() ) + { + return static_cast( index.internalPointer() ); + } + else + { + return m_rootItem; + } +} + + +void +PlayableModel::append( const Tomahawk::artist_ptr& artist ) +{ + insert( artist, rowCount( QModelIndex() ) ); +} + + +void +PlayableModel::append( const Tomahawk::album_ptr& album ) +{ + insert( album, rowCount( QModelIndex() ) ); +} + + +void +PlayableModel::append( const Tomahawk::query_ptr& query ) +{ + insert( query, rowCount( QModelIndex() ) ); +} + + +void +PlayableModel::append( const QList< Tomahawk::artist_ptr >& artists ) +{ + insert( artists, rowCount( QModelIndex() ) ); +} + + +void +PlayableModel::append( const QList< Tomahawk::album_ptr >& albums ) +{ + insert( albums, rowCount( QModelIndex() ) ); +} + + +void +PlayableModel::append( const QList< Tomahawk::query_ptr >& queries ) +{ + insert( queries, rowCount( QModelIndex() ) ); +} + + +void +PlayableModel::insert( const Tomahawk::artist_ptr& artist, int row ) +{ + insertInternal( artist, row ); +} + + +void +PlayableModel::insert( const Tomahawk::album_ptr& album, int row ) +{ + insertInternal( album, row ); +} + + +void +PlayableModel::insert( const Tomahawk::query_ptr& query, int row ) +{ + insertInternal( query, row ); +} + + +void +PlayableModel::insert( const QList< Tomahawk::artist_ptr >& artists, int row ) +{ + insertInternal( artists, row ); +} + + +void +PlayableModel::insert( const QList< Tomahawk::album_ptr >& albums, int row ) +{ + insertInternal( albums, row ); +} + + +void +PlayableModel::insert( const QList< Tomahawk::query_ptr >& queries, int row ) +{ + insertInternal( queries, row ); +} diff --git a/src/libtomahawk/playlist/PlayableModel.h b/src/libtomahawk/playlist/PlayableModel.h index 7ee0f763c..1b864a575 100644 --- a/src/libtomahawk/playlist/PlayableModel.h +++ b/src/libtomahawk/playlist/PlayableModel.h @@ -22,6 +22,7 @@ #define PLAYABLEMODEL_H #include +#include #include "PlaylistInterface.h" #include "Typedefs.h" @@ -38,7 +39,7 @@ Q_OBJECT public: enum PlayableItemStyle - { Detailed = 0, Short = 1, ShortWithAvatars = 2, Large = 3 }; + { Detailed = 0, Short = 1, ShortWithAvatars = 2, Large = 3, Collection = 4 }; enum PlayableModelRole { StyleRole = Qt::UserRole + 1 }; @@ -55,10 +56,11 @@ public: Year = 8, Filesize = 9, Origin = 10, - Score = 11 + Score = 11, + Name = 12 }; - explicit PlayableModel( QObject* parent = 0 ); + explicit PlayableModel( QObject* parent = 0, bool loading = true ); virtual ~PlayableModel(); PlayableModel::PlayableItemStyle style() const { return m_style; } @@ -69,19 +71,30 @@ public: virtual bool isReadOnly() const { return m_readOnly; } virtual void setReadOnly( bool b ) { m_readOnly = b; } + virtual bool isLoading() const { return m_loading; } virtual QString title() const { return m_title; } virtual void setTitle( const QString& title ) { m_title = title; } virtual QString description() const { return m_description; } virtual void setDescription( const QString& description ) { m_description = description; } + virtual QPixmap icon() const { return m_icon; } + virtual void setIcon( const QPixmap& pixmap ) { m_icon = pixmap; } virtual int trackCount() const { return rowCount( QModelIndex() ); } + virtual int itemCount() const { return rowCount( QModelIndex() ); } virtual int rowCount( const QModelIndex& parent ) const; virtual int columnCount( const QModelIndex& parent = QModelIndex() ) const; + virtual bool hasChildren( const QModelIndex& parent ) const; + + QList< double > columnWeights() const; virtual QVariant data( const QModelIndex& index, int role = Qt::DisplayRole ) const; virtual QVariant headerData( int section, Qt::Orientation orientation, int role ) const; + + virtual QVariant artistData( const Tomahawk::artist_ptr& artist, int role = Qt::DisplayRole ) const; + virtual QVariant albumData( const Tomahawk::album_ptr& album, int role = Qt::DisplayRole ) const; + virtual QVariant queryData( const Tomahawk::query_ptr&, int column, int role = Qt::DisplayRole ) const; virtual QMimeData* mimeData( const QModelIndexList& indexes ) const; virtual QStringList mimeTypes() const; @@ -101,12 +114,19 @@ public: QList< Tomahawk::query_ptr > queries() const; void updateDetailedInfo( const QModelIndex& index ); + + QSize itemSize() const { return m_itemSize; } + void setItemSize( const QSize& size ) { m_itemSize = size; } + + void startLoading(); + void finishLoading(); signals: void repeatModeChanged( Tomahawk::PlaylistModes::RepeatMode mode ); void shuffleModeChanged( bool enabled ); void trackCountChanged( unsigned int tracks ); + void itemCountChanged( unsigned int items ); void loadingStarted(); void loadingFinished(); @@ -117,12 +137,18 @@ public slots: virtual void clear(); virtual void append( const QList< Tomahawk::query_ptr >& queries ); + virtual void append( const QList< Tomahawk::artist_ptr >& artists ); + virtual void append( const QList< Tomahawk::album_ptr >& albums ); virtual void append( const Tomahawk::query_ptr& query ); - virtual void append( const Tomahawk::artist_ptr& artist ) { Q_UNUSED( artist ); } - virtual void append( const Tomahawk::album_ptr& album ) { Q_UNUSED( album ); } + virtual void append( const Tomahawk::artist_ptr& artist ); + virtual void append( const Tomahawk::album_ptr& album ); virtual void insert( const QList< Tomahawk::query_ptr >& queries, int row = 0 ); + virtual void insert( const QList< Tomahawk::artist_ptr >& artists, int row = 0 ); + virtual void insert( const QList< Tomahawk::album_ptr >& albums, int row = 0 ); virtual void insert( const Tomahawk::query_ptr& query, int row = 0 ); + virtual void insert( const Tomahawk::artist_ptr& artist, int row = 0 ); + virtual void insert( const Tomahawk::album_ptr& album, int row = 0 ); virtual void remove( int row, bool moreToCome = false ); virtual void remove( const QModelIndex& index, bool moreToCome = false ); @@ -142,18 +168,29 @@ private slots: void onPlaybackStopped(); private: + template + void insertInternal( const QList< T >& items, int row ); + template + void insertInternal( const T& item, int row ); + Qt::Alignment columnAlignment( int column ) const; PlayableItem* m_rootItem; QPersistentModelIndex m_currentIndex; Tomahawk::QID m_currentUuid; + QSize m_itemSize; bool m_readOnly; QString m_title; QString m_description; + QPixmap m_icon; + + QHash< PlayableItemStyle, QList > m_headerStyle; + QStringList m_header; PlayableItemStyle m_style; + bool m_loading; }; #endif // PLAYABLEMODEL_H diff --git a/src/libtomahawk/playlist/PlayableProxyModel.cpp b/src/libtomahawk/playlist/PlayableProxyModel.cpp index efee2a979..783250f6c 100644 --- a/src/libtomahawk/playlist/PlayableProxyModel.cpp +++ b/src/libtomahawk/playlist/PlayableProxyModel.cpp @@ -43,6 +43,18 @@ PlayableProxyModel::PlayableProxyModel( QObject* parent ) } +bool +PlayableProxyModel::isLoading() const +{ + if ( m_model ) + { + return m_model->isLoading(); + } + + return false; +} + + void PlayableProxyModel::setSourceModel( QAbstractItemModel* model ) { @@ -55,10 +67,25 @@ PlayableProxyModel::setSourceModel( QAbstractItemModel* model ) void PlayableProxyModel::setSourcePlayableModel( PlayableModel* sourceModel ) { + if ( m_model ) + { + if ( m_model->metaObject()->indexOfSignal( "trackCountChanged(uint)" ) > -1 ) + disconnect( m_model, SIGNAL( trackCountChanged( unsigned int ) ), this, SIGNAL( sourceTrackCountChanged( unsigned int ) ) ); + + disconnect( m_model, SIGNAL( loadingStarted() ), this, SIGNAL( loadingStarted() ) ); + disconnect( m_model, SIGNAL( loadingFinished() ), this, SIGNAL( loadingFinished() ) ); + } + m_model = sourceModel; - if ( m_model && m_model->metaObject()->indexOfSignal( "trackCountChanged(uint)" ) > -1 ) - connect( m_model, SIGNAL( trackCountChanged( unsigned int ) ), playlistInterface().data(), SIGNAL( sourceTrackCountChanged( unsigned int ) ) ); + if ( m_model ) + { + if ( m_model->metaObject()->indexOfSignal( "trackCountChanged(uint)" ) > -1 ) + connect( m_model, SIGNAL( trackCountChanged( unsigned int ) ), playlistInterface().data(), SIGNAL( sourceTrackCountChanged( unsigned int ) ) ); + + connect( m_model, SIGNAL( loadingStarted() ), SIGNAL( loadingStarted() ) ); + connect( m_model, SIGNAL( loadingFinished() ), SIGNAL( loadingFinished() ) ); + } QSortFilterProxyModel::setSourceModel( m_model ); } @@ -71,32 +98,69 @@ PlayableProxyModel::filterAcceptsRow( int sourceRow, const QModelIndex& sourcePa if ( !pi ) return false; - const Tomahawk::query_ptr& q = pi->query()->displayQuery(); - if ( q.isNull() ) // uh oh? filter out invalid queries i guess - return false; - - Tomahawk::result_ptr r; - if ( q->numResults() ) - r = q->results().first(); - - if ( !m_showOfflineResults && !r.isNull() && !r->isOnline() ) - return false; - - if ( filterRegExp().isEmpty() ) - return true; - - QStringList sl = filterRegExp().pattern().split( " ", QString::SkipEmptyParts ); - foreach( QString s, sl ) + if ( pi->query() ) { - s = s.toLower(); - if ( !q->artist().toLower().contains( s ) && - !q->album().toLower().contains( s ) && - !q->track().toLower().contains( s ) ) - { + const Tomahawk::query_ptr& q = pi->query()->displayQuery(); + if ( q.isNull() ) // uh oh? filter out invalid queries i guess return false; + + Tomahawk::result_ptr r; + if ( q->numResults() ) + r = q->results().first(); + + if ( !m_showOfflineResults && !r.isNull() && !r->isOnline() ) + return false; + + if ( filterRegExp().isEmpty() ) + return true; + + QStringList sl = filterRegExp().pattern().split( " ", QString::SkipEmptyParts ); + foreach( QString s, sl ) + { + s = s.toLower(); + if ( !q->artist().toLower().contains( s ) && + !q->album().toLower().contains( s ) && + !q->track().toLower().contains( s ) ) + { + return false; + } } } + const Tomahawk::album_ptr& al = pi->album(); + if ( al ) + { + QStringList sl = filterRegExp().pattern().split( " ", QString::SkipEmptyParts ); + + bool found = true; + foreach( const QString& s, sl ) + { + if ( !al->name().contains( s, Qt::CaseInsensitive ) && !al->artist()->name().contains( s, Qt::CaseInsensitive ) ) + { + found = false; + } + } + + return found; + } + + const Tomahawk::album_ptr& ar = pi->album(); + if ( ar ) + { + QStringList sl = filterRegExp().pattern().split( " ", QString::SkipEmptyParts ); + + bool found = true; + foreach( const QString& s, sl ) + { + if ( !ar->name().contains( s, Qt::CaseInsensitive ) && !ar->artist()->name().contains( s, Qt::CaseInsensitive ) ) + { + found = false; + } + } + + return found; + } + return true; } @@ -148,32 +212,22 @@ PlayableProxyModel::remove( const QList< QPersistentModelIndex >& indexes ) bool -PlayableProxyModel::lessThan( const QModelIndex& left, const QModelIndex& right ) const +PlayableProxyModel::lessThan( int column, const Tomahawk::query_ptr& q1, const Tomahawk::query_ptr& q2 ) const { - PlayableItem* p1 = itemFromIndex( left ); - PlayableItem* p2 = itemFromIndex( right ); - - if ( !p1 ) - return true; - if ( !p2 ) - return false; - - const Tomahawk::query_ptr& q1 = p1->query()->displayQuery(); - const Tomahawk::query_ptr& q2 = p2->query()->displayQuery(); - - QString artist1 = q1->artistSortname(); - QString artist2 = q2->artistSortname(); - QString album1 = q1->albumSortname(); - QString album2 = q2->albumSortname(); - QString track1 = q1->trackSortname(); - QString track2 = q2->trackSortname(); - unsigned int albumpos1 = q1->albumpos(); - unsigned int albumpos2 = q2->albumpos(); - unsigned int discnumber1 = q1->discnumber(); - unsigned int discnumber2 = q2->discnumber(); + const QString artist1 = q1->artistSortname(); + const QString artist2 = q2->artistSortname(); + const QString album1 = q1->albumSortname(); + const QString album2 = q2->albumSortname(); + const QString track1 = q1->trackSortname(); + const QString track2 = q2->trackSortname(); + const unsigned int albumpos1 = q1->albumpos(); + const unsigned int albumpos2 = q2->albumpos(); + const unsigned int discnumber1 = q1->discnumber(); + const unsigned int discnumber2 = q2->discnumber(); unsigned int bitrate1 = 0, bitrate2 = 0; unsigned int mtime1 = 0, mtime2 = 0; unsigned int size1 = 0, size2 = 0; + float score1 = 0, score2 = 0; qint64 id1 = 0, id2 = 0; if ( q1->numResults() ) @@ -181,16 +235,18 @@ PlayableProxyModel::lessThan( const QModelIndex& left, const QModelIndex& right const Tomahawk::result_ptr& r = q1->results().at( 0 ); bitrate1 = r->bitrate(); mtime1 = r->modificationTime(); - id1 = r->trackId(); size1 = r->size(); + score1 = r->score(); + id1 = (qint64)&r; } if ( q2->numResults() ) { const Tomahawk::result_ptr& r = q2->results().at( 0 ); bitrate2 = r->bitrate(); mtime2 = r->modificationTime(); - id2 = r->trackId(); size2 = r->size(); + score2 = r->score(); + id2 = (qint64)&r; } // This makes it a stable sorter and prevents items from randomly jumping about. @@ -200,7 +256,7 @@ PlayableProxyModel::lessThan( const QModelIndex& left, const QModelIndex& right id2 = (qint64)&q2; } - if ( left.column() == PlayableModel::Artist ) // sort by artist + if ( column == PlayableModel::Artist ) // sort by artist { if ( artist1 == artist2 ) { @@ -222,7 +278,7 @@ PlayableProxyModel::lessThan( const QModelIndex& left, const QModelIndex& right return QString::localeAwareCompare( artist1, artist2 ) < 0; } - else if ( left.column() == PlayableModel::Album ) // sort by album + else if ( column == PlayableModel::Album ) // sort by album { if ( album1 == album2 ) { @@ -239,28 +295,28 @@ PlayableProxyModel::lessThan( const QModelIndex& left, const QModelIndex& right return QString::localeAwareCompare( album1, album2 ) < 0; } - else if ( left.column() == PlayableModel::Bitrate ) // sort by bitrate + else if ( column == PlayableModel::Bitrate ) // sort by bitrate { if ( bitrate1 == bitrate2 ) return id1 < id2; return bitrate1 < bitrate2; } - else if ( left.column() == PlayableModel::Age ) // sort by mtime + else if ( column == PlayableModel::Age ) // sort by mtime { if ( mtime1 == mtime2 ) return id1 < id2; return mtime1 < mtime2; } - else if ( left.column() == PlayableModel::Filesize ) // sort by file size + else if ( column == PlayableModel::Filesize ) // sort by file size { if ( size1 == size2 ) return id1 < id2; return size1 < size2; } - else if ( left.column() == PlayableModel::AlbumPos ) // sort by album pos + else if ( column == PlayableModel::AlbumPos ) // sort by album pos { if ( discnumber1 != discnumber2 ) { @@ -272,9 +328,9 @@ PlayableProxyModel::lessThan( const QModelIndex& left, const QModelIndex& right return albumpos1 < albumpos2; } } - - const QString& lefts = sourceModel()->data( left ).toString(); - const QString& rights = sourceModel()->data( right ).toString(); + + const QString& lefts = q1->track(); + const QString& rights = q2->track(); if ( lefts == rights ) return id1 < id2; @@ -282,6 +338,28 @@ PlayableProxyModel::lessThan( const QModelIndex& left, const QModelIndex& right } +bool +PlayableProxyModel::lessThan( const QModelIndex& left, const QModelIndex& right ) const +{ + PlayableItem* p1 = itemFromIndex( left ); + PlayableItem* p2 = itemFromIndex( right ); + + if ( !p1 ) + return true; + if ( !p2 ) + return false; + + if ( p1->query() && p2->query() ) + { + const Tomahawk::query_ptr& q1 = p1->query()->displayQuery(); + const Tomahawk::query_ptr& q2 = p2->query()->displayQuery(); + return lessThan( left.column(), q1, q2 ); + } + + return QString::localeAwareCompare( sourceModel()->data( left ).toString(), sourceModel()->data( right ).toString() ) < 0; +} + + Tomahawk::playlistinterface_ptr PlayableProxyModel::playlistInterface() { diff --git a/src/libtomahawk/playlist/PlayableProxyModel.h b/src/libtomahawk/playlist/PlayableProxyModel.h index 34b63c145..2e2f2b662 100644 --- a/src/libtomahawk/playlist/PlayableProxyModel.h +++ b/src/libtomahawk/playlist/PlayableProxyModel.h @@ -39,6 +39,8 @@ public: virtual void setSourcePlayableModel( PlayableModel* sourceModel ); virtual void setSourceModel( QAbstractItemModel* model ); + virtual bool isLoading() const; + virtual QPersistentModelIndex currentIndex() const { return mapFromSource( m_model->currentItem() ); } virtual void setCurrentIndex( const QModelIndex& index ) { m_model->setCurrentItem( mapToSource( index ) ); } @@ -58,13 +60,23 @@ public: signals: void filterChanged( const QString& filter ); + void filteringStarted(); + void filteringFinished(); + + void loadingStarted(); + void loadingFinished(); + protected: virtual bool filterAcceptsRow( int sourceRow, const QModelIndex& sourceParent ) const; virtual bool lessThan( const QModelIndex& left, const QModelIndex& right ) const; + Tomahawk::playlistinterface_ptr m_playlistInterface; + +private: + virtual bool lessThan( int column, const Tomahawk::query_ptr& left, const Tomahawk::query_ptr& right ) const; + PlayableModel* m_model; bool m_showOfflineResults; - Tomahawk::playlistinterface_ptr m_playlistInterface; }; #endif // TRACKPROXYMODEL_H diff --git a/src/libtomahawk/playlist/PlaylistChartItemDelegate.cpp b/src/libtomahawk/playlist/PlaylistChartItemDelegate.cpp index 638d88a4b..b36058e94 100644 --- a/src/libtomahawk/playlist/PlaylistChartItemDelegate.cpp +++ b/src/libtomahawk/playlist/PlaylistChartItemDelegate.cpp @@ -32,7 +32,7 @@ #include "PlayableItem.h" #include "PlayableProxyModel.h" #include "TrackView.h" -#include "TrackHeader.h" +#include "ViewHeader.h" #include "utils/TomahawkUtilsGui.h" #include "utils/Logger.h" diff --git a/src/libtomahawk/playlist/PlaylistItemDelegate.cpp b/src/libtomahawk/playlist/PlaylistItemDelegate.cpp index 3fa898c2f..72655c61f 100644 --- a/src/libtomahawk/playlist/PlaylistItemDelegate.cpp +++ b/src/libtomahawk/playlist/PlaylistItemDelegate.cpp @@ -32,7 +32,7 @@ #include "PlayableItem.h" #include "PlayableProxyModel.h" #include "TrackView.h" -#include "TrackHeader.h" +#include "ViewHeader.h" #include "utils/TomahawkUtilsGui.h" #include "utils/Logger.h" @@ -201,7 +201,11 @@ PlaylistItemDelegate::paintShort( QPainter* painter, const QStyleOptionViewItem& painter->drawText( r.adjusted( 0, 1, 0, 0 ), text, m_topOption ); painter->setFont( opt.font ); - painter->setPen( Qt::gray ); + if ( option.state & QStyle::State_Selected ) + painter->setPen( option.palette.color( QPalette::HighlightedText ) ); + else + painter->setPen( Qt::gray ); + text = painter->fontMetrics().elidedText( lowerText, Qt::ElideRight, r.width() ); painter->drawText( r.adjusted( 0, 1, 0, 0 ), text, m_bottomOption ); } diff --git a/src/libtomahawk/playlist/PlaylistLargeItemDelegate.cpp b/src/libtomahawk/playlist/PlaylistLargeItemDelegate.cpp index acd1fd8f0..6783a0d3e 100644 --- a/src/libtomahawk/playlist/PlaylistLargeItemDelegate.cpp +++ b/src/libtomahawk/playlist/PlaylistLargeItemDelegate.cpp @@ -33,7 +33,7 @@ #include "PlayableItem.h" #include "PlayableProxyModel.h" #include "TrackView.h" -#include "TrackHeader.h" +#include "ViewHeader.h" #include "utils/TomahawkUtilsGui.h" #include "utils/Logger.h" @@ -99,7 +99,7 @@ PlaylistLargeItemDelegate::prepareStyleOption( QStyleOptionViewItemV4* option, c void -PlaylistLargeItemDelegate::drawRichText( QPainter* painter, const QRect& rect, int flags, QTextDocument& text ) const +PlaylistLargeItemDelegate::drawRichText( QPainter* painter, const QStyleOptionViewItem& option, const QRect& rect, int flags, QTextDocument& text ) const { text.setPageSize( QSize( rect.width(), QWIDGETSIZE_MAX ) ); QAbstractTextDocumentLayout* layout = text.documentLayout(); @@ -112,7 +112,11 @@ PlaylistLargeItemDelegate::drawRichText( QPainter* painter, const QRect& rect, i y += ( rect.height() - height ) / 2; QAbstractTextDocumentLayout::PaintContext context; - context.palette.setColor( QPalette::Text, painter->pen().color() ); + + if ( option.state & QStyle::State_Selected ) + context.palette.setColor( QPalette::Text, option.palette.color( QPalette::HighlightedText ) ); + else + context.palette.setColor( QPalette::Text, painter->pen().color() ); painter->save(); painter->translate( rect.x(), y ); @@ -235,7 +239,7 @@ PlaylistLargeItemDelegate::paint( QPainter* painter, const QStyleOptionViewItem& if ( textDoc.idealWidth() > leftRect.width() ) textDoc.setHtml( item->query()->socialActionDescription( "Love", Query::Short ) ); - drawRichText( painter, leftRect, Qt::AlignBottom, textDoc ); + drawRichText( painter, option, leftRect, Qt::AlignBottom, textDoc ); if ( duration > 0 ) { diff --git a/src/libtomahawk/playlist/PlaylistLargeItemDelegate.h b/src/libtomahawk/playlist/PlaylistLargeItemDelegate.h index d6b33f076..9fed77936 100644 --- a/src/libtomahawk/playlist/PlaylistLargeItemDelegate.h +++ b/src/libtomahawk/playlist/PlaylistLargeItemDelegate.h @@ -59,7 +59,7 @@ private slots: private: void prepareStyleOption( QStyleOptionViewItemV4* option, const QModelIndex& index, PlayableItem* item ) const; - void drawRichText( QPainter* painter, const QRect& rect, int flags, QTextDocument& text ) const; + void drawRichText( QPainter* painter, const QStyleOptionViewItem& option, const QRect& rect, int flags, QTextDocument& text ) const; QTextOption m_topOption; QTextOption m_centerRightOption; diff --git a/src/libtomahawk/playlist/PlaylistModel.cpp b/src/libtomahawk/playlist/PlaylistModel.cpp index 5ed5241bb..7eae940c9 100644 --- a/src/libtomahawk/playlist/PlaylistModel.cpp +++ b/src/libtomahawk/playlist/PlaylistModel.cpp @@ -84,6 +84,7 @@ PlaylistModel::loadPlaylist( const Tomahawk::playlist_ptr& playlist, bool loadEn .arg( TomahawkUtils::ageToString( QDateTime::fromTime_t( playlist->createdOn() ), true ) ) ); m_isTemporary = false; + emit playlistChanged(); if ( !loadEntries ) { @@ -92,8 +93,6 @@ PlaylistModel::loadPlaylist( const Tomahawk::playlist_ptr& playlist, bool loadEn } QList entries = playlist->entries(); - - qDebug() << "playlist loading entries:"; foreach( const plentry_ptr& p, entries ) qDebug() << p->guid() << p->query()->track() << p->query()->artist(); @@ -211,6 +210,7 @@ PlaylistModel::insert( const QList< Tomahawk::plentry_ptr >& entries, int row ) if ( !entries.count() ) { emit trackCountChanged( rowCount( QModelIndex() ) ); + finishLoading(); return; } @@ -257,6 +257,7 @@ PlaylistModel::insert( const QList< Tomahawk::plentry_ptr >& entries, int row ) emit endInsertRows(); emit trackCountChanged( rowCount( QModelIndex() ) ); + finishLoading(); } diff --git a/src/libtomahawk/playlist/PlaylistProxyModel.cpp b/src/libtomahawk/playlist/PlaylistProxyModel.cpp deleted file mode 100644 index b9d7ccb7e..000000000 --- a/src/libtomahawk/playlist/PlaylistProxyModel.cpp +++ /dev/null @@ -1,40 +0,0 @@ -/* === This file is part of Tomahawk Player - === - * - * Copyright 2010-2011, Christian Muehlhaeuser - * Copyright 2010-2012, Jeff Mitchell - * - * Tomahawk is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Tomahawk is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Tomahawk. If not, see . - */ - -#include "PlaylistProxyModel.h" - -#include "PlaylistProxyModelPlaylistInterface.h" -#include "utils/Logger.h" - - -PlaylistProxyModel::PlaylistProxyModel( QObject* parent ) - : PlayableProxyModel( parent ) -{ -} - -Tomahawk::playlistinterface_ptr -PlaylistProxyModel::playlistInterface() -{ - if ( m_playlistInterface.isNull() ) - { - m_playlistInterface = Tomahawk::playlistinterface_ptr( new Tomahawk::PlaylistProxyModelPlaylistInterface( this ) ); - } - - return m_playlistInterface; -} diff --git a/src/libtomahawk/playlist/PlaylistProxyModelPlaylistInterface.cpp b/src/libtomahawk/playlist/PlaylistProxyModelPlaylistInterface.cpp deleted file mode 100644 index ce06675d2..000000000 --- a/src/libtomahawk/playlist/PlaylistProxyModelPlaylistInterface.cpp +++ /dev/null @@ -1,35 +0,0 @@ -/* === This file is part of Tomahawk Player - === - * - * Copyright 2010-2011, Christian Muehlhaeuser - * Copyright 2010-2011, Jeff Mitchell - * - * Tomahawk is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Tomahawk is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Tomahawk. If not, see . - */ - -#include "PlaylistProxyModelPlaylistInterface.h" - -#include "PlaylistProxyModel.h" -#include "utils/Logger.h" - -using namespace Tomahawk; - -PlaylistProxyModelPlaylistInterface::PlaylistProxyModelPlaylistInterface( PlaylistProxyModel *proxyModel ) - : PlayableProxyModelPlaylistInterface( proxyModel ) -{ -} - -PlaylistProxyModelPlaylistInterface::~PlaylistProxyModelPlaylistInterface() -{ - m_proxyModel.clear(); -} diff --git a/src/libtomahawk/playlist/PlaylistProxyModelPlaylistInterface.h b/src/libtomahawk/playlist/PlaylistProxyModelPlaylistInterface.h deleted file mode 100644 index 29888c0bf..000000000 --- a/src/libtomahawk/playlist/PlaylistProxyModelPlaylistInterface.h +++ /dev/null @@ -1,43 +0,0 @@ -/* === This file is part of Tomahawk Player - === - * - * Copyright 2010-2011, Christian Muehlhaeuser - * Copyright 2010-2011, Jeff Mitchell - * - * Tomahawk is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Tomahawk is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Tomahawk. If not, see . - */ - -#ifndef PLAYLISTPROXYMODELPLAYLISTINTERFACE_H -#define PLAYLISTPROXYMODELPLAYLISTINTERFACE_H - -#include "PlayableProxyModelPlaylistInterface.h" - -#include "DllMacro.h" - -class PlaylistProxyModel; - -namespace Tomahawk -{ - -class DLLEXPORT PlaylistProxyModelPlaylistInterface : public PlayableProxyModelPlaylistInterface -{ -Q_OBJECT - -public: - explicit PlaylistProxyModelPlaylistInterface( PlaylistProxyModel *proxyModel ); - virtual ~PlaylistProxyModelPlaylistInterface(); -}; - -} //ns - -#endif // PLAYLISTPROXYMODELPLAYLISTINTERFACE_H diff --git a/src/libtomahawk/playlist/PlaylistUpdaterInterface.h b/src/libtomahawk/playlist/PlaylistUpdaterInterface.h index b05621995..0776451bd 100644 --- a/src/libtomahawk/playlist/PlaylistUpdaterInterface.h +++ b/src/libtomahawk/playlist/PlaylistUpdaterInterface.h @@ -71,6 +71,8 @@ public: static void registerUpdaterFactory( PlaylistUpdaterFactory* f ); + virtual bool sync() const { return true; } + signals: void changed(); diff --git a/src/libtomahawk/playlist/PlaylistView.cpp b/src/libtomahawk/playlist/PlaylistView.cpp index 3fb6f7426..ef62eca80 100644 --- a/src/libtomahawk/playlist/PlaylistView.cpp +++ b/src/libtomahawk/playlist/PlaylistView.cpp @@ -22,11 +22,10 @@ #include #include -#include "playlist/PlaylistProxyModel.h" -#include "widgets/OverlayWidget.h" #include "ViewManager.h" #include "utils/Logger.h" #include "PlaylistUpdaterInterface.h" +#include "Source.h" using namespace Tomahawk; @@ -35,8 +34,6 @@ PlaylistView::PlaylistView( QWidget* parent ) : TrackView( parent ) , m_model( 0 ) { - setProxyModel( new PlaylistProxyModel( this ) ); - connect( contextMenu(), SIGNAL( triggered( int ) ), SLOT( onMenuTriggered( int ) ) ); } @@ -77,7 +74,6 @@ PlaylistView::setPlaylistModel( PlaylistModel* model ) } } - connect( m_model, SIGNAL( trackCountChanged( unsigned int ) ), SLOT( onTrackCountChanged( unsigned int ) ) ); connect( m_model, SIGNAL( playlistDeleted() ), SLOT( onDeleted() ) ); connect( m_model, SIGNAL( playlistChanged() ), SLOT( onChanged() ) ); @@ -88,7 +84,6 @@ PlaylistView::setPlaylistModel( PlaylistModel* model ) void PlaylistView::keyPressEvent( QKeyEvent* event ) { - qDebug() << Q_FUNC_INFO; TrackView::keyPressEvent( event ); if ( !model() ) @@ -102,6 +97,38 @@ PlaylistView::keyPressEvent( QKeyEvent* event ) } +bool +PlaylistView::eventFilter( QObject* obj, QEvent* event ) +{ + if ( event->type() == QEvent::DragEnter ) + { + QDragEnterEvent* e = static_cast(event); + dragEnterEvent( e ); + return true; + } + if ( event->type() == QEvent::DragMove ) + { + QDragMoveEvent* e = static_cast(event); + dragMoveEvent( e ); + return true; + } + if ( event->type() == QEvent::DragLeave ) + { + QDragLeaveEvent* e = static_cast(event); + dragLeaveEvent( e ); + return true; + } + if ( event->type() == QEvent::Drop ) + { + QDropEvent* e = static_cast(event); + dropEvent( e ); + return true; + } + + return QObject::eventFilter( obj, event ); +} + + void PlaylistView::deleteItems() { @@ -119,27 +146,6 @@ PlaylistView::updaters() const } -void -PlaylistView::onTrackCountChanged( unsigned int tracks ) -{ - if ( tracks == 0 ) - { - overlay()->setText( tr( "This playlist is currently empty. Add some tracks to it and enjoy the music!" ) ); - overlay()->show(); - } - else - overlay()->hide(); -} - - -bool -PlaylistView::jumpToCurrentTrack() -{ - scrollTo( proxyModel()->currentIndex(), QAbstractItemView::PositionAtCenter ); - return true; -} - - void PlaylistView::onDeleted() { @@ -151,9 +157,17 @@ PlaylistView::onDeleted() void PlaylistView::onChanged() { - if ( m_model && !m_model->playlist().isNull() && - ViewManager::instance()->currentPage() == this ) - emit nameChanged( m_model->playlist()->title() ); + if ( m_model ) + { + if ( m_model->isReadOnly() ) + setEmptyTip( tr( "This playlist is currently empty." ) ); + else + setEmptyTip( tr( "This playlist is currently empty. Add some tracks to it and enjoy the music!" ) ); + m_model->finishLoading(); + + if ( !m_model->playlist().isNull() && ViewManager::instance()->currentPage() == this ) + emit nameChanged( m_model->playlist()->title() ); + } } @@ -174,7 +188,6 @@ PlaylistView::onMenuTriggered( int action ) break; default: - TrackView::onMenuTriggered( action ); break; } } diff --git a/src/libtomahawk/playlist/PlaylistView.h b/src/libtomahawk/playlist/PlaylistView.h index 34633ee1e..14140f4ad 100644 --- a/src/libtomahawk/playlist/PlaylistView.h +++ b/src/libtomahawk/playlist/PlaylistView.h @@ -26,7 +26,7 @@ #include "ViewPage.h" #include "DllMacro.h" -class DLLEXPORT PlaylistView : public TrackView, public Tomahawk::ViewPage +class DLLEXPORT PlaylistView : public TrackView { Q_OBJECT @@ -38,17 +38,9 @@ public: virtual void setPlaylistModel( PlaylistModel* model ); virtual void setModel( QAbstractItemModel* model ); - virtual QWidget* widget() { return this; } - virtual Tomahawk::playlistinterface_ptr playlistInterface() const { return proxyModel()->playlistInterface(); } - - virtual bool showFilter() const { return true; } - virtual QList updaters() const; - virtual QString title() const { return playlistModel()->title(); } - virtual QString description() const { return m_model->description(); } virtual QPixmap pixmap() const { return QPixmap( RESPATH "images/playlist-icon.png" ); } - virtual bool jumpToCurrentTrack(); virtual bool isTemporaryPage() const; signals: @@ -58,9 +50,9 @@ signals: protected: void keyPressEvent( QKeyEvent* event ); + bool eventFilter( QObject* obj, QEvent* event ); private slots: - void onTrackCountChanged( unsigned int tracks ); void onMenuTriggered( int action ); void deleteItems(); diff --git a/src/libtomahawk/playlist/QueueProxyModel.cpp b/src/libtomahawk/playlist/QueueProxyModel.cpp index b1821c68c..e544eb645 100644 --- a/src/libtomahawk/playlist/QueueProxyModel.cpp +++ b/src/libtomahawk/playlist/QueueProxyModel.cpp @@ -19,22 +19,22 @@ #include "QueueProxyModel.h" -#include "QueueProxyModelPlaylistInterface.h" +#include "audio/AudioEngine.h" #include "playlist/TrackView.h" +#include "PlayableItem.h" #include "ViewManager.h" -#include "utils/Logger.h" #include "Source.h" +#include "utils/Logger.h" using namespace Tomahawk; QueueProxyModel::QueueProxyModel( TrackView* parent ) - : PlaylistProxyModel( parent ) + : PlayableProxyModel( parent ) { - qDebug() << Q_FUNC_INFO; - - connect( parent, SIGNAL( itemActivated( QModelIndex ) ), this, SLOT( onIndexActivated( QModelIndex ) ) ); - connect( playlistInterface().data(), SIGNAL( sourceTrackCountChanged( unsigned int ) ), this, SLOT( onTrackCountChanged( unsigned int ) ) ); + connect( parent, SIGNAL( itemActivated( QModelIndex ) ), SLOT( onIndexActivated( QModelIndex ) ) ); + connect( playlistInterface().data(), SIGNAL( sourceTrackCountChanged( unsigned int ) ), SLOT( onTrackCountChanged( unsigned int ) ) ); + connect( AudioEngine::instance(), SIGNAL( loading( Tomahawk::result_ptr ) ), SLOT( onPlaybackStarted( Tomahawk::result_ptr ) ) ); } @@ -43,6 +43,19 @@ QueueProxyModel::~QueueProxyModel() } +void +QueueProxyModel::onPlaybackStarted( const Tomahawk::result_ptr& result ) +{ + for ( int i = 0; i < rowCount(); i++ ) + { + QModelIndex idx = index( i, 0 ); + PlayableItem* item = itemFromIndex( mapToSource( idx ) ); + if ( item && item->query() && item->query()->equals( result->toQuery() ) ) + remove( idx ); + } +} + + void QueueProxyModel::onIndexActivated( const QModelIndex& index ) { @@ -57,15 +70,3 @@ QueueProxyModel::onTrackCountChanged( unsigned int count ) if ( count == 0 ) ViewManager::instance()->hideQueue(); } - - -Tomahawk::playlistinterface_ptr -QueueProxyModel::playlistInterface() -{ - if ( m_playlistInterface.isNull() ) - { - m_playlistInterface = Tomahawk::playlistinterface_ptr( new Tomahawk::QueueProxyModelPlaylistInterface( this ) ); - } - - return m_playlistInterface; -} diff --git a/src/libtomahawk/playlist/QueueProxyModel.h b/src/libtomahawk/playlist/QueueProxyModel.h index 8156d8df3..3c39a68dc 100644 --- a/src/libtomahawk/playlist/QueueProxyModel.h +++ b/src/libtomahawk/playlist/QueueProxyModel.h @@ -20,14 +20,14 @@ #ifndef QUEUEPROXYMODEL_H #define QUEUEPROXYMODEL_H -#include "PlaylistProxyModel.h" +#include "PlayableProxyModel.h" #include "DllMacro.h" class QMetaData; class TrackView; -class DLLEXPORT QueueProxyModel : public PlaylistProxyModel +class DLLEXPORT QueueProxyModel : public PlayableProxyModel { Q_OBJECT @@ -35,11 +35,10 @@ public: explicit QueueProxyModel( TrackView* parent = 0 ); virtual ~QueueProxyModel(); - virtual Tomahawk::playlistinterface_ptr playlistInterface(); - private slots: void onIndexActivated( const QModelIndex& index ); void onTrackCountChanged( unsigned int count ); + void onPlaybackStarted( const Tomahawk::result_ptr& result ); }; #endif // QUEUEPROXYMODEL_H diff --git a/src/libtomahawk/playlist/QueueProxyModelPlaylistInterface.cpp b/src/libtomahawk/playlist/QueueProxyModelPlaylistInterface.cpp deleted file mode 100644 index 25f94cd78..000000000 --- a/src/libtomahawk/playlist/QueueProxyModelPlaylistInterface.cpp +++ /dev/null @@ -1,51 +0,0 @@ -/* === This file is part of Tomahawk Player - === - * - * Copyright 2010-2011, Christian Muehlhaeuser - * Copyright 2010-2011, Jeff Mitchell - * - * Tomahawk is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Tomahawk is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Tomahawk. If not, see . - */ - -#include "QueueProxyModelPlaylistInterface.h" - -#include "QueueProxyModel.h" -#include "utils/Logger.h" - -using namespace Tomahawk; - -QueueProxyModelPlaylistInterface::QueueProxyModelPlaylistInterface( QueueProxyModel *proxyModel ) - : PlaylistProxyModelPlaylistInterface( proxyModel ) -{ -} - - -QueueProxyModelPlaylistInterface::~QueueProxyModelPlaylistInterface() -{ - m_proxyModel.clear(); -} - - -Tomahawk::result_ptr -QueueProxyModelPlaylistInterface::siblingItem( int itemsAway ) -{ - if ( m_proxyModel.isNull() ) - return Tomahawk::result_ptr(); - - m_proxyModel.data()->setCurrentIndex( QModelIndex() ); - Tomahawk::result_ptr res = PlaylistProxyModelPlaylistInterface::siblingItem( itemsAway ); - - m_proxyModel.data()->remove( m_proxyModel.data()->currentIndex() ); - - return res; -} diff --git a/src/libtomahawk/playlist/QueueProxyModelPlaylistInterface.h b/src/libtomahawk/playlist/QueueProxyModelPlaylistInterface.h deleted file mode 100644 index 12540f2ff..000000000 --- a/src/libtomahawk/playlist/QueueProxyModelPlaylistInterface.h +++ /dev/null @@ -1,46 +0,0 @@ -/* === This file is part of Tomahawk Player - === - * - * Copyright 2010-2011, Christian Muehlhaeuser - * Copyright 2010-2011, Jeff Mitchell - * - * Tomahawk is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Tomahawk is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Tomahawk. If not, see . - */ - -#ifndef QUEUEPROXYMODELPLAYLISTINTERFACE_H -#define QUEUEPROXYMODELPLAYLISTINTERFACE_H - -#include "PlaylistProxyModelPlaylistInterface.h" - -#include "Result.h" -#include "DllMacro.h" - -class QueueProxyModel; - -namespace Tomahawk -{ - -class DLLEXPORT QueueProxyModelPlaylistInterface : public PlaylistProxyModelPlaylistInterface -{ -Q_OBJECT - -public: - explicit QueueProxyModelPlaylistInterface( QueueProxyModel *proxyModel ); - virtual ~QueueProxyModelPlaylistInterface(); - - virtual Tomahawk::result_ptr siblingItem( int itemsAway ); -}; - -} //ns - -#endif // QUEUEPROXYMODELPLAYLISTINTERFACE_H diff --git a/src/libtomahawk/playlist/QueueView.cpp b/src/libtomahawk/playlist/QueueView.cpp index 1134f21e0..e939e2b6d 100644 --- a/src/libtomahawk/playlist/QueueView.cpp +++ b/src/libtomahawk/playlist/QueueView.cpp @@ -23,11 +23,11 @@ #include "widgets/HeaderLabel.h" #include "playlist/QueueProxyModel.h" -#include "widgets/OverlayWidget.h" #include "utils/Logger.h" #include "PlaylistView.h" #include "Source.h" #include "utils/TomahawkUtilsGui.h" +#include "widgets/OverlayWidget.h" using namespace Tomahawk; @@ -45,13 +45,22 @@ QueueView::QueueView( AnimatedSplitter* parent ) ui->queue->setProxyModel( new QueueProxyModel( ui->queue ) ); ui->queue->setSizePolicy( QSizePolicy::Preferred, QSizePolicy::Ignored ); - ui->queue->setFrameShape( QFrame::NoFrame ); - ui->queue->setAttribute( Qt::WA_MacShowFocusRect, 0 ); - ui->queue->overlay()->setEnabled( false ); + PlaylistModel* queueModel = new PlaylistModel( this ); + queueModel->setStyle( PlaylistModel::Short ); + queueModel->finishLoading(); + ui->queue->setPlaylistModel( queueModel ); + queueModel->setReadOnly( false ); + +// ui->queue->setEmptyTip( tr( "The queue is currently empty. Drop something to enqueue it!" ) ); + ui->queue->setEmptyTip( QString() ); + + connect( queueModel, SIGNAL( trackCountChanged( unsigned int ) ), SLOT( updateLabel() ) ); connect( ui->toggleButton, SIGNAL( clicked() ), SLOT( show() ) ); + connect( this, SIGNAL( animationFinished() ), SLOT( onAnimationFinished() ) ); ui->toggleButton->installEventFilter( this ); + ui->toggleButton->setCursor( Qt::PointingHandCursor ); } @@ -118,8 +127,11 @@ QueueView::hide() { disconnect( ui->toggleButton, SIGNAL( clicked() ), this, SLOT( hide() ) ); connect( ui->toggleButton, SIGNAL( clicked() ), SLOT( show() ) ); - ui->toggleButton->setText( tr( "Show Queue" ) ); - emit hideWidget(); + disconnect( ui->toggleButton, SIGNAL( resized( QPoint ) ), this, SIGNAL( resizeBy( QPoint ) ) ); + + ui->queue->overlay()->setVisible( false ); + AnimatedWidget::hide(); + updateLabel(); } @@ -128,8 +140,11 @@ QueueView::show() { disconnect( ui->toggleButton, SIGNAL( clicked() ), this, SLOT( show() ) ); connect( ui->toggleButton, SIGNAL( clicked() ), SLOT( hide() ) ); - ui->toggleButton->setText( tr( "Hide Queue" ) ); - emit showWidget(); + connect( ui->toggleButton, SIGNAL( resized( QPoint ) ), SIGNAL( resizeBy( QPoint ) ) ); + + ui->queue->overlay()->setVisible( false ); + AnimatedWidget::show(); + updateLabel(); } @@ -151,3 +166,29 @@ QueueView::onHidden( QWidget* widget, bool animated ) AnimatedWidget::onHidden( widget, animated ); } + + +void +QueueView::onAnimationFinished() +{ + ui->queue->overlay()->setVisible( true ); +} + + +void +QueueView::updateLabel() +{ + if ( isHidden() ) + { + const unsigned int c = queue()->model()->rowCount( QModelIndex() ); + + if ( c ) + ui->toggleButton->setText( tr( "Open Queue - %n item(s)", "", c ) ); + else + ui->toggleButton->setText( tr( "Open Queue" ) ); + } + else + { + ui->toggleButton->setText( tr( "Close Queue" ) ); + } +} diff --git a/src/libtomahawk/playlist/QueueView.h b/src/libtomahawk/playlist/QueueView.h index 49952dc37..ce8ef7eae 100644 --- a/src/libtomahawk/playlist/QueueView.h +++ b/src/libtomahawk/playlist/QueueView.h @@ -57,6 +57,10 @@ public slots: protected: void changeEvent( QEvent* e ); +private slots: + void updateLabel(); + void onAnimationFinished(); + private: Ui::QueueView* ui; QTimer* m_dragTimer; diff --git a/src/libtomahawk/playlist/QueueView.ui b/src/libtomahawk/playlist/QueueView.ui index e9e318b12..fba21c5b1 100644 --- a/src/libtomahawk/playlist/QueueView.ui +++ b/src/libtomahawk/playlist/QueueView.ui @@ -38,7 +38,7 @@ true - Show Queue + Open Queue Qt::AlignCenter diff --git a/src/libtomahawk/playlist/RecentlyPlayedModel.cpp b/src/libtomahawk/playlist/RecentlyPlayedModel.cpp index a61c92431..5902ee44a 100644 --- a/src/libtomahawk/playlist/RecentlyPlayedModel.cpp +++ b/src/libtomahawk/playlist/RecentlyPlayedModel.cpp @@ -68,6 +68,7 @@ RecentlyPlayedModel::loadHistory() { clear(); } + loadingStarted(); DatabaseCommand_PlaybackHistory* cmd = new DatabaseCommand_PlaybackHistory( m_source ); cmd->setLimit( m_limit ); diff --git a/src/libtomahawk/playlist/TrackHeader.cpp b/src/libtomahawk/playlist/TrackHeader.cpp deleted file mode 100644 index 74ccf1ff2..000000000 --- a/src/libtomahawk/playlist/TrackHeader.cpp +++ /dev/null @@ -1,39 +0,0 @@ -/* === This file is part of Tomahawk Player - === - * - * Copyright 2010-2011, Christian Muehlhaeuser - * Copyright 2010-2011, Jeff Mitchell - * - * Tomahawk is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Tomahawk is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Tomahawk. If not, see . - */ - -#include "TrackHeader.h" - -#include "playlist/TrackView.h" -#include "utils/Logger.h" - - -TrackHeader::TrackHeader( TrackView* parent ) - : ViewHeader( parent ) - , m_parent( parent ) -{ - QList< double > columnWeights; - columnWeights << 0.16 << 0.16 << 0.14 << 0.12 << 0.05 << 0.05 << 0.05 << 0.05 << 0.05 << 0.05 << 0.09; // << 0.03; - - setDefaultColumnWeights( columnWeights ); -} - - -TrackHeader::~TrackHeader() -{ -} diff --git a/src/libtomahawk/playlist/TrackHeader.h b/src/libtomahawk/playlist/TrackHeader.h deleted file mode 100644 index 2c472dcfd..000000000 --- a/src/libtomahawk/playlist/TrackHeader.h +++ /dev/null @@ -1,40 +0,0 @@ -/* === This file is part of Tomahawk Player - === - * - * Copyright 2010-2011, Christian Muehlhaeuser - * Copyright 2010-2011, Jeff Mitchell - * - * Tomahawk is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Tomahawk is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Tomahawk. If not, see . - */ - -#ifndef TRACKHEADER_H -#define TRACKHEADER_H - -#include "ViewHeader.h" -#include "DllMacro.h" - -class TrackView; - -class DLLEXPORT TrackHeader : public ViewHeader -{ -Q_OBJECT - -public: - explicit TrackHeader( TrackView* parent = 0 ); - ~TrackHeader(); - -private: - TrackView* m_parent; -}; - -#endif diff --git a/src/libtomahawk/playlist/TrackView.cpp b/src/libtomahawk/playlist/TrackView.cpp index 9bbc109ff..418d92827 100644 --- a/src/libtomahawk/playlist/TrackView.cpp +++ b/src/libtomahawk/playlist/TrackView.cpp @@ -23,7 +23,7 @@ #include #include -#include "TrackHeader.h" +#include "ViewHeader.h" #include "ViewManager.h" #include "PlayableModel.h" #include "PlayableProxyModel.h" @@ -31,12 +31,13 @@ #include "audio/AudioEngine.h" #include "context/ContextWidget.h" #include "widgets/OverlayWidget.h" -#include "utils/TomahawkUtils.h" +#include "utils/TomahawkUtilsGui.h" #include "utils/Logger.h" #include "utils/Closure.h" #include "DropJob.h" #include "Artist.h" #include "Album.h" +#include "Source.h" #include "utils/AnimatedSpinner.h" #define SCROLL_TIMEOUT 280 @@ -49,14 +50,18 @@ TrackView::TrackView( QWidget* parent ) , m_model( 0 ) , m_proxyModel( 0 ) , m_delegate( 0 ) - , m_header( new TrackHeader( this ) ) + , m_header( new ViewHeader( this ) ) , m_overlay( new OverlayWidget( this ) ) - , m_loadingSpinner( new AnimatedSpinner( this ) ) + , m_loadingSpinner( new LoadingSpinner( this ) ) , m_resizing( false ) , m_dragging( false ) , m_updateContextView( true ) , m_contextMenu( new ContextMenu( this ) ) { + setFrameShape( QFrame::NoFrame ); + setAttribute( Qt::WA_MacShowFocusRect, 0 ); + + setContentsMargins( 0, 0, 0, 0 ); setMouseTracking( true ); setAlternatingRowColors( true ); setSelectionMode( QAbstractItemView::ExtendedSelection ); @@ -94,6 +99,8 @@ TrackView::TrackView( QWidget* parent ) connect( this, SIGNAL( doubleClicked( QModelIndex ) ), SLOT( onItemActivated( QModelIndex ) ) ); connect( this, SIGNAL( customContextMenuRequested( const QPoint& ) ), SLOT( onCustomContextMenu( const QPoint& ) ) ); connect( m_contextMenu, SIGNAL( triggered( int ) ), SLOT( onMenuTriggered( int ) ) ); + + setProxyModel( new PlayableProxyModel( this ) ); } @@ -142,13 +149,11 @@ TrackView::setPlayableModel( PlayableModel* model ) m_proxyModel->setSourcePlayableModel( m_model ); } - connect( m_model, SIGNAL( loadingStarted() ), m_loadingSpinner, SLOT( fadeIn() ) ); - connect( m_model, SIGNAL( loadingFinished() ), m_loadingSpinner, SLOT( fadeOut() ) ); - connect( m_proxyModel, SIGNAL( filterChanged( QString ) ), SLOT( onFilterChanged( QString ) ) ); connect( m_proxyModel, SIGNAL( rowsInserted( QModelIndex, int, int ) ), SLOT( onViewChanged() ) ); setAcceptDrops( true ); + m_header->setDefaultColumnWeights( model->columnWeights() ); switch( model->style() ) { @@ -163,6 +168,16 @@ TrackView::setPlayableModel( PlayableModel* model ) setHeaderHidden( false ); setHorizontalScrollBarPolicy( Qt::ScrollBarAsNeeded ); } + + emit modelChanged(); +} + + +void +TrackView::setEmptyTip( const QString& tip ) +{ + m_emptyTip = tip; + m_overlay->setText( tip ); } @@ -494,8 +509,17 @@ TrackView::onFilterChanged( const QString& ) m_overlay->show(); } else + { if ( model()->trackCount() ) + { m_overlay->hide(); + } + else + { + m_overlay->setText( m_emptyTip ); + m_overlay->show(); + } + } } @@ -697,3 +721,39 @@ TrackView::mousePressEvent( QMouseEvent* event ) } } } + + +Tomahawk::playlistinterface_ptr +TrackView::playlistInterface() const +{ + return proxyModel()->playlistInterface(); +} + + +QString +TrackView::title() const +{ + return model()->title(); +} + + +QString +TrackView::description() const +{ + return model()->description(); +} + + +QPixmap +TrackView::pixmap() const +{ + return QPixmap( RESPATH "images/music-icon.png" ); +} + + +bool +TrackView::jumpToCurrentTrack() +{ + scrollTo( proxyModel()->currentIndex(), QAbstractItemView::PositionAtCenter ); + return true; +} diff --git a/src/libtomahawk/playlist/TrackView.h b/src/libtomahawk/playlist/TrackView.h index 7ff314656..24f119a7e 100644 --- a/src/libtomahawk/playlist/TrackView.h +++ b/src/libtomahawk/playlist/TrackView.h @@ -26,17 +26,18 @@ #include "ContextMenu.h" #include "PlaylistItemDelegate.h" +#include "ViewPage.h" #include "DllMacro.h" class QAction; class AnimatedSpinner; -class TrackHeader; +class ViewHeader; class PlayableModel; class PlayableProxyModel; class OverlayWidget; -class DLLEXPORT TrackView : public QTreeView +class DLLEXPORT TrackView : public QTreeView, public Tomahawk::ViewPage { Q_OBJECT @@ -54,11 +55,25 @@ public: virtual PlayableModel* model() const { return m_model; } PlayableProxyModel* proxyModel() const { return m_proxyModel; } PlaylistItemDelegate* delegate() const { return m_delegate; } - TrackHeader* header() const { return m_header; } + ViewHeader* header() const { return m_header; } OverlayWidget* overlay() const { return m_overlay; } Tomahawk::ContextMenu* contextMenu() const { return m_contextMenu; } AnimatedSpinner* loadingSpinner() const { return m_loadingSpinner; } + void setEmptyTip( const QString& tip ); + + virtual QWidget* widget() { return this; } + virtual Tomahawk::playlistinterface_ptr playlistInterface() const; + + virtual QString title() const; + virtual QString description() const; + virtual QPixmap pixmap() const; + + virtual bool showModes() const { return true; } + virtual bool showFilter() const { return true; } + + virtual bool jumpToCurrentTrack(); + QModelIndex hoveredIndex() const { return m_hoveredIndex; } QModelIndex contextMenuIndex() const { return m_contextMenuIndex; } void setContextMenuIndex( const QModelIndex& idx ) { m_contextMenuIndex = idx; } @@ -80,6 +95,7 @@ public slots: signals: void itemActivated( const QModelIndex& index ); + void modelChanged(); protected: virtual void resizeEvent( QResizeEvent* event ); @@ -117,10 +133,11 @@ private: PlayableModel* m_model; PlayableProxyModel* m_proxyModel; PlaylistItemDelegate* m_delegate; - TrackHeader* m_header; + ViewHeader* m_header; OverlayWidget* m_overlay; AnimatedSpinner* m_loadingSpinner; + QString m_emptyTip; bool m_resizing; bool m_dragging; QRect m_dropRect; @@ -131,7 +148,6 @@ private: QModelIndex m_contextMenuIndex; Tomahawk::query_ptr m_autoPlaying; - Tomahawk::ContextMenu* m_contextMenu; QTimer m_timer; diff --git a/src/libtomahawk/playlist/TreeHeader.cpp b/src/libtomahawk/playlist/TreeHeader.cpp deleted file mode 100644 index 4aeccd17d..000000000 --- a/src/libtomahawk/playlist/TreeHeader.cpp +++ /dev/null @@ -1,39 +0,0 @@ -/* === This file is part of Tomahawk Player - === - * - * Copyright 2010-2011, Christian Muehlhaeuser - * - * Tomahawk is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Tomahawk is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Tomahawk. If not, see . - */ - -#include "TreeHeader.h" - -#include "playlist/ArtistView.h" -#include "utils/Logger.h" -#include "Source.h" - - -TreeHeader::TreeHeader( ArtistView* parent ) - : ViewHeader( parent ) - , m_parent( parent ) -{ - QList< double > columnWeights; - columnWeights << 0.42 << 0.12 << 0.07 << 0.07 << 0.07 << 0.07 << 0.07; // << 0.11; - - setDefaultColumnWeights( columnWeights ); -} - - -TreeHeader::~TreeHeader() -{ -} diff --git a/src/libtomahawk/playlist/TreeHeader.h b/src/libtomahawk/playlist/TreeHeader.h deleted file mode 100644 index d80cf872c..000000000 --- a/src/libtomahawk/playlist/TreeHeader.h +++ /dev/null @@ -1,39 +0,0 @@ -/* === This file is part of Tomahawk Player - === - * - * Copyright 2010-2011, Christian Muehlhaeuser - * - * Tomahawk is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Tomahawk is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Tomahawk. If not, see . - */ - -#ifndef TREEHEADER_H -#define TREEHEADER_H - -#include "ViewHeader.h" -#include "DllMacro.h" - -class ArtistView; - -class DLLEXPORT TreeHeader : public ViewHeader -{ -Q_OBJECT - -public: - explicit TreeHeader( ArtistView* parent = 0 ); - ~TreeHeader(); - -private: - ArtistView* m_parent; -}; - -#endif diff --git a/src/libtomahawk/playlist/TreeItemDelegate.cpp b/src/libtomahawk/playlist/TreeItemDelegate.cpp index da0b367db..c22847709 100644 --- a/src/libtomahawk/playlist/TreeItemDelegate.cpp +++ b/src/libtomahawk/playlist/TreeItemDelegate.cpp @@ -35,10 +35,10 @@ #include "PlayableItem.h" #include "TreeProxyModel.h" #include "Source.h" -#include "ArtistView.h" +#include "TreeView.h" -TreeItemDelegate::TreeItemDelegate( ArtistView* parent, TreeProxyModel* proxy ) +TreeItemDelegate::TreeItemDelegate( TreeView* parent, TreeProxyModel* proxy ) : QStyledItemDelegate( (QObject*)parent ) , m_view( parent ) , m_model( proxy ) diff --git a/src/libtomahawk/playlist/TreeItemDelegate.h b/src/libtomahawk/playlist/TreeItemDelegate.h index 419bc6790..2c4e90f12 100644 --- a/src/libtomahawk/playlist/TreeItemDelegate.h +++ b/src/libtomahawk/playlist/TreeItemDelegate.h @@ -28,7 +28,7 @@ namespace Tomahawk { class PixmapDelegateFader; } -class ArtistView; +class TreeView; class TreeProxyModel; class DLLEXPORT TreeItemDelegate : public QStyledItemDelegate @@ -36,7 +36,7 @@ class DLLEXPORT TreeItemDelegate : public QStyledItemDelegate Q_OBJECT public: - TreeItemDelegate( ArtistView* parent = 0, TreeProxyModel* proxy = 0 ); + TreeItemDelegate( TreeView* parent = 0, TreeProxyModel* proxy = 0 ); protected: void paint( QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index ) const; @@ -51,7 +51,7 @@ private slots: void doUpdateIndex( const QPersistentModelIndex& index ); private: - ArtistView* m_view; + TreeView* m_view; TreeProxyModel* m_model; mutable QHash< QPersistentModelIndex, QSharedPointer< Tomahawk::PixmapDelegateFader > > m_pixmaps; diff --git a/src/libtomahawk/playlist/TreeModel.cpp b/src/libtomahawk/playlist/TreeModel.cpp index c61cffc83..9e9e57349 100644 --- a/src/libtomahawk/playlist/TreeModel.cpp +++ b/src/libtomahawk/playlist/TreeModel.cpp @@ -38,44 +38,20 @@ using namespace Tomahawk; TreeModel::TreeModel( QObject* parent ) - : QAbstractItemModel( parent ) - , m_rootItem( new PlayableItem( 0, this ) ) - , m_infoId( uuid() ) - , m_columnStyle( AllColumns ) + : PlayableModel( parent ) , m_mode( DatabaseMode ) { + setStyle( Collection ); setIcon( QPixmap( RESPATH "images/music-icon.png" ) ); connect( AudioEngine::instance(), SIGNAL( started( Tomahawk::result_ptr ) ), SLOT( onPlaybackStarted( Tomahawk::result_ptr ) ), Qt::DirectConnection ); connect( AudioEngine::instance(), SIGNAL( stopped() ), SLOT( onPlaybackStopped() ), Qt::DirectConnection ); - - connect( Tomahawk::InfoSystem::InfoSystem::instance(), - SIGNAL( info( Tomahawk::InfoSystem::InfoRequestData, QVariant ) ), - SLOT( infoSystemInfo( Tomahawk::InfoSystem::InfoRequestData, QVariant ) ) ); } TreeModel::~TreeModel() { tDebug() << Q_FUNC_INFO; - - delete m_rootItem; -} - - -void -TreeModel::clear() -{ - if ( rowCount( QModelIndex() ) ) - { - emit loadingFinished(); - - emit beginResetModel(); - delete m_rootItem; - m_rootItem = 0; - m_rootItem = new PlayableItem( 0, this ); - emit endResetModel(); - } } @@ -100,52 +76,13 @@ TreeModel::getCover( const QModelIndex& index ) { PlayableItem* item = itemFromIndex( index ); - if ( !item->artist().isNull() && !item->artist()->infoLoaded() ) + if ( !item->artist().isNull() && !item->artist()->coverLoaded() ) item->artist()->cover( QSize( 0, 0 ) ); - else if ( !item->album().isNull() && !item->album()->infoLoaded() ) + else if ( !item->album().isNull() && !item->album()->coverLoaded() ) item->album()->cover( QSize( 0, 0 ) ); } -void -TreeModel::setCurrentItem( const QModelIndex& index ) -{ - qDebug() << Q_FUNC_INFO; - - PlayableItem* oldEntry = itemFromIndex( m_currentIndex ); - if ( oldEntry ) - { - oldEntry->setIsPlaying( false ); - } - - PlayableItem* entry = itemFromIndex( index ); - if ( entry ) - { - m_currentIndex = index; - entry->setIsPlaying( true ); - } - else - { - m_currentIndex = QModelIndex(); - } -} - - -QModelIndex -TreeModel::index( int row, int column, const QModelIndex& parent ) const -{ - if ( !m_rootItem || row < 0 || column < 0 ) - return QModelIndex(); - - PlayableItem* parentItem = itemFromIndex( parent ); - PlayableItem* childItem = parentItem->children.value( row ); - if ( !childItem ) - return QModelIndex(); - - return createIndex( row, column, childItem ); -} - - bool TreeModel::canFetchMore( const QModelIndex& parent ) const { @@ -190,388 +127,11 @@ TreeModel::fetchMore( const QModelIndex& parent ) } -bool -TreeModel::hasChildren( const QModelIndex& parent ) const -{ - PlayableItem* parentItem = itemFromIndex( parent ); - if ( !parentItem ) - return false; - - if ( parentItem == m_rootItem ) - return true; - - return ( !parentItem->artist().isNull() || !parentItem->album().isNull() ); -} - - -int -TreeModel::rowCount( const QModelIndex& parent ) const -{ - if ( parent.column() > 0 ) - return 0; - - PlayableItem* parentItem = itemFromIndex( parent ); - if ( !parentItem ) - return 0; - - return parentItem->children.count(); -} - - -int -TreeModel::columnCount( const QModelIndex& parent ) const -{ - Q_UNUSED( parent ); - - if ( m_columnStyle == AllColumns ) - return 8; - else if ( m_columnStyle == TrackOnly ) - return 1; - - // UH.. - return 0; -} - - -QModelIndex -TreeModel::parent( const QModelIndex& child ) const -{ - PlayableItem* entry = itemFromIndex( child ); - if ( !entry ) - return QModelIndex(); - - PlayableItem* parentEntry = entry->parent(); - if ( !parentEntry ) - return QModelIndex(); - - PlayableItem* grandparentEntry = parentEntry->parent(); - if ( !grandparentEntry ) - return QModelIndex(); - - int row = grandparentEntry->children.indexOf( parentEntry ); - return createIndex( row, 0, parentEntry ); -} - - -QVariant -TreeModel::data( const QModelIndex& index, int role ) const -{ - PlayableItem* entry = itemFromIndex( index ); - if ( !entry ) - return QVariant(); - - if ( role == Qt::SizeHintRole ) - { - if ( !entry->result().isNull() || !entry->query().isNull() ) - { - return QSize( 128, 20 ); - } - else if ( !entry->album().isNull() ) - { - return QSize( 128, 32 ); - } - else if ( !entry->artist().isNull() ) - { - return QSize( 128, 44 ); - } - - return QSize( 128, 0 ); - } - - if ( role != Qt::DisplayRole ) // && role != Qt::ToolTipRole ) - return QVariant(); - - if ( !entry->artist().isNull() && index.column() == Name ) - { - return entry->artist()->name(); - } - else if ( !entry->album().isNull() && index.column() == Name ) - { - return entry->album()->name(); - } - else if ( !entry->result().isNull() ) - { - const result_ptr& result = entry->result(); - unsigned int discnumber = 0; - if ( !entry->query().isNull() ) - discnumber = entry->query()->discnumber(); - if ( discnumber == 0 ) - discnumber = result->discnumber(); - - unsigned int albumpos = 0; - if ( !entry->query().isNull() ) - albumpos = entry->query()->albumpos(); - if ( albumpos == 0 ) - albumpos = result->albumpos(); - - switch( index.column() ) - { - case Name: - return QString( "%1%2%3" ).arg( discnumber > 0 ? QString( "%1." ).arg( discnumber ) : QString() ) - .arg( albumpos > 0 ? QString( "%1. ").arg( albumpos ) : QString() ) - .arg( result->track() ); - - case Duration: - return TomahawkUtils::timeToString( result->duration() ); - - case Bitrate: - if ( result->bitrate() > 0 ) - return result->bitrate(); - break; - - case Age: - return TomahawkUtils::ageToString( QDateTime::fromTime_t( result->modificationTime() ) ); - - case Year: - if ( result->year() != 0 ) - return result->year(); - break; - - case Filesize: - return TomahawkUtils::filesizeToString( result->size() ); - - case Origin: - return result->friendlySource(); - - case AlbumPosition: - return result->albumpos(); - - case Composer: - if ( !result->composer().isNull() ) - return result->composer()->name(); - break; - - default: - return QVariant(); - } - } - else if ( !entry->query().isNull() ) - { - const query_ptr& query = entry->query(); - switch( index.column() ) - { - case Name: - return QString( "%1%2%3" ).arg( query->discnumber() > 0 ? QString( "%1." ).arg( query->discnumber() ) : QString() ) - .arg( query->albumpos() > 0 ? QString( "%1. ").arg( query->albumpos() ) : QString() ) - .arg( query->track() ); - - case AlbumPosition: - return entry->query()->albumpos(); - - default: - return QVariant(); - } - } - - return QVariant(); -} - - -QVariant -TreeModel::headerData( int section, Qt::Orientation orientation, int role ) const -{ - QStringList headers; - headers << tr( "Name" ) << tr( "Composer" ) << tr( "Duration" ) << tr( "Bitrate" ) << tr( "Age" ) << tr( "Year" ) << tr( "Size" ) << tr( "Origin" ); - if ( orientation == Qt::Horizontal && role == Qt::DisplayRole && section >= 0 ) - { - return headers.at( section ); - } - - return QVariant(); -} - - -Qt::ItemFlags -TreeModel::flags( const QModelIndex& index ) const -{ - Qt::ItemFlags defaultFlags = QAbstractItemModel::flags( index ); - - if ( index.isValid() && index.column() == 0 ) - { - PlayableItem* item = itemFromIndex( index ); - if ( item && !item->result().isNull() ) - return Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled | defaultFlags; - if ( item && ( !item->album().isNull() || !item->artist().isNull() ) ) - return Qt::ItemIsDragEnabled | defaultFlags; - } - - return defaultFlags; -} - - -QStringList -TreeModel::mimeTypes() const -{ - QStringList types; - types << "application/tomahawk.mixed"; - return types; -} - - -QMimeData* -TreeModel::mimeData( const QModelIndexList &indexes ) const -{ - qDebug() << Q_FUNC_INFO; - - QByteArray resultData; - QDataStream resultStream( &resultData, QIODevice::WriteOnly ); - - // lets try with artist only - bool fail = false; - foreach ( const QModelIndex& i, indexes) - { - if ( i.column() > 0 || indexes.contains( i.parent() ) ) - continue; - - PlayableItem* item = itemFromIndex( i ); - if ( !item ) - continue; - - if ( !item->artist().isNull() ) - { - const artist_ptr& artist = item->artist(); - resultStream << artist->name(); - } - else - { - fail = true; - break; - } - } - if ( !fail ) - { - QMimeData* mimeData = new QMimeData(); - mimeData->setData( "application/tomahawk.metadata.artist", resultData ); - return mimeData; - } - - // lets try with album only - fail = false; - resultData.clear(); - foreach ( const QModelIndex& i, indexes ) - { - if ( i.column() > 0 || indexes.contains( i.parent() ) ) - continue; - - PlayableItem* item = itemFromIndex( i ); - if ( !item ) - continue; - - if ( !item->album().isNull() ) - { - const album_ptr& album = item->album(); - resultStream << album->artist()->name(); - resultStream << album->name(); - } - else - { - fail = true; - break; - } - } - if ( !fail ) - { - QMimeData* mimeData = new QMimeData(); - mimeData->setData( "application/tomahawk.metadata.album", resultData ); - return mimeData; - } - - // lets try with tracks only - fail = false; - resultData.clear(); - foreach ( const QModelIndex& i, indexes ) - { - if ( i.column() > 0 || indexes.contains( i.parent() ) ) - continue; - - PlayableItem* item = itemFromIndex( i ); - if ( !item ) - continue; - - if ( !item->result().isNull() ) - { - const result_ptr& result = item->result(); - resultStream << qlonglong( &result ); - } - else - { - fail = true; - break; - } - } - if ( !fail ) - { - QMimeData* mimeData = new QMimeData(); - mimeData->setData( "application/tomahawk.result.list", resultData ); - return mimeData; - } - - // Ok... we have to use mixed - resultData.clear(); - foreach ( const QModelIndex& i, indexes ) - { - if ( i.column() > 0 || indexes.contains( i.parent() ) ) - continue; - - PlayableItem* item = itemFromIndex( i ); - if ( !item ) - continue; - - if ( !item->artist().isNull() ) - { - const artist_ptr& artist = item->artist(); - resultStream << QString( "application/tomahawk.metadata.artist" ) << artist->name(); - } - else if ( !item->album().isNull() ) - { - const album_ptr& album = item->album(); - resultStream << QString( "application/tomahawk.metadata.album" ) << album->artist()->name() << album->name(); - } - else if ( !item->result().isNull() ) - { - const result_ptr& result = item->result(); - resultStream << QString( "application/tomahawk.result.list" ) << qlonglong( &result ); - } - } - - QMimeData* mimeData = new QMimeData(); - mimeData->setData( "application/tomahawk.mixed", resultData ); - return mimeData; -} - - -void -TreeModel::removeIndex( const QModelIndex& index ) -{ - qDebug() << Q_FUNC_INFO; - - if ( index.column() > 0 ) - return; - - PlayableItem* item = itemFromIndex( index ); - if ( item ) - { - emit beginRemoveRows( index.parent(), index.row(), index.row() ); - delete item; - emit endRemoveRows(); - } -} - - -void -TreeModel::removeIndexes( const QList& indexes ) -{ - foreach( const QModelIndex& idx, indexes ) - { - removeIndex( idx ); - } -} - - void TreeModel::addAllCollections() { - emit loadingStarted(); + startLoading(); + DatabaseCommand_AllArtists* cmd = new DatabaseCommand_AllArtists(); connect( cmd, SIGNAL( artists( QList ) ), @@ -587,7 +147,7 @@ TreeModel::addAllCollections() connect( source->collection().data(), SIGNAL( changed() ), SLOT( onCollectionChanged() ), Qt::UniqueConnection ); } - m_title = tr( "All Artists" ); + setTitle( tr( "All Artists" ) ); } @@ -597,7 +157,7 @@ TreeModel::addArtists( const artist_ptr& artist ) if ( artist.isNull() ) return; - emit loadingStarted(); + startLoading(); QList artists; artists << artist; @@ -608,7 +168,7 @@ TreeModel::addArtists( const artist_ptr& artist ) void TreeModel::fetchAlbums( const artist_ptr& artist ) { - emit loadingStarted(); + startLoading(); connect( artist.data(), SIGNAL( albumsAdded( QList, Tomahawk::ModelMode ) ), SLOT( onAlbumsFound( QList, Tomahawk::ModelMode ) ), Qt::UniqueConnection ); @@ -624,7 +184,7 @@ TreeModel::onAlbumsFound( const QList& albums, ModelMode mo if ( m_mode != mode ) return; - Artist* artist = qobject_cast< Artist* >( sender() ); + Tomahawk::Artist* artist = qobject_cast< Tomahawk::Artist* >( sender() ); if ( !artist ) return; @@ -640,7 +200,7 @@ TreeModel::onAlbumsFound( const QList& albums, ModelMode mo void TreeModel::addAlbums( const QModelIndex& parent, const QList& albums ) { - emit loadingFinished(); + finishLoading(); if ( !albums.count() ) return; @@ -672,12 +232,13 @@ TreeModel::addTracks( const album_ptr& album, const QModelIndex& parent, bool au { Q_UNUSED( autoRefetch ); - emit loadingStarted(); + startLoading(); connect( album.data(), SIGNAL( tracksAdded( QList, Tomahawk::ModelMode, Tomahawk::collection_ptr ) ), SLOT( onTracksFound( QList, Tomahawk::ModelMode, Tomahawk::collection_ptr ) ) ); - onTracksAdded( album->tracks( m_mode, m_collection ), parent ); + if ( !album->tracks( m_mode, m_collection ).isEmpty() ) + onTracksAdded( album->tracks( m_mode, m_collection ), parent ); } @@ -755,12 +316,7 @@ TreeModel::onCollectionChanged() void TreeModel::onArtistsAdded( const QList& artists ) { - emit loadingFinished(); - if ( !artists.count() ) - { - emit itemCountChanged( rowCount( QModelIndex() ) ); - return; - } + finishLoading(); int c = rowCount( QModelIndex() ); QPair< int, int > crows; @@ -772,20 +328,19 @@ TreeModel::onArtistsAdded( const QList& artists ) PlayableItem* artistitem; foreach( const artist_ptr& artist, artists ) { - artistitem = new PlayableItem( artist, m_rootItem ); - artistitem->index = createIndex( m_rootItem->children.count() - 1, 0, artistitem ); + artistitem = new PlayableItem( artist, rootItem() ); + artistitem->index = createIndex( rootItem()->children.count() - 1, 0, artistitem ); connect( artistitem, SIGNAL( dataChanged() ), SLOT( onDataChanged() ) ); } emit endInsertRows(); - emit itemCountChanged( rowCount( QModelIndex() ) ); } void TreeModel::onTracksAdded( const QList& tracks, const QModelIndex& parent ) { - emit loadingFinished(); + finishLoading(); if ( !tracks.count() ) return; @@ -817,135 +372,17 @@ TreeModel::onTracksFound( const QList& tracks, Tomahawk::Mo if ( mode != m_mode || collection != m_collection ) return; - Album* album = qobject_cast( sender() ); + Tomahawk::Album* album = qobject_cast( sender() ); QModelIndex idx = indexFromAlbum( album->weakRef().toStrongRef() ); onTracksAdded( tracks, idx ); } -void -TreeModel::infoSystemInfo( Tomahawk::InfoSystem::InfoRequestData requestData, QVariant output ) -{ - if ( requestData.caller != m_infoId ) - { - return; - } - - switch ( requestData.type ) - { - case Tomahawk::InfoSystem::InfoAlbumSongs: - { - m_receivedInfoData.append( requestData.input.value< Tomahawk::InfoSystem::InfoStringHash >() ); - - QVariantMap returnedData = output.value< QVariantMap >(); - if ( !returnedData.isEmpty() ) - { - emit loadingFinished(); - - QList< QVariant > rows = requestData.customData[ "rows" ].toList(); - QModelIndex idx = index( rows.first().toUInt(), 0, index( rows.at( 1 ).toUInt(), 0, QModelIndex() ) ); - if ( rowCount( idx ) ) - return; - - Tomahawk::InfoSystem::InfoStringHash inputInfo; - inputInfo = requestData.input.value< Tomahawk::InfoSystem::InfoStringHash >(); - - QStringList tracks = returnedData[ "tracks" ].toStringList(); - QList ql; - - //TODO: Figure out how to do this with a multi-disk album without breaking the - // current behaviour. I just know too little about InfoSystem to deal with - // it right now, I've only taken the liberty of adding Query::setDiscNumber - // which should make this easier. --Teo 11/2011 - unsigned int trackNo = 1; - - foreach ( const QString& trackName, tracks ) - { - query_ptr query = Query::get( inputInfo[ "artist" ], trackName, inputInfo[ "album" ] ); - query->setAlbumPos( trackNo++ ); - ql << query; - } - Pipeline::instance()->resolve( ql ); - - onTracksAdded( ql, idx ); - } - else if ( m_receivedInfoData.count() == 2 /* FIXME */ ) - { - // If the second load got no data, but the first load did, don't do anything - QList< QVariant > rows = requestData.customData[ "rows" ].toList(); - QModelIndex idx = index( rows.first().toUInt(), 0, index( rows.at( 1 ).toUInt(), 0, QModelIndex() ) ); - if ( rowCount( idx ) ) - return; - - if ( requestData.customData[ "refetch" ].toBool() ) - { - setMode( DatabaseMode ); - - Tomahawk::InfoSystem::InfoStringHash inputInfo; - inputInfo = requestData.input.value< InfoSystem::InfoStringHash >(); - artist_ptr artist = Artist::get( inputInfo[ "artist" ], false ); - album_ptr album = Album::get( artist, inputInfo[ "album" ], false ); - - addTracks( album, QModelIndex() ); - } - else - emit loadingFinished(); - } - - break; - } - - default: - { - Q_ASSERT( false ); - break; - } - } -} - - -void -TreeModel::onPlaybackStarted( const Tomahawk::result_ptr& result ) -{ - PlayableItem* oldEntry = itemFromIndex( m_currentIndex ); - if ( oldEntry && ( oldEntry->result().isNull() || oldEntry->result().data() != result.data() ) ) - { - oldEntry->setIsPlaying( false ); - } -} - - -void -TreeModel::onPlaybackStopped() -{ - PlayableItem* oldEntry = itemFromIndex( m_currentIndex ); - if ( oldEntry ) - { - oldEntry->setIsPlaying( false ); - } -} - - -void -TreeModel::onDataChanged() -{ - PlayableItem* p = (PlayableItem*)sender(); - emit dataChanged( p->index, p->index.sibling( p->index.row(), columnCount( QModelIndex() ) - 1 ) ); -} - - -void -TreeModel::setColumnStyle( TreeModel::ColumnStyle style ) -{ - m_columnStyle = style; -} - - QModelIndex TreeModel::indexFromArtist( const Tomahawk::artist_ptr& artist ) const { - for ( int i = 0; i < rowCount(); i++ ) + for ( int i = 0; i < rowCount( QModelIndex() ); i++ ) { QModelIndex idx = index( i, 0, QModelIndex() ); PlayableItem* item = itemFromIndex( idx ); diff --git a/src/libtomahawk/playlist/TreeModel.h b/src/libtomahawk/playlist/TreeModel.h index 21ec55591..6fb91d3c3 100644 --- a/src/libtomahawk/playlist/TreeModel.h +++ b/src/libtomahawk/playlist/TreeModel.h @@ -27,11 +27,10 @@ #include "Album.h" #include "Query.h" #include "Result.h" +#include "PlayableModel.h" #include "PlaylistInterface.h" #include "database/DatabaseCommand_AllArtists.h" -#include "infosystem/InfoSystem.h" - #include "DllMacro.h" #include "Typedefs.h" @@ -39,57 +38,17 @@ class QMetaData; class PlayableItem; -class DLLEXPORT TreeModel : public QAbstractItemModel +class DLLEXPORT TreeModel : public PlayableModel { Q_OBJECT public: - enum Columns { - Name = 0, - Composer, - Duration, - Bitrate, - Age, - Year, - Filesize, - Origin, - AlbumPosition - }; - - enum ColumnStyle - { AllColumns = 0, TrackOnly }; - explicit TreeModel( QObject* parent = 0 ); virtual ~TreeModel(); - virtual QModelIndex index( int row, int column, const QModelIndex& parent ) const; - virtual QModelIndex parent( const QModelIndex& child ) const; - - virtual bool isReadOnly() const { return true; } - - virtual int trackCount() const { return rowCount( QModelIndex() ); } - virtual int albumCount() const { return rowCount( QModelIndex() ); } - - virtual bool hasChildren( const QModelIndex& parent = QModelIndex() ) const; - virtual int rowCount( const QModelIndex& parent = QModelIndex() ) const; - virtual int columnCount( const QModelIndex& parent = QModelIndex() ) const; - virtual Tomahawk::ModelMode mode() const { return m_mode; } virtual void setMode( Tomahawk::ModelMode mode ); - virtual QVariant data( const QModelIndex& index, int role = Qt::DisplayRole ) const; - virtual QVariant headerData( int section, Qt::Orientation orientation, int role ) const; - - virtual void clear(); - virtual void removeIndex( const QModelIndex& index ); - virtual void removeIndexes( const QList& indexes ); - - virtual QMimeData* mimeData( const QModelIndexList& indexes ) const; - virtual QStringList mimeTypes() const; - virtual Qt::ItemFlags flags( const QModelIndex& index ) const; - - virtual QPersistentModelIndex currentItem() { return m_currentIndex; } - Tomahawk::collection_ptr collection() const; void addAllCollections(); @@ -102,47 +61,14 @@ public: void getCover( const QModelIndex& index ); - ColumnStyle columnStyle() const { return m_columnStyle; } - void setColumnStyle( ColumnStyle style ); - - virtual QString title() const { return m_title; } - virtual QString description() const { return m_description; } - virtual QPixmap icon() const { return m_icon; } - virtual void setTitle( const QString& title ) { m_title = title; } - virtual void setDescription( const QString& description ) { m_description = description; } - virtual void setIcon( const QPixmap& pixmap ) { m_icon = pixmap; } - QModelIndex indexFromArtist( const Tomahawk::artist_ptr& artist ) const; QModelIndex indexFromAlbum( const Tomahawk::album_ptr& album ) const; - PlayableItem* itemFromIndex( const QModelIndex& index ) const - { - if ( index.isValid() ) - { - return static_cast( index.internalPointer() ); - } - else - { - return m_rootItem; - } - } public slots: - virtual void setCurrentItem( const QModelIndex& index ); - - virtual void setRepeatMode( Tomahawk::PlaylistModes::RepeatMode /*mode*/ ) {} - virtual void setShuffled( bool /*shuffled*/ ) {} - void addAlbums( const QModelIndex& parent, const QList& albums ); signals: - void repeatModeChanged( Tomahawk::PlaylistModes::RepeatMode mode ); - void shuffleModeChanged( bool enabled ); - void modeChanged( Tomahawk::ModelMode mode ); - void itemCountChanged( unsigned int items ); - - void loadingStarted(); - void loadingFinished(); protected: bool canFetchMore( const QModelIndex& parent ) const; @@ -154,31 +80,14 @@ private slots: void onTracksAdded( const QList& tracks, const QModelIndex& index ); void onTracksFound( const QList& tracks, Tomahawk::ModelMode mode, Tomahawk::collection_ptr collection ); - void infoSystemInfo( Tomahawk::InfoSystem::InfoRequestData requestData, QVariant output ); - - void onPlaybackStarted( const Tomahawk::result_ptr& result ); - void onPlaybackStopped(); - - void onDataChanged(); - void onSourceAdded( const Tomahawk::source_ptr& source ); void onCollectionChanged(); private: - QPersistentModelIndex m_currentIndex; - PlayableItem* m_rootItem; - QString m_infoId; - - QString m_title; - QString m_description; - QPixmap m_icon; - ColumnStyle m_columnStyle; Tomahawk::ModelMode m_mode; + Tomahawk::collection_ptr m_collection; QList m_artistsFilter; - - Tomahawk::collection_ptr m_collection; - QList m_receivedInfoData; }; #endif // ALBUMMODEL_H diff --git a/src/libtomahawk/playlist/TreeProxyModel.cpp b/src/libtomahawk/playlist/TreeProxyModel.cpp index c8ffa0d43..8d181af65 100644 --- a/src/libtomahawk/playlist/TreeProxyModel.cpp +++ b/src/libtomahawk/playlist/TreeProxyModel.cpp @@ -32,52 +32,30 @@ TreeProxyModel::TreeProxyModel( QObject* parent ) - : QSortFilterProxyModel( parent ) + : PlayableProxyModel( parent ) , m_artistsFilterCmd( 0 ) , m_model( 0 ) { - setFilterCaseSensitivity( Qt::CaseInsensitive ); - setSortCaseSensitivity( Qt::CaseInsensitive ); - setDynamicSortFilter( true ); - - setSourceTreeModel( 0 ); -} - - -QPersistentModelIndex -TreeProxyModel::currentIndex() const -{ - if ( !m_model ) - return QPersistentModelIndex(); - - return mapFromSource( m_model->currentItem() ); } void -TreeProxyModel::setSourceModel( QAbstractItemModel* sourceModel ) +TreeProxyModel::setSourcePlayableModel( TreeModel* model ) { - Q_UNUSED( sourceModel ); - qDebug() << "Explicitly use setSourceTreeModel instead"; - Q_ASSERT( false ); -} - - -void -TreeProxyModel::setSourceTreeModel( TreeModel* sourceModel ) -{ - m_model = sourceModel; - - if ( m_model ) + if ( sourceModel() ) { - if ( m_model->metaObject()->indexOfSignal( "trackCountChanged(uint)" ) > -1 ) - connect( m_model, SIGNAL( trackCountChanged( unsigned int ) ), SIGNAL( sourceTrackCountChanged( unsigned int ) ) ); + disconnect( m_model, SIGNAL( rowsInserted( QModelIndex, int, int ) ), this, SLOT( onRowsInserted( QModelIndex, int, int ) ) ); + disconnect( m_model, SIGNAL( modelReset() ), this, SLOT( onModelReset() ) ); + } + PlayableProxyModel::setSourcePlayableModel( model ); + m_model = model; + + if ( sourceModel() ) + { connect( m_model, SIGNAL( rowsInserted( QModelIndex, int, int ) ), SLOT( onRowsInserted( QModelIndex, int, int ) ) ); connect( m_model, SIGNAL( modelReset() ), SLOT( onModelReset() ) ); } - - QSortFilterProxyModel::setSourceModel( sourceModel ); } @@ -114,7 +92,7 @@ TreeProxyModel::onModelReset() void -TreeProxyModel::newFilterFromPlaylistInterface( const QString &pattern ) +TreeProxyModel::newFilterFromPlaylistInterface( const QString& pattern ) { emit filteringStarted(); @@ -339,33 +317,6 @@ TreeProxyModel::lessThan( const QModelIndex& left, const QModelIndex& right ) co } -void -TreeProxyModel::removeIndex( const QModelIndex& index ) -{ - qDebug() << Q_FUNC_INFO; - - if ( !sourceModel() ) - return; - if ( index.column() > 0 ) - return; - - sourceModel()->removeIndex( mapToSource( index ) ); -} - - -void -TreeProxyModel::removeIndexes( const QList& indexes ) -{ - if ( !sourceModel() ) - return; - - foreach( const QModelIndex& idx, indexes ) - { - removeIndex( idx ); - } -} - - QString TreeProxyModel::textForItem( PlayableItem* item ) const { diff --git a/src/libtomahawk/playlist/TreeProxyModel.h b/src/libtomahawk/playlist/TreeProxyModel.h index cf24f1973..bca8676b0 100644 --- a/src/libtomahawk/playlist/TreeProxyModel.h +++ b/src/libtomahawk/playlist/TreeProxyModel.h @@ -20,10 +20,9 @@ #ifndef TREEPROXYMODEL_H #define TREEPROXYMODEL_H -#include - #include "PlaylistInterface.h" #include "TreeModel.h" +#include "PlayableProxyModel.h" #include "DllMacro.h" @@ -34,7 +33,7 @@ namespace Tomahawk class TreeProxyModelPlaylistInterface; } -class DLLEXPORT TreeProxyModel : public QSortFilterProxyModel +class DLLEXPORT TreeProxyModel : public PlayableProxyModel { Q_OBJECT @@ -42,28 +41,13 @@ public: explicit TreeProxyModel( QObject* parent = 0 ); virtual ~TreeProxyModel() {} - virtual TreeModel* sourceModel() const { return m_model; } - virtual void setSourceTreeModel( TreeModel* sourceModel ); - virtual void setSourceModel( QAbstractItemModel* sourceModel ); + virtual void setSourcePlayableModel( TreeModel* model ); - virtual QPersistentModelIndex currentIndex() const; - virtual void setCurrentIndex( const QModelIndex& index ) { m_model->setCurrentItem( mapToSource( index ) ); } - - virtual void newFilterFromPlaylistInterface( const QString &pattern ); - - virtual void removeIndex( const QModelIndex& index ); - virtual void removeIndexes( const QList& indexes ); - - virtual int albumCount() const { return rowCount( QModelIndex() ); } - - virtual PlayableItem* itemFromIndex( const QModelIndex& index ) const { return sourceModel()->itemFromIndex( index ); } + virtual void newFilterFromPlaylistInterface( const QString& pattern ); virtual Tomahawk::playlistinterface_ptr playlistInterface(); signals: - void filterChanged( const QString& filter ); - void filteringStarted(); - void filteringFinished(); protected: bool filterAcceptsRow( int sourceRow, const QModelIndex& sourceParent ) const; @@ -87,8 +71,7 @@ private: QList m_albumsFilter; DatabaseCommand_AllArtists* m_artistsFilterCmd; - QString m_filter; - + QString m_filter; TreeModel* m_model; Tomahawk::playlistinterface_ptr m_playlistInterface; diff --git a/src/libtomahawk/playlist/ArtistView.cpp b/src/libtomahawk/playlist/TreeView.cpp similarity index 83% rename from src/libtomahawk/playlist/ArtistView.cpp rename to src/libtomahawk/playlist/TreeView.cpp index 0dcf8c5e0..57269b238 100644 --- a/src/libtomahawk/playlist/ArtistView.cpp +++ b/src/libtomahawk/playlist/TreeView.cpp @@ -17,7 +17,7 @@ * along with Tomahawk. If not, see . */ -#include "ArtistView.h" +#include "TreeView.h" #include #include @@ -31,11 +31,13 @@ #include "ContextMenu.h" #include "TomahawkSettings.h" -#include "TreeHeader.h" +#include "ViewHeader.h" #include "TreeItemDelegate.h" #include "TreeModel.h" #include "PlayableItem.h" +#include "Source.h" #include "ViewManager.h" +#include "utils/TomahawkUtilsGui.h" #include "utils/Logger.h" #define SCROLL_TIMEOUT 280 @@ -43,18 +45,21 @@ using namespace Tomahawk; -ArtistView::ArtistView( QWidget* parent ) +TreeView::TreeView( QWidget* parent ) : QTreeView( parent ) - , m_header( new TreeHeader( this ) ) + , m_header( new ViewHeader( this ) ) , m_overlay( new OverlayWidget( this ) ) , m_model( 0 ) , m_proxyModel( 0 ) -// , m_delegate( 0 ) - , m_loadingSpinner( new AnimatedSpinner( this ) ) + , m_loadingSpinner( new LoadingSpinner( this ) ) , m_updateContextView( true ) , m_contextMenu( new ContextMenu( this ) ) , m_showModes( true ) { + setFrameShape( QFrame::NoFrame ); + setAttribute( Qt::WA_MacShowFocusRect, 0 ); + + setContentsMargins( 0, 0, 0, 0 ); setAlternatingRowColors( true ); setDragEnabled( true ); setDropIndicatorShown( false ); @@ -93,14 +98,14 @@ ArtistView::ArtistView( QWidget* parent ) } -ArtistView::~ArtistView() +TreeView::~TreeView() { tDebug() << Q_FUNC_INFO; } void -ArtistView::setProxyModel( TreeProxyModel* model ) +TreeView::setProxyModel( TreeProxyModel* model ) { m_proxyModel = model; TreeItemDelegate* del = new TreeItemDelegate( this, m_proxyModel ); @@ -112,7 +117,7 @@ ArtistView::setProxyModel( TreeProxyModel* model ) void -ArtistView::setModel( QAbstractItemModel* model ) +TreeView::setModel( QAbstractItemModel* model ) { Q_UNUSED( model ); qDebug() << "Explicitly use setPlaylistModel instead"; @@ -121,28 +126,26 @@ ArtistView::setModel( QAbstractItemModel* model ) void -ArtistView::setTreeModel( TreeModel* model ) +TreeView::setTreeModel( TreeModel* model ) { m_model = model; if ( m_proxyModel ) { - m_proxyModel->setSourceTreeModel( model ); + m_proxyModel->setSourcePlayableModel( model ); m_proxyModel->sort( 0 ); } - connect( m_model, SIGNAL( loadingStarted() ), m_loadingSpinner, SLOT( fadeIn() ) ); - connect( m_model, SIGNAL( loadingFinished() ), m_loadingSpinner, SLOT( fadeOut() ) ); connect( m_proxyModel, SIGNAL( filteringStarted() ), SLOT( onFilteringStarted() ) ); connect( m_proxyModel, SIGNAL( filteringFinished() ), m_loadingSpinner, SLOT( fadeOut() ) ); - connect( m_model, SIGNAL( itemCountChanged( unsigned int ) ), SLOT( onItemCountChanged( unsigned int ) ) ); connect( m_proxyModel, SIGNAL( filteringFinished() ), SLOT( onFilterChangeFinished() ) ); connect( m_proxyModel, SIGNAL( rowsInserted( QModelIndex, int, int ) ), SLOT( onViewChanged() ) ); guid(); // this will set the guid on the header - if ( model->columnStyle() == TreeModel::TrackOnly ) + m_header->setDefaultColumnWeights( model->columnWeights() ); + if ( model->style() == PlayableModel::Large ) { setHeaderHidden( true ); setHorizontalScrollBarPolicy( Qt::ScrollBarAlwaysOff ); @@ -152,11 +155,28 @@ ArtistView::setTreeModel( TreeModel* model ) setHeaderHidden( false ); setHorizontalScrollBarPolicy( Qt::ScrollBarAsNeeded ); } + + emit modelChanged(); + +/* setColumnHidden( PlayableModel::Score, true ); // Hide score column per default + setColumnHidden( PlayableModel::Origin, true ); // Hide origin column per default + setColumnHidden( PlayableModel::Composer, true ); //Hide composer column per default + + setGuid( QString( "collectionview/%1" ).arg( model->columnCount() ) ); + sortByColumn( PlayableModel::Artist, Qt::AscendingOrder );*/ } void -ArtistView::onViewChanged() +TreeView::setEmptyTip( const QString& tip ) +{ + m_emptyTip = tip; + m_overlay->setText( tip ); +} + + +void +TreeView::onViewChanged() { if ( m_timer.isActive() ) m_timer.stop(); @@ -166,7 +186,7 @@ ArtistView::onViewChanged() void -ArtistView::onScrollTimeout() +TreeView::onScrollTimeout() { if ( m_timer.isActive() ) m_timer.stop(); @@ -194,7 +214,7 @@ ArtistView::onScrollTimeout() void -ArtistView::currentChanged( const QModelIndex& current, const QModelIndex& previous ) +TreeView::currentChanged( const QModelIndex& current, const QModelIndex& previous ) { QTreeView::currentChanged( current, previous ); @@ -217,7 +237,7 @@ ArtistView::currentChanged( const QModelIndex& current, const QModelIndex& previ void -ArtistView::onItemActivated( const QModelIndex& index ) +TreeView::onItemActivated( const QModelIndex& index ) { PlayableItem* item = m_model->itemFromIndex( m_proxyModel->mapToSource( index ) ); if ( item ) @@ -236,7 +256,7 @@ ArtistView::onItemActivated( const QModelIndex& index ) void -ArtistView::keyPressEvent( QKeyEvent* event ) +TreeView::keyPressEvent( QKeyEvent* event ) { QTreeView::keyPressEvent( event ); @@ -251,7 +271,7 @@ ArtistView::keyPressEvent( QKeyEvent* event ) void -ArtistView::resizeEvent( QResizeEvent* event ) +TreeView::resizeEvent( QResizeEvent* event ) { QTreeView::resizeEvent( event ); m_header->checkState(); @@ -267,24 +287,7 @@ ArtistView::resizeEvent( QResizeEvent* event ) void -ArtistView::onItemCountChanged( unsigned int items ) -{ - if ( items == 0 ) - { - if ( m_model->collection().isNull() || ( !m_model->collection().isNull() && m_model->collection()->source()->isLocal() ) ) - m_overlay->setText( tr( "After you have scanned your music collection you will find your tracks right here." ) ); - else - m_overlay->setText( tr( "This collection is currently empty." ) ); - - m_overlay->show(); - } - else - m_overlay->hide(); -} - - -void -ArtistView::onFilterChangeFinished() +TreeView::onFilterChangeFinished() { if ( selectedIndexes().count() ) scrollTo( selectedIndexes().at( 0 ), QAbstractItemView::PositionAtCenter ); @@ -295,13 +298,22 @@ ArtistView::onFilterChangeFinished() m_overlay->show(); } else + { if ( model()->trackCount() ) + { m_overlay->hide(); + } + else + { + m_overlay->setText( m_emptyTip ); + m_overlay->show(); + } + } } void -ArtistView::onFilteringStarted() +TreeView::onFilteringStarted() { m_overlay->hide(); m_loadingSpinner->fadeIn(); @@ -309,7 +321,7 @@ ArtistView::onFilteringStarted() void -ArtistView::startDrag( Qt::DropActions supportedActions ) +TreeView::startDrag( Qt::DropActions supportedActions ) { QList pindexes; QModelIndexList indexes; @@ -349,7 +361,7 @@ ArtistView::startDrag( Qt::DropActions supportedActions ) void -ArtistView::onCustomContextMenu( const QPoint& pos ) +TreeView::onCustomContextMenu( const QPoint& pos ) { m_contextMenu->clear(); @@ -390,7 +402,7 @@ ArtistView::onCustomContextMenu( const QPoint& pos ) void -ArtistView::onMenuTriggered( int action ) +TreeView::onMenuTriggered( int action ) { switch ( action ) { @@ -405,9 +417,9 @@ ArtistView::onMenuTriggered( int action ) bool -ArtistView::jumpToCurrentTrack() +TreeView::jumpToCurrentTrack() { - if ( !m_proxyModel ) + if ( !m_proxyModel || !m_proxyModel->sourceModel() ) return false; scrollTo( m_proxyModel->currentIndex(), QAbstractItemView::PositionAtCenter ); @@ -416,7 +428,7 @@ ArtistView::jumpToCurrentTrack() QString -ArtistView::guid() const +TreeView::guid() const { if ( m_guid.isEmpty() ) { diff --git a/src/libtomahawk/playlist/ArtistView.h b/src/libtomahawk/playlist/TreeView.h similarity index 89% rename from src/libtomahawk/playlist/ArtistView.h rename to src/libtomahawk/playlist/TreeView.h index 90c76e66f..8bd34cb03 100644 --- a/src/libtomahawk/playlist/ArtistView.h +++ b/src/libtomahawk/playlist/TreeView.h @@ -17,8 +17,8 @@ * along with Tomahawk. If not, see . */ -#ifndef ARTISTVIEW_H -#define ARTISTVIEW_H +#ifndef TREEVIEW_H +#define TREEVIEW_H #include #include @@ -36,18 +36,18 @@ namespace Tomahawk class ContextMenu; }; -class TreeHeader; +class ViewHeader; class AnimatedSpinner; class OverlayWidget; class TreeModel; -class DLLEXPORT ArtistView : public QTreeView, public Tomahawk::ViewPage +class DLLEXPORT TreeView : public QTreeView, public Tomahawk::ViewPage { Q_OBJECT public: - explicit ArtistView( QWidget* parent = 0 ); - ~ArtistView(); + explicit TreeView( QWidget* parent = 0 ); + ~TreeView(); virtual QString guid() const; virtual void setGuid( const QString& guid ) { m_guid = guid; } @@ -57,11 +57,12 @@ public: TreeModel* model() const { return m_model; } TreeProxyModel* proxyModel() const { return m_proxyModel; } OverlayWidget* overlay() const { return m_overlay; } - // PlaylistItemDelegate* delegate() { return m_delegate; } void setModel( QAbstractItemModel* model ); void setTreeModel( TreeModel* model ); + void setEmptyTip( const QString& tip ); + virtual QWidget* widget() { return this; } virtual Tomahawk::playlistinterface_ptr playlistInterface() const { return proxyModel()->playlistInterface(); } @@ -83,6 +84,9 @@ public: public slots: void onItemActivated( const QModelIndex& index ); +signals: + void modelChanged(); + protected: virtual void startDrag( Qt::DropActions supportedActions ); virtual void resizeEvent( QResizeEvent* event ); @@ -93,7 +97,6 @@ protected slots: virtual void currentChanged( const QModelIndex& current, const QModelIndex& previous ); private slots: - void onItemCountChanged( unsigned int items ); void onFilterChangeFinished(); void onFilteringStarted(); void onViewChanged(); @@ -103,11 +106,10 @@ private slots: void onMenuTriggered( int action ); private: - TreeHeader* m_header; + ViewHeader* m_header; OverlayWidget* m_overlay; TreeModel* m_model; TreeProxyModel* m_proxyModel; -// PlaylistItemDelegate* m_delegate; AnimatedSpinner* m_loadingSpinner; bool m_updateContextView; @@ -115,9 +117,10 @@ private: QModelIndex m_contextMenuIndex; Tomahawk::ContextMenu* m_contextMenu; + QString m_emptyTip; bool m_showModes; QTimer m_timer; mutable QString m_guid; }; -#endif // ARTISTVIEW_H +#endif // TREEVIEW_H diff --git a/src/libtomahawk/playlist/XspfUpdater.cpp b/src/libtomahawk/playlist/XspfUpdater.cpp index 22c43fd4a..879184ba2 100644 --- a/src/libtomahawk/playlist/XspfUpdater.cpp +++ b/src/libtomahawk/playlist/XspfUpdater.cpp @@ -77,15 +77,20 @@ XspfUpdater::XspfUpdater( const playlist_ptr& pl, int interval, bool autoUpdate, XspfUpdater::~XspfUpdater() -{} +{ +} +#ifndef ENABLE_HEADLESS + QWidget* XspfUpdater::configurationWidget() const { return m_toggleCheckbox; } +#endif + void XspfUpdater::updateNow() diff --git a/src/libtomahawk/playlist/dynamic/DynamicView.cpp b/src/libtomahawk/playlist/dynamic/DynamicView.cpp index d55c03065..a1643195d 100644 --- a/src/libtomahawk/playlist/dynamic/DynamicView.cpp +++ b/src/libtomahawk/playlist/dynamic/DynamicView.cpp @@ -27,7 +27,6 @@ #include "PlaylistModel.h" #include "PlayableProxyModel.h" -#include "TrackHeader.h" #include "DynamicModel.h" #include "widgets/OverlayWidget.h" #include "utils/Logger.h" @@ -49,10 +48,6 @@ DynamicView::DynamicView( QWidget* parent ) , m_fadebg( false ) , m_fadeOnly( false ) { - setContentsMargins( 0, 0, 0, 0 ); - setFrameShape( QFrame::NoFrame ); - setAttribute( Qt::WA_MacShowFocusRect, 0 ); - m_fadeOutAnim.setDuration( FADE_LENGTH ); m_fadeOutAnim.setCurveShape( QTimeLine::LinearCurve ); m_fadeOutAnim.setFrameRange( 100, 0 ); @@ -71,18 +66,17 @@ DynamicView::DynamicView( QWidget* parent ) DynamicView::~DynamicView() { - } void -DynamicView::setDynamicModel( DynamicModel* model) +DynamicView::setDynamicModel( DynamicModel* model ) { m_model = model; PlaylistView::setPlaylistModel( m_model ); connect( m_model, SIGNAL( trackCountChanged( unsigned int ) ), SLOT( onTrackCountChanged( unsigned int ) ) ); - connect( m_model, SIGNAL( checkForOverflow() ), this, SLOT( checkForOverflow() ) ); + connect( m_model, SIGNAL( checkForOverflow() ), SLOT( checkForOverflow() ) ); } diff --git a/src/libtomahawk/playlist/dynamic/echonest/EchonestSteerer.cpp b/src/libtomahawk/playlist/dynamic/echonest/EchonestSteerer.cpp index f9c983b9e..82a44d3c0 100644 --- a/src/libtomahawk/playlist/dynamic/echonest/EchonestSteerer.cpp +++ b/src/libtomahawk/playlist/dynamic/echonest/EchonestSteerer.cpp @@ -66,6 +66,15 @@ EchonestSteerer::EchonestSteerer( QWidget* parent ) // m_steerBottom->setFont( f ); // m_textL->addWidget( m_steerBottom ); + + QPalette p = m_steerTop->palette(); +#ifdef Q_OS_MAC + p.setBrush( QPalette::WindowText, Qt::white ); +#else + p.setBrush( QPalette::WindowText, palette().highlightedText() ); +#endif + m_steerTop->setPalette( p ); + m_layout->addLayout( m_textL, 1 ); m_amplifier = new QComboBox( this ); diff --git a/src/libtomahawk/resolvers/QtScriptResolver.cpp b/src/libtomahawk/resolvers/QtScriptResolver.cpp index 3cacfe102..d20d411eb 100644 --- a/src/libtomahawk/resolvers/QtScriptResolver.cpp +++ b/src/libtomahawk/resolvers/QtScriptResolver.cpp @@ -131,6 +131,7 @@ QtScriptResolverHelper::setResolverConfig( const QVariantMap& config ) m_resolverConfig = config; } + QString QtScriptResolverHelper::hmac( const QByteArray& key, const QByteArray &input ) { @@ -156,6 +157,7 @@ QtScriptResolverHelper::hmac( const QByteArray& key, const QByteArray &input ) #endif } + QString QtScriptResolverHelper::md5( const QByteArray& input ) { @@ -163,6 +165,7 @@ QtScriptResolverHelper::md5( const QByteArray& input ) return QString::fromLatin1( digest.toHex() ); } + void QtScriptResolverHelper::addCustomUrlHandler( const QString& protocol, const QString& callbackFuncName ) { @@ -172,6 +175,21 @@ QtScriptResolverHelper::addCustomUrlHandler( const QString& protocol, const QStr m_urlCallback = callbackFuncName; } + +QByteArray +QtScriptResolverHelper::base64Encode( const QByteArray& input ) +{ + return input.toBase64(); +} + + +QByteArray +QtScriptResolverHelper::base64Decode( const QByteArray& input ) +{ + return QByteArray::fromBase64( input ); +} + + QSharedPointer< QIODevice > QtScriptResolverHelper::customIODeviceFactory( const Tomahawk::result_ptr& result ) { @@ -227,7 +245,9 @@ QtScriptResolver::QtScriptResolver( const QString& scriptPath ) QtScriptResolver::~QtScriptResolver() { - Tomahawk::Pipeline::instance()->removeResolver( this ); + if ( !m_stopped ) + stop(); + delete m_engine; } @@ -253,6 +273,7 @@ QtScriptResolver::running() const return m_ready && !m_stopped; } + void QtScriptResolver::reload() { @@ -312,6 +333,7 @@ QtScriptResolver::init() m_ready = true; } + void QtScriptResolver::start() { @@ -361,8 +383,7 @@ QtScriptResolver::resolve( const Tomahawk::query_ptr& query ) } QVariantMap m = m_engine->mainFrame()->evaluateJavaScript( eval ).toMap(); - - if( m.isEmpty() ) + if ( m.isEmpty() ) { // if the resolver doesn't return anything, async api is used return; @@ -422,6 +443,7 @@ QtScriptResolver::parseResultVariantList( const QVariantList& reslist ) Q_ASSERT( !rp->mimetype().isEmpty() ); } + rp->setResolvedBy( this ); results << rp; } diff --git a/src/libtomahawk/resolvers/QtScriptResolver.h b/src/libtomahawk/resolvers/QtScriptResolver.h index 85d10d59e..c2dae5210 100644 --- a/src/libtomahawk/resolvers/QtScriptResolver.h +++ b/src/libtomahawk/resolvers/QtScriptResolver.h @@ -53,6 +53,9 @@ public: Q_INVOKABLE void addCustomUrlHandler( const QString& protocol, const QString& callbackFuncName ); + Q_INVOKABLE QByteArray base64Encode( const QByteArray& input ); + Q_INVOKABLE QByteArray base64Decode( const QByteArray& input ); + QSharedPointer customIODeviceFactory( const Tomahawk::result_ptr& result ); public slots: diff --git a/src/libtomahawk/resolvers/ScriptResolver.cpp b/src/libtomahawk/resolvers/ScriptResolver.cpp index 6e66fb6d6..bde843ab3 100644 --- a/src/libtomahawk/resolvers/ScriptResolver.cpp +++ b/src/libtomahawk/resolvers/ScriptResolver.cpp @@ -69,13 +69,14 @@ ScriptResolver::~ScriptResolver() msg[ "_msgtype" ] = "quit"; sendMessage( msg ); - bool finished = m_proc.waitForFinished( 2500 ); // might call handleMsg + bool finished = m_proc.state() != QProcess::Running || m_proc.waitForFinished( 2500 ); // might call handleMsg Tomahawk::Pipeline::instance()->removeResolver( this ); if ( !finished || m_proc.state() == QProcess::Running ) { qDebug() << "External resolver didn't exit after waiting 2s for it to die, killing forcefully"; + Q_ASSERT(false); #ifdef Q_OS_WIN m_proc.kill(); #else @@ -287,6 +288,7 @@ ScriptResolver::handleMsg( const QByteArray& msg ) Q_ASSERT( !rp->mimetype().isEmpty() ); } + rp->setResolvedBy( this ); results << rp; } @@ -440,7 +442,11 @@ void ScriptResolver::startProcess() #endif // Q_OS_WIN if( interpreter.isEmpty() ) + { + const QFileInfo info( runPath ); + m_proc.setWorkingDirectory( info.absolutePath() ); m_proc.start( runPath ); + } else m_proc.start( interpreter, QStringList() << filePath() ); diff --git a/src/libtomahawk/sip/SipPlugin.cpp b/src/libtomahawk/sip/SipPlugin.cpp index 694bf03e0..ad1d296fa 100644 --- a/src/libtomahawk/sip/SipPlugin.cpp +++ b/src/libtomahawk/sip/SipPlugin.cpp @@ -58,12 +58,16 @@ SipPlugin::serviceName() const } +#ifndef ENABLE_HEADLESS + QMenu* SipPlugin::menu() { return 0; } +#endif + Tomahawk::Accounts::Account* SipPlugin::account() const diff --git a/src/libtomahawk/taghandlers/tag.cpp b/src/libtomahawk/taghandlers/tag.cpp index 698cc0e07..6084900f6 100644 --- a/src/libtomahawk/taghandlers/tag.cpp +++ b/src/libtomahawk/taghandlers/tag.cpp @@ -34,6 +34,7 @@ #include #include #include +#include #include @@ -56,6 +57,12 @@ namespace Tomahawk if( file->tag() ) t = new OggTag( f.tag(), file->tag() ); } + else if( TagLib::RIFF::AIFF::File *file = + dynamic_cast< TagLib::RIFF::AIFF::File * >( f.file() ) ) + { + if( file->tag() ) + t = new ID3v2Tag( f.tag(), file->tag() ); + } else if( TagLib::Ogg::Speex::File *file = dynamic_cast< TagLib::Ogg::Speex::File * >( f.file() ) ) { diff --git a/src/libtomahawk/utils/AnimatedSpinner.cpp b/src/libtomahawk/utils/AnimatedSpinner.cpp index c3cffd547..2d66e7273 100644 --- a/src/libtomahawk/utils/AnimatedSpinner.cpp +++ b/src/libtomahawk/utils/AnimatedSpinner.cpp @@ -31,7 +31,7 @@ #include "utils/Logger.h" -AnimatedSpinner::AnimatedSpinner( QWidget *parent ) +AnimatedSpinner::AnimatedSpinner( QWidget* parent ) : QWidget( parent ) , m_showHide( new QTimeLine ) , m_animation( new QTimeLine ) @@ -41,7 +41,7 @@ AnimatedSpinner::AnimatedSpinner( QWidget *parent ) } -AnimatedSpinner::AnimatedSpinner( const QSize size, bool autoStart ) +AnimatedSpinner::AnimatedSpinner( const QSize& size, bool autoStart ) : QWidget() , m_showHide( new QTimeLine ) , m_animation( new QTimeLine ) @@ -260,3 +260,27 @@ AnimatedSpinner::segmentCount() const { return 11; } + + +LoadingSpinner::LoadingSpinner( QAbstractItemView* parent ) + : AnimatedSpinner( parent ) + , m_parent( parent ) +{ + if ( m_parent->model() ) + { + connect( m_parent->model(), SIGNAL( loadingStarted() ), SLOT( fadeIn() ), Qt::UniqueConnection ); + connect( m_parent->model(), SIGNAL( loadingFinished() ), SLOT( fadeOut() ), Qt::UniqueConnection ); + } + connect( m_parent, SIGNAL( modelChanged() ), SLOT( onViewModelChanged() ) ); +} + + +void +LoadingSpinner::onViewModelChanged() +{ + if ( m_parent->model() ) + { + connect( m_parent->model(), SIGNAL( loadingStarted() ), SLOT( fadeIn() ), Qt::UniqueConnection ); + connect( m_parent->model(), SIGNAL( loadingFinished() ), SLOT( fadeOut() ), Qt::UniqueConnection ); + } +} diff --git a/src/libtomahawk/utils/AnimatedSpinner.h b/src/libtomahawk/utils/AnimatedSpinner.h index 0bf502246..19ec3090e 100644 --- a/src/libtomahawk/utils/AnimatedSpinner.h +++ b/src/libtomahawk/utils/AnimatedSpinner.h @@ -26,6 +26,7 @@ #include #include #include +#include class QTimeLine; class QHideEvent; @@ -42,9 +43,10 @@ class QTimerEvent; class DLLEXPORT AnimatedSpinner : public QWidget { Q_OBJECT + public: - explicit AnimatedSpinner( QWidget *parent = 0 ); // widget mode - AnimatedSpinner( const QSize size, bool autoStart ); // pixmap mode + explicit AnimatedSpinner( QWidget* parent = 0 ); // widget mode + AnimatedSpinner( const QSize& size, bool autoStart ); // pixmap mode QSize sizeHint() const; @@ -87,4 +89,19 @@ private: bool m_autoCenter; }; + +class LoadingSpinner : public AnimatedSpinner +{ + Q_OBJECT + +public: + explicit LoadingSpinner( QAbstractItemView* parent = 0 ); // widget mode + +private slots: + void onViewModelChanged(); + +private: + QAbstractItemView* m_parent; +}; + #endif diff --git a/src/libtomahawk/utils/BinaryExtractWorker.cpp b/src/libtomahawk/utils/BinaryExtractWorker.cpp new file mode 100644 index 000000000..0c4353676 --- /dev/null +++ b/src/libtomahawk/utils/BinaryExtractWorker.cpp @@ -0,0 +1,105 @@ +/* === This file is part of Tomahawk Player - === + * + * Copyright 2010-2011, Christian Muehlhaeuser + * Copyright 2010-2011, Leo Franchi + * Copyright 2010-2012, Jeff Mitchell + * + * Tomahawk is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Tomahawk is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Tomahawk. If not, see . + */ + +#include "BinaryExtractWorker.h" + +#include +#include +#include +#include + +#include "utils/TomahawkUtils.h" +#include "utils/Logger.h" + + +namespace TomahawkUtils +{ + +void +BinaryExtractWorker::run() +{ + ScopedDeleter deleter( this ); + +#ifdef Q_OS_MAC + // Platform-specific handling of resolver payload now. We know it's good + // Unzip the file. + QFileInfo info( m_zipFileName ); + QDir tmpDir = QDir::tempPath(); + if ( !tmpDir.mkdir( info.baseName() ) ) + { + qWarning() << "Failed to create temporary directory to unzip in:" << tmpDir.absolutePath(); + return; + } + tmpDir.cd( info.baseName() ); + TomahawkUtils::unzipFileInFolder( info.absoluteFilePath(), tmpDir ); + + // On OSX it just contains 1 file, the resolver executable itself. For now. We just copy it to + // the Tomahawk.app/Contents/MacOS/ folder alongside the Tomahawk executable. + const QString dest = QCoreApplication::applicationDirPath(); + // Find the filename + const QDir toList( tmpDir.absolutePath() ); + const QStringList files = toList.entryList( QStringList(), QDir::Files ); + Q_ASSERT( files.size() == 1 ); + + const QString src = toList.absoluteFilePath( files.first() ); + qDebug() << "OS X: Copying binary resolver from to:" << src << dest; + + copyWithAuthentication( src, dest, m_receiver ); + + return; +#elif defined(Q_OS_WIN) || defined(Q_OS_LINUX) + // We unzip directly to the target location, just like normal attica resolvers + Q_ASSERT( m_receiver ); + if ( !m_receiver ) + return; + + const QString resolverId = m_receiver->property( "resolverid" ).toString(); + + Q_ASSERT( !resolverId.isEmpty() ); + if ( resolverId.isEmpty() ) + return; + + const QDir resolverPath( extractScriptPayload( m_zipFileName, resolverId ) ); + +#ifdef Q_OS_WIN + const QStringList files = resolverPath.entryList( QStringList() << "*.exe", QDir::Files ); +#elif defined(Q_OS_LINUX) + const QStringList files = resolverPath.entryList( QStringList() << "*_tomahawkresolver", QDir::Files ); +#endif + + qDebug() << "Found executables in unzipped binary resolver dir:" << files; + Q_ASSERT( files.size() == 1 ); + if ( files.size() < 1 ) + return; + + const QString resolverToUse = resolverPath.absoluteFilePath( files.first() ); + +#ifdef Q_OS_LINUX + QProcess p; + p.start( "chmod", QStringList() << "744" << resolverToUse, QIODevice::ReadOnly ); + p.waitForFinished(); +#endif + + QMetaObject::invokeMethod( m_receiver, "installSucceeded", Qt::QueuedConnection, Q_ARG( QString, resolverToUse ) ); + +#endif +} + +} diff --git a/src/libtomahawk/playlist/CollectionProxyModel.h b/src/libtomahawk/utils/BinaryExtractWorker.h similarity index 59% rename from src/libtomahawk/playlist/CollectionProxyModel.h rename to src/libtomahawk/utils/BinaryExtractWorker.h index 17ae207b2..52fceb301 100644 --- a/src/libtomahawk/playlist/CollectionProxyModel.h +++ b/src/libtomahawk/utils/BinaryExtractWorker.h @@ -1,6 +1,7 @@ /* === This file is part of Tomahawk Player - === * * Copyright 2010-2011, Christian Muehlhaeuser + * Copyright 2010-2011, Leo Franchi * Copyright 2010-2012, Jeff Mitchell * * Tomahawk is free software: you can redistribute it and/or modify @@ -17,24 +18,42 @@ * along with Tomahawk. If not, see . */ -#ifndef COLLECTIONPROXYMODEL_H -#define COLLECTIONPROXYMODEL_H +#ifndef BINARYEXTRACTWORKER_H +#define BINARYEXTRACTWORKER_H -#include "PlayableProxyModel.h" -#include "PlayableProxyModelPlaylistInterface.h" +#include #include "DllMacro.h" -class DLLEXPORT CollectionProxyModel : public PlayableProxyModel +namespace TomahawkUtils { -Q_OBJECT +class ScopedDeleter +{ public: - explicit CollectionProxyModel( QObject* parent = 0 ); - virtual ~CollectionProxyModel() {} - - virtual Tomahawk::playlistinterface_ptr playlistInterface(); + ScopedDeleter( QObject* o ) : m_o( 0 ) {} + ~ScopedDeleter() { m_o->deleteLater(); } +private: + QObject* m_o; }; -#endif // COLLECTIONPROXYMODEL_H + +class BinaryExtractWorker : public QThread +{ + Q_OBJECT +public: + BinaryExtractWorker( const QString& zipFilename, QObject* receiver ) : m_zipFileName( zipFilename ), m_receiver( receiver ) {} + virtual ~BinaryExtractWorker() {} + +protected: + virtual void run(); + +private: + QString m_zipFileName; + QObject* m_receiver; +}; + +} + +#endif \ No newline at end of file diff --git a/src/libtomahawk/utils/BinaryInstallerHelper.cpp b/src/libtomahawk/utils/BinaryInstallerHelper.cpp index e13cb9321..d061053ca 100644 --- a/src/libtomahawk/utils/BinaryInstallerHelper.cpp +++ b/src/libtomahawk/utils/BinaryInstallerHelper.cpp @@ -20,13 +20,16 @@ #include "accounts/AccountManager.h" #include "TomahawkSettingsGui.h" +#include -BinaryInstallerHelper::BinaryInstallerHelper( const QString& resolverId, bool createAccount, AtticaManager* manager ) +BinaryInstallerHelper::BinaryInstallerHelper( QTemporaryFile* tempFile, const QString& resolverId, bool createAccount, AtticaManager* manager ) : QObject( manager ) + , m_tempFile( tempFile ) , m_resolverId( resolverId ) , m_createAccount( createAccount ) , m_manager( QWeakPointer< AtticaManager >( manager ) ) { + Q_ASSERT( m_tempFile ); Q_ASSERT( !m_resolverId.isEmpty() ); Q_ASSERT( !m_manager.isNull() ); @@ -34,6 +37,13 @@ BinaryInstallerHelper::BinaryInstallerHelper( const QString& resolverId, bool cr } +BinaryInstallerHelper::~BinaryInstallerHelper() +{ + Q_ASSERT( m_tempFile ); + delete m_tempFile; +} + + void BinaryInstallerHelper::installSucceeded( const QString& path ) { diff --git a/src/libtomahawk/utils/BinaryInstallerHelper.h b/src/libtomahawk/utils/BinaryInstallerHelper.h index 511584581..33fbba7ce 100644 --- a/src/libtomahawk/utils/BinaryInstallerHelper.h +++ b/src/libtomahawk/utils/BinaryInstallerHelper.h @@ -22,19 +22,21 @@ #include +class QTemporaryFile; class BinaryInstallerHelper : public QObject { Q_OBJECT public: - explicit BinaryInstallerHelper( const QString& resolverId, bool createAccount, AtticaManager* manager ); + explicit BinaryInstallerHelper( QTemporaryFile* tempFile, const QString& resolverId, bool createAccount, AtticaManager* manager ); - virtual ~BinaryInstallerHelper() {} + virtual ~BinaryInstallerHelper(); public slots: void installSucceeded( const QString& path ); void installFailed(); private: + QTemporaryFile* m_tempFile; QString m_resolverId; bool m_createAccount; QWeakPointer m_manager; diff --git a/src/libtomahawk/utils/DropJobNotifier.cpp b/src/libtomahawk/utils/DropJobNotifier.cpp index 535c5a295..085e42a99 100644 --- a/src/libtomahawk/utils/DropJobNotifier.cpp +++ b/src/libtomahawk/utils/DropJobNotifier.cpp @@ -32,25 +32,25 @@ #include #include -class QNetworkReply; - using namespace Tomahawk; + DropJobNotifier::DropJobNotifier( QPixmap servicePixmap, QString service, DropJob::DropType type, QNetworkReply* job ) : JobStatusItem() , m_type( "unknown" ) , m_job( 0 ) - , m_pixmap ( servicePixmap ) - , m_service ( service ) + , m_pixmap( servicePixmap ) + , m_service( service ) { init( type ); - if( m_service.isEmpty() ) + if ( m_service.isEmpty() ) m_service = "DropJob"; connect( job, SIGNAL( finished() ), this, SLOT( setFinished() ) ); } + DropJobNotifier::DropJobNotifier( QPixmap pixmap, DropJob::DropType type ) : JobStatusItem() , m_job( 0 ) @@ -61,23 +61,24 @@ DropJobNotifier::DropJobNotifier( QPixmap pixmap, DropJob::DropType type ) DropJobNotifier::~DropJobNotifier() -{} +{ +} + void DropJobNotifier::init( DropJob::DropType type ) { - if( type == DropJob::Playlist ) - m_type = "playlist"; + if ( type == DropJob::Playlist ) + m_type = tr( "playlist" ); - if( type == DropJob::Artist ) - m_type = "artist"; + if ( type == DropJob::Artist ) + m_type = tr( "artist" ); - if( type == DropJob::Track ) - m_type = "track"; - - if( type == DropJob::Album ) - m_type = "album"; + if ( type == DropJob::Track ) + m_type = tr( "track" ); + if ( type == DropJob::Album ) + m_type = tr( "album" ); } @@ -87,6 +88,7 @@ DropJobNotifier::rightColumnText() const return QString(); } + QPixmap DropJobNotifier::icon() const { @@ -108,6 +110,7 @@ DropJobNotifier::mainText() const } } + void DropJobNotifier::setFinished() { diff --git a/src/utils/GuiHelpers.cpp b/src/libtomahawk/utils/GuiHelpers.cpp similarity index 98% rename from src/utils/GuiHelpers.cpp rename to src/libtomahawk/utils/GuiHelpers.cpp index 6a77d1b6c..a682f8b9c 100644 --- a/src/utils/GuiHelpers.cpp +++ b/src/libtomahawk/utils/GuiHelpers.cpp @@ -22,7 +22,7 @@ #include "accounts/Account.h" #include "accounts/AccountManager.h" -#include "DelegateConfigWrapper.h" +#include "accounts/DelegateConfigWrapper.h" #include "TomahawkSettings.h" namespace TomahawkUtils @@ -169,4 +169,4 @@ openAccountConfig( Tomahawk::Accounts::Account* account, QWidget* parent, bool s } // namespace TomahawkUtils -#include "GuiHelpers.moc" \ No newline at end of file +#include "GuiHelpers.moc" diff --git a/src/utils/GuiHelpers.h b/src/libtomahawk/utils/GuiHelpers.h similarity index 80% rename from src/utils/GuiHelpers.h rename to src/libtomahawk/utils/GuiHelpers.h index f17ccd43c..9fe8f3873 100644 --- a/src/utils/GuiHelpers.h +++ b/src/libtomahawk/utils/GuiHelpers.h @@ -19,6 +19,8 @@ #ifndef TOMAHAWK_GUI_HELPERS_H #define TOMAHAWK_GUI_HELPERS_H +#include "DllMacro.h" + class QWidget; namespace Tomahawk { namespace Accounts { @@ -29,8 +31,8 @@ namespace Tomahawk { namespace TomahawkUtils { - void createAccountFromFactory( Tomahawk::Accounts::AccountFactory*, QWidget* parent ); - void openAccountConfig( Tomahawk::Accounts::Account*, QWidget* parent, bool showDelete = false ); + DLLEXPORT void createAccountFromFactory( Tomahawk::Accounts::AccountFactory*, QWidget* parent ); + DLLEXPORT void openAccountConfig( Tomahawk::Accounts::Account*, QWidget* parent, bool showDelete = false ); } -#endif \ No newline at end of file +#endif diff --git a/src/libtomahawk/utils/Logger.cpp b/src/libtomahawk/utils/Logger.cpp index 4f4efd7f5..a34df872d 100644 --- a/src/libtomahawk/utils/Logger.cpp +++ b/src/libtomahawk/utils/Logger.cpp @@ -35,6 +35,7 @@ #define RELEASE_LEVEL_THRESHOLD 0 #define DEBUG_LEVEL_THRESHOLD LOGEXTRA +#define LOG_SQL_QUERIES 1 using namespace std; ofstream logfile; @@ -65,9 +66,19 @@ log( const char *msg, unsigned int debugLevel, bool toDisk = true ) if ( debugLevel > DEBUG_LEVEL_THRESHOLD ) toDisk = false; #endif + + #ifdef LOG_SQL_QUERIES + if ( debugLevel == LOGSQL ) + toDisk = true; + #endif if ( toDisk || (int)debugLevel <= s_threshold ) { + #ifdef LOG_SQL_QUERIES + if ( debugLevel == LOGSQL ) + logfile << "TSQLQUERY: "; + #endif + logfile << QTime::currentTime().toString().toAscii().data() << " [" << QString::number( debugLevel ).toAscii().data() << "]: " << msg << endl; logfile.flush(); } diff --git a/src/libtomahawk/utils/Logger.h b/src/libtomahawk/utils/Logger.h index a95fee6ef..6c1f69fdb 100644 --- a/src/libtomahawk/utils/Logger.h +++ b/src/libtomahawk/utils/Logger.h @@ -24,6 +24,13 @@ #include "DllMacro.h" +#define LOGDEBUG 1 +#define LOGINFO 2 +#define LOGEXTRA 5 +#define LOGVERBOSE 8 +#define LOGTHIRDPARTY 9 +#define LOGSQL 10 + namespace Logger { class DLLEXPORT TLog : public QDebug @@ -40,7 +47,15 @@ namespace Logger class DLLEXPORT TDebug : public TLog { public: - TDebug( unsigned int debugLevel = 1 ) : TLog( debugLevel ) + TDebug( unsigned int debugLevel = LOGDEBUG ) : TLog( debugLevel ) + { + } + }; + + class DLLEXPORT TSqlLog : public TLog + { + public: + TSqlLog() : TLog( LOGSQL ) { } }; @@ -51,11 +66,6 @@ namespace Logger #define tLog Logger::TLog #define tDebug Logger::TDebug - -#define LOGDEBUG 1 -#define LOGINFO 2 -#define LOGEXTRA 5 -#define LOGVERBOSE 8 -#define LOGTHIRDPARTY 9 +#define tSqlLog Logger::TSqlLog #endif // TOMAHAWK_LOGGER_H diff --git a/src/libtomahawk/utils/PixmapDelegateFader.cpp b/src/libtomahawk/utils/PixmapDelegateFader.cpp index f3adac4e4..b1f2bfa56 100644 --- a/src/libtomahawk/utils/PixmapDelegateFader.cpp +++ b/src/libtomahawk/utils/PixmapDelegateFader.cpp @@ -29,8 +29,6 @@ using namespace Tomahawk; -#define COVER_FADEIN 1000 - QWeakPointer< TomahawkUtils::SharedTimeLine > PixmapDelegateFader::s_stlInstance = QWeakPointer< TomahawkUtils::SharedTimeLine >(); @@ -51,7 +49,7 @@ PixmapDelegateFader::PixmapDelegateFader( const artist_ptr& artist, const QSize& { if ( !m_artist.isNull() ) { - connect( m_artist.data(), SIGNAL( updated() ), SLOT( trackChanged() ) ); + connect( m_artist.data(), SIGNAL( updated() ), SLOT( artistChanged() ) ); connect( m_artist.data(), SIGNAL( coverChanged() ), SLOT( artistChanged() ) ); m_currentReference = m_artist->cover( size, forceLoad ); } @@ -67,7 +65,7 @@ PixmapDelegateFader::PixmapDelegateFader( const album_ptr& album, const QSize& s { if ( !m_album.isNull() ) { - connect( m_album.data(), SIGNAL( updated() ), SLOT( trackChanged() ) ); + connect( m_album.data(), SIGNAL( updated() ), SLOT( albumChanged() ) ); connect( m_album.data(), SIGNAL( coverChanged() ), SLOT( albumChanged() ) ); m_currentReference = m_album->cover( size, forceLoad ); } @@ -102,6 +100,8 @@ PixmapDelegateFader::init() { if ( m_currentReference.isNull() ) m_defaultImage = true; + else + m_defaultImage = false; m_startFrame = 0; m_fadePct = 100; @@ -126,7 +126,7 @@ void PixmapDelegateFader::setSize( const QSize& size ) { m_size = size; - + if ( m_defaultImage ) { // No cover loaded yet, use default and don't fade in @@ -188,11 +188,11 @@ PixmapDelegateFader::setPixmap( const QPixmap& pixmap ) return; m_defaultImage = false; - QByteArray ba; - QBuffer buffer( &ba ); - buffer.open( QIODevice::WriteOnly ); - pixmap.save( &buffer, "PNG" ); - QString newImageMd5 = TomahawkUtils::md5( buffer.data() ); + QCryptographicHash hash( QCryptographicHash::Md5 ); + const QImage img = pixmap.toImage(); + hash.addData( (const char*)img.constBits(), img.byteCount() ); + const QString newImageMd5 = hash.result(); + if ( m_oldImageMd5 == newImageMd5 ) return; diff --git a/src/libtomahawk/utils/PixmapDelegateFader.h b/src/libtomahawk/utils/PixmapDelegateFader.h index ee0a71ac7..f79c58774 100644 --- a/src/libtomahawk/utils/PixmapDelegateFader.h +++ b/src/libtomahawk/utils/PixmapDelegateFader.h @@ -23,6 +23,7 @@ #include "Artist.h" #include "Album.h" #include "Query.h" +#include "utils/SharedTimeLine.h" #include #include diff --git a/src/libtomahawk/utils/SharedTimeLine.cpp b/src/libtomahawk/utils/SharedTimeLine.cpp new file mode 100644 index 000000000..cb48befed --- /dev/null +++ b/src/libtomahawk/utils/SharedTimeLine.cpp @@ -0,0 +1,64 @@ +/* === This file is part of Tomahawk Player - === + * + * Copyright 2010-2011, Christian Muehlhaeuser + * Copyright 2010-2011, Leo Franchi + * Copyright 2010-2012, Jeff Mitchell + * + * Tomahawk is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Tomahawk is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Tomahawk. If not, see . + */ + +#include "SharedTimeLine.h" + + +namespace TomahawkUtils +{ + +SharedTimeLine::SharedTimeLine() + : QObject( 0 ) + , m_refcount( 0 ) +{ + m_timeline.setCurveShape( QTimeLine::LinearCurve ); + m_timeline.setFrameRange( 0, INT_MAX ); + m_timeline.setDuration( INT_MAX ); + m_timeline.setUpdateInterval( 40 ); + connect( &m_timeline, SIGNAL( frameChanged( int ) ), SIGNAL( frameChanged( int ) ) ); +} + + +void +SharedTimeLine::connectNotify( const char* signal ) +{ + if ( signal == QMetaObject::normalizedSignature( SIGNAL( frameChanged( int ) ) ) ) { + m_refcount++; + if ( m_timeline.state() != QTimeLine::Running ) + m_timeline.start(); + } +} + + +void +SharedTimeLine::disconnectNotify( const char* signal ) +{ + if ( signal == QMetaObject::normalizedSignature( SIGNAL( frameChanged( int ) ) ) ) + { + m_refcount--; + if ( m_timeline.state() == QTimeLine::Running && m_refcount == 0 ) + { + m_timeline.stop(); + deleteLater(); + } + } +} + +} \ No newline at end of file diff --git a/src/libtomahawk/playlist/PlaylistProxyModel.h b/src/libtomahawk/utils/SharedTimeLine.h similarity index 54% rename from src/libtomahawk/playlist/PlaylistProxyModel.h rename to src/libtomahawk/utils/SharedTimeLine.h index 49adf1534..5d8d59602 100644 --- a/src/libtomahawk/playlist/PlaylistProxyModel.h +++ b/src/libtomahawk/utils/SharedTimeLine.h @@ -1,6 +1,7 @@ /* === This file is part of Tomahawk Player - === * * Copyright 2010-2011, Christian Muehlhaeuser + * Copyright 2010-2011, Leo Franchi * Copyright 2010-2012, Jeff Mitchell * * Tomahawk is free software: you can redistribute it and/or modify @@ -17,22 +18,43 @@ * along with Tomahawk. If not, see . */ -#ifndef PLAYLISTPROXYMODEL_H -#define PLAYLISTPROXYMODEL_H +#ifndef SHAREDTIMELINE_H +#define SHAREDTIMELINE_H -#include "PlayableProxyModel.h" +#include +#include #include "DllMacro.h" -class DLLEXPORT PlaylistProxyModel : public PlayableProxyModel +namespace TomahawkUtils { -Q_OBJECT -public: - explicit PlaylistProxyModel( QObject* parent = 0 ); - virtual ~PlaylistProxyModel() {} +class DLLEXPORT SharedTimeLine : public QObject +{ + Q_OBJECT - virtual Tomahawk::playlistinterface_ptr playlistInterface(); + public: + SharedTimeLine(); + + virtual ~SharedTimeLine() {} + + int currentFrame() { return m_timeline.currentFrame(); } + + void setUpdateInterval( int msec ) { if ( msec != m_timeline.updateInterval() ) m_timeline.setUpdateInterval( msec ); } + + signals: + void frameChanged( int ); + + protected slots: + virtual void connectNotify( const char *signal ); + + virtual void disconnectNotify( const char *signal ); + + private: + int m_refcount; + QTimeLine m_timeline; }; -#endif // PLAYLISTPROXYMODEL_H +} + +#endif \ No newline at end of file diff --git a/src/libtomahawk/utils/ShortenedLinkParser.cpp b/src/libtomahawk/utils/ShortenedLinkParser.cpp index 6452e1b0c..f683795ac 100644 --- a/src/libtomahawk/utils/ShortenedLinkParser.cpp +++ b/src/libtomahawk/utils/ShortenedLinkParser.cpp @@ -69,8 +69,9 @@ ShortenedLinkParser::handlesUrl( const QString& url ) url.contains( "rd.io" ) ); } + void -ShortenedLinkParser::lookupUrl ( const QString& url ) +ShortenedLinkParser::lookupUrl( const QString& url ) { tDebug() << "Looking up..." << url; QString cleaned = url; @@ -87,6 +88,7 @@ ShortenedLinkParser::lookupUrl ( const QString& url ) } + void ShortenedLinkParser::lookupFinished() { @@ -128,6 +130,8 @@ ShortenedLinkParser::checkFinished() } +#ifndef ENABLE_HEADLESS + QPixmap ShortenedLinkParser::pixmap() { @@ -136,3 +140,5 @@ ShortenedLinkParser::pixmap() return *s_pixmap; } + +#endif diff --git a/src/libtomahawk/utils/ShortenedLinkParser.h b/src/libtomahawk/utils/ShortenedLinkParser.h index 53131f932..b50ce17ec 100644 --- a/src/libtomahawk/utils/ShortenedLinkParser.h +++ b/src/libtomahawk/utils/ShortenedLinkParser.h @@ -26,7 +26,10 @@ #include #include #include -#include + +#ifndef ENABLE_HEADLESS + #include +#endif class QNetworkReply; @@ -61,13 +64,14 @@ private: void lookupUrl( const QString& url ); void checkFinished(); +#ifndef ENABLE_HEADLESS static QPixmap pixmap(); + static QPixmap* s_pixmap; +#endif QStringList m_links; QSet< QNetworkReply* > m_queries; DropJobNotifier* m_expandJob; - - static QPixmap* s_pixmap; }; } diff --git a/src/libtomahawk/utils/TomahawkCache.cpp b/src/libtomahawk/utils/TomahawkCache.cpp index e69baac16..51e58f313 100644 --- a/src/libtomahawk/utils/TomahawkCache.cpp +++ b/src/libtomahawk/utils/TomahawkCache.cpp @@ -101,7 +101,7 @@ QVariant Cache::getData ( const QString& identifier, const QString& key ) return data.data; } - tDebug( LOGVERBOSE ) << Q_FUNC_INFO << "No such client" << identifier; + tDebug( LOGVERBOSE ) << Q_FUNC_INFO << "No such key" << key; return QVariant(); } diff --git a/src/libtomahawk/utils/TomahawkUtils.cpp b/src/libtomahawk/utils/TomahawkUtils.cpp index 07471f42e..83cfbf821 100644 --- a/src/libtomahawk/utils/TomahawkUtils.cpp +++ b/src/libtomahawk/utils/TomahawkUtils.cpp @@ -25,6 +25,8 @@ #include "utils/TomahawkUtils.h" #include "utils/Logger.h" #include "Source.h" +#include "BinaryExtractWorker.h" +#include "SharedTimeLine.h" #ifdef LIBLASTFM_FOUND #include @@ -39,6 +41,7 @@ #include #include #include +#include #include #include @@ -54,7 +57,7 @@ #endif #ifdef QCA2_FOUND -#include + #include #endif namespace TomahawkUtils @@ -175,13 +178,6 @@ appLogDir() } -QString -sqlEscape( QString sql ) -{ - return sql.replace( "'", "''" ); -} - - QString timeToString( int seconds ) { @@ -300,17 +296,31 @@ extensionToMimetype( const QString& extension ) s_ext2mime.insert( "mp3", "audio/mpeg" ); s_ext2mime.insert( "ogg", "application/ogg" ); s_ext2mime.insert( "oga", "application/ogg" ); - s_ext2mime.insert( "flac", "audio/flac" ); s_ext2mime.insert( "mpc", "audio/x-musepack" ); s_ext2mime.insert( "wma", "audio/x-ms-wma" ); s_ext2mime.insert( "aac", "audio/mp4" ); s_ext2mime.insert( "m4a", "audio/mp4" ); s_ext2mime.insert( "mp4", "audio/mp4" ); + s_ext2mime.insert( "flac", "audio/flac" ); + s_ext2mime.insert( "aiff", "audio/aiff" ); + s_ext2mime.insert( "aif", "audio/aiff" ); } return s_ext2mime.value( extension, "unknown" ); } + +void +msleep( unsigned int ms ) +{ + #ifdef WIN32 + Sleep( ms ); + #else + ::usleep( ms * 1000 ); + #endif +} + + static QMutex s_noProxyHostsMutex; static QStringList s_noProxyHosts; @@ -461,7 +471,10 @@ nam() { QMutexLocker locker( &s_namAccessMutex ); if ( s_threadNamHash.contains( QThread::currentThread() ) ) + { + //tDebug() << Q_FUNC_INFO << "Found current thread in nam hash"; return s_threadNamHash[ QThread::currentThread() ]; + } if ( !s_threadNamHash.contains( TOMAHAWK_APPLICATION::instance()->thread() ) ) { @@ -473,6 +486,7 @@ nam() else return 0; } + tDebug() << Q_FUNC_INFO << "Found gui thread in nam hash"; // Create a nam for this thread based on the main thread's settings but with its own proxyfactory QNetworkAccessManager *mainNam = s_threadNamHash[ TOMAHAWK_APPLICATION::instance()->thread() ]; @@ -484,7 +498,9 @@ nam() s_threadNamHash[ QThread::currentThread() ] = newNam; - tDebug( LOGEXTRA ) << "created new nam for thread " << QThread::currentThread(); + tDebug( LOGEXTRA ) << Q_FUNC_INFO << "created new nam for thread " << QThread::currentThread(); + //QNetworkProxy proxy = dynamic_cast< TomahawkUtils::NetworkProxyFactory* >( newNam->proxyFactory() )->proxy(); + //tDebug() << Q_FUNC_INFO << "reply proxy properties: " << proxy.type() << proxy.hostName() << proxy.port(); return newNam; } @@ -521,6 +537,7 @@ setNam( QNetworkAccessManager* nam, bool noMutexLocker ) s_noProxyHostsMutex.unlock(); } + QNetworkProxyFactory::setApplicationProxyFactory( proxyFactory ); nam->setProxyFactory( proxyFactory ); s_threadNamHash[ QThread::currentThread() ] = nam; s_threadProxyFactoryHash[ QThread::currentThread() ] = proxyFactory; @@ -647,43 +664,6 @@ crash() } -SharedTimeLine::SharedTimeLine() - : QObject( 0 ) - , m_refcount( 0 ) -{ - m_timeline.setCurveShape( QTimeLine::LinearCurve ); - m_timeline.setFrameRange( 0, INT_MAX ); - m_timeline.setDuration( INT_MAX ); - m_timeline.setUpdateInterval( 40 ); - connect( &m_timeline, SIGNAL( frameChanged( int ) ), SIGNAL( frameChanged( int ) ) ); -} - -void -SharedTimeLine::connectNotify( const char* signal ) -{ - if ( signal == QMetaObject::normalizedSignature( SIGNAL( frameChanged( int ) ) ) ) { - m_refcount++; - if ( m_timeline.state() != QTimeLine::Running ) - m_timeline.start(); - } -} - - -void -SharedTimeLine::disconnectNotify( const char* signal ) -{ - if ( signal == QMetaObject::normalizedSignature( SIGNAL( frameChanged( int ) ) ) ) - { - m_refcount--; - if ( m_timeline.state() == QTimeLine::Running && m_refcount == 0 ) - { - m_timeline.stop(); - deleteLater(); - } - } -} - - bool verifyFile( const QString &filePath, const QString &signature ) { @@ -771,7 +751,6 @@ extractScriptPayload( const QString& filename, const QString& resolverId ) } resolverDir.cd( QString( "atticaresolvers/%1" ).arg( resolverId ) ); - if ( !unzipFileInFolder( filename, resolverDir ) ) { qWarning() << "Failed to unzip resolver. Ooops."; @@ -848,69 +827,11 @@ unzipFileInFolder( const QString &zipFileName, const QDir &folder ) void extractBinaryResolver( const QString& zipFilename, QObject* receiver ) { -#ifndef Q_OS_MAC - Q_UNUSED( zipFilename ); - Q_UNUSED( receiver ); -#endif - -#if !defined(Q_OS_MAC) && !defined (Q_OS_WIN) - Q_ASSERT( false ); - qWarning() << "NO SUPPORT YET FOR LINUX BINARY RESOLVERS!"; - return; -#endif - -#ifdef Q_OS_MAC - // Platform-specific handling of resolver payload now. We know it's good - // Unzip the file. - QFileInfo info( zipFilename ); - QDir tmpDir = QDir::tempPath(); - if ( !tmpDir.mkdir( info.baseName() ) ) - { - qWarning() << "Failed to create temporary directory to unzip in:" << tmpDir.absolutePath(); - return; - } - tmpDir.cd( info.baseName() ); - TomahawkUtils::unzipFileInFolder( info.absoluteFilePath(), tmpDir ); - - // On OSX it just contains 1 file, the resolver executable itself. For now. We just copy it to - // the Tomahawk.app/Contents/MacOS/ folder alongside the Tomahawk executable. - const QString dest = QCoreApplication::applicationDirPath(); - // Find the filename - const QDir toList( tmpDir.absolutePath() ); - const QStringList files = toList.entryList( QStringList(), QDir::Files ); - Q_ASSERT( files.size() == 1 ); - - const QString src = toList.absoluteFilePath( files.first() ); - qDebug() << "OS X: Copying binary resolver from to:" << src << dest; - - copyWithAuthentication( src, dest, receiver ); -#elif defined(Q_OS_WIN) - // We unzip directly to the target location, just like normal attica resolvers - Q_ASSERT( receiver ); - if ( !receiver ) - return; - - const QString resolverId = receiver->property( "resolverid" ).toString(); - - Q_ASSERT( !resolverId.isEmpty() ); - if ( resolverId.isEmpty() ) - return; - - const QDir resolverPath( extractScriptPayload( zipFilename, resolverId ) ); - const QStringList files = resolverPath.entryList( QStringList() << "*.exe", QDir::Files ); - qDebug() << "Found executables in unzipped binary resolver dir:" << files; - Q_ASSERT( files.size() == 1 ); - if ( files.size() < 1 ) - return; - - const QString resolverToUse = resolverPath.absoluteFilePath( files.first() ); - QMetaObject::invokeMethod(receiver, "installSucceeded", Qt::DirectConnection, Q_ARG( QString, resolverToUse ) ); - -#endif - - // No support for binary resolvers on linux! Shouldn't even have been allowed to see/install.. - Q_ASSERT( false ); + BinaryExtractWorker* worker = new BinaryExtractWorker( zipFilename, receiver ); + worker->start( QThread::LowPriority ); } } // ns + +#include "TomahawkUtils.moc" diff --git a/src/libtomahawk/utils/TomahawkUtils.h b/src/libtomahawk/utils/TomahawkUtils.h index 27350e3e1..5da2fab30 100644 --- a/src/libtomahawk/utils/TomahawkUtils.h +++ b/src/libtomahawk/utils/TomahawkUtils.h @@ -26,12 +26,10 @@ #include #include #include -#include #include #define RESPATH ":/data/" - class QDir; class QNetworkAccessManager; @@ -64,33 +62,6 @@ namespace TomahawkUtils }; - class DLLEXPORT SharedTimeLine : public QObject - { - Q_OBJECT - - public: - SharedTimeLine(); - - virtual ~SharedTimeLine() {} - - int currentFrame() { return m_timeline.currentFrame(); } - - void setUpdateInterval( int msec ) { if ( msec != m_timeline.updateInterval() ) m_timeline.setUpdateInterval( msec ); } - - signals: - void frameChanged( int ); - - protected slots: - virtual void connectNotify( const char *signal ); - - virtual void disconnectNotify( const char *signal ); - - private: - int m_refcount; - QTimeLine m_timeline; - }; - - class DLLEXPORT NetworkProxyFactory : public QNetworkProxyFactory { public: @@ -123,11 +94,12 @@ namespace TomahawkUtils DLLEXPORT QDir appDataDir(); DLLEXPORT QDir appLogDir(); - DLLEXPORT QString sqlEscape( QString sql ); DLLEXPORT QString timeToString( int seconds ); DLLEXPORT QString ageToString( const QDateTime& time, bool appendAgoString = false ); DLLEXPORT QString filesizeToString( unsigned int size ); DLLEXPORT QString extensionToMimetype( const QString& extension ); + + DLLEXPORT void msleep( unsigned int ms ); DLLEXPORT bool newerVersion( const QString& oldVersion, const QString& newVersion ); DLLEXPORT NetworkProxyFactory* proxyFactory( bool makeClone = false, bool noMutexLocker = false ); @@ -143,7 +115,6 @@ namespace TomahawkUtils DLLEXPORT QString extractScriptPayload( const QString& filename, const QString& resolverId ); DLLEXPORT bool unzipFileInFolder( const QString& zipFileName, const QDir& folder ); - // Extracting may be asynchronous, pass in a receiver object with the following slots: // extractSucceeded( const QString& path ) and extractFailed() to be notified/ DLLEXPORT void extractBinaryResolver( const QString& zipFilename, QObject* receiver ); diff --git a/src/libtomahawk/utils/TomahawkUtilsGui.cpp b/src/libtomahawk/utils/TomahawkUtilsGui.cpp index 98e25a84a..4dfef653b 100644 --- a/src/libtomahawk/utils/TomahawkUtilsGui.cpp +++ b/src/libtomahawk/utils/TomahawkUtilsGui.cpp @@ -31,6 +31,7 @@ #include #include #include +#include #include #include @@ -62,23 +63,24 @@ createDragPixmap( MediaType type, int itemCount ) { xCount = 5; size = 16; - } else if( itemCount > 9 ) + } + else if( itemCount > 9 ) { xCount = 4; size = 22; } - if( itemCount < xCount ) + if ( itemCount < xCount ) { xCount = itemCount; } int yCount = itemCount / xCount; - if( itemCount % xCount != 0 ) + if ( itemCount % xCount != 0 ) { ++yCount; } - if( yCount > xCount ) + if ( yCount > xCount ) { yCount = xCount; } @@ -105,7 +107,7 @@ createDragPixmap( MediaType type, int itemCount ) int x = 0; int y = 0; - for( int i = 0; i < itemCount; ++i ) + for ( int i = 0; i < itemCount; ++i ) { painter.drawPixmap( x, y, pixmap ); @@ -126,9 +128,29 @@ createDragPixmap( MediaType type, int itemCount ) } +void +drawShadowText( QPainter* painter, const QRect& rect, const QString& text, const QTextOption& textOption ) +{ + painter->save(); + + painter->drawText( rect, text, textOption ); + +/* QFont font = painter->font(); + font.setPixelSize( font.pixelSize() + 2 ); + painter->setFont( font ); + + painter->setPen( Qt::black ); + painter->drawText( rect, text, textOption );*/ + + painter->restore(); +} + + void drawBackgroundAndNumbers( QPainter* painter, const QString& text, const QRect& figRectIn ) { + painter->save(); + QRect figRect = figRectIn; if ( text.length() == 1 ) figRect.adjust( -painter->fontMetrics().averageCharWidth(), 0, 0, 0 ); @@ -155,15 +177,13 @@ drawBackgroundAndNumbers( QPainter* painter, const QString& text, const QRect& f ppath.arcTo( leftArcRect, 270, 180 ); painter->drawPath( ppath ); - painter->setPen( origpen ); - -#ifdef Q_WS_MAC figRect.adjust( -1, 0, 0, 0 ); -#endif - QTextOption to( Qt::AlignCenter ); + painter->setPen( origpen ); painter->setPen( Qt::white ); - painter->drawText( figRect.adjusted( -5, 0, 6, 0 ), text, to ); + painter->drawText( figRect.adjusted( -5, 0, 6, 0 ), text, QTextOption( Qt::AlignCenter ) ); + + painter->restore(); } @@ -277,10 +297,10 @@ QPixmap createAvatarFrame( const QPixmap &avatar ) { QPixmap frame( ":/data/images/avatar_frame.png" ); - QPixmap scaledAvatar = avatar.scaled( frame.height() * 75 / 100, frame.width() * 75 / 100, Qt::KeepAspectRatio, Qt::SmoothTransformation ); + QPixmap scaledAvatar = avatar.scaled( frame.height() * 75 / 100, frame.width() * 75 / 100, Qt::IgnoreAspectRatio, Qt::SmoothTransformation ); QPainter painter( &frame ); - painter.drawPixmap( (frame.height() - scaledAvatar.height()) / 2, (frame.width() - scaledAvatar.width()) / 2, scaledAvatar ); + painter.drawPixmap( ( frame.height() - scaledAvatar.height() ) / 2, ( frame.width() - scaledAvatar.width() ) / 2, scaledAvatar ); return frame; } @@ -448,7 +468,7 @@ drawRoundedButton( QPainter* painter, const QRect& btnRect, const QColor& color, else painter->fillPath( btnPath, color ); //painter->setPen( bg.darker() ); - + //painter->drawPath( btnPath ); btnPath = QPainterPath(); @@ -472,4 +492,27 @@ drawRoundedButton( QPainter* painter, const QRect& btnRect, const QColor& color, } +void +styleScrollBar( QScrollBar* scrollBar ) +{ + scrollBar->setStyleSheet( + "QScrollBar:horizontal { background-color: transparent; }" + "QScrollBar::handle:horizontal { border-height: 9px; margin-bottom: 6px;" + "border-image: url(" RESPATH "images/scrollbar-horizontal-handle.png) 3 3 3 3 stretch stretch;" + "border-top: 3px transparent; border-bottom: 3px transparent; border-right: 3px transparent; border-left: 3px transparent; }" + "QScrollBar::add-page:horizontal, QScrollBar::sub-page:horizontal { width: 0px; height: 0px; background: none; }" + "QScrollBar::add-line:horizontal, QScrollBar::sub-line:horizontal { width: 0px; height: 0px; background: none; }" + "QScrollBar:left-arrow:horizontal, QScrollBar::right-arrow:horizontal {" + "border: 0px; width: 0px; height: 0px; background: none; background-color: transparent; }" + + "QScrollBar:vertical { background-color: transparent; }" + "QScrollBar::handle:vertical { border-width: 9px; margin-right: 6px;" + "border-image: url(" RESPATH "images/scrollbar-vertical-handle.png) 3 3 3 3 stretch stretch;" + "border-top: 3px transparent; border-bottom: 3px transparent; border-right: 3px transparent; border-left: 3px transparent; }" + "QScrollBar::add-page:vertical, QScrollBar::sub-page:vertical { width: 0px; height: 0px; background: none; }" + "QScrollBar::add-line:vertical, QScrollBar::sub-line:vertical { width: 0px; height: 0px; background: none; }" + "QScrollBar:up-arrow:vertical, QScrollBar::down-arrow:vertical {" + "border: 0px; width: 0px; height: 0px; background: none; background-color: transparent; }" ); +} + } // ns diff --git a/src/libtomahawk/utils/TomahawkUtilsGui.h b/src/libtomahawk/utils/TomahawkUtilsGui.h index 266e630f0..6e8f7d8bf 100644 --- a/src/libtomahawk/utils/TomahawkUtilsGui.h +++ b/src/libtomahawk/utils/TomahawkUtilsGui.h @@ -24,6 +24,7 @@ #include #include #include +#include #include "TomahawkUtils.h" #include "DllMacro.h" @@ -34,6 +35,8 @@ class QPainter; class QPixmap; class QLayout; class QPalette; +class QRect; +class QScrollBar; namespace TomahawkUtils { @@ -47,7 +50,9 @@ namespace TomahawkUtils DLLEXPORT QColor alphaBlend( const QColor& colorFrom, const QColor& colorTo, float opacity ); DLLEXPORT QPixmap createDragPixmap( MediaType type, int itemCount = 1 ); + DLLEXPORT void drawShadowText( QPainter* p, const QRect& rect, const QString& text, const QTextOption& textOption ); DLLEXPORT void drawBackgroundAndNumbers( QPainter* p, const QString& text, const QRect& rect ); + DLLEXPORT void unmarginLayout( QLayout* layout ); DLLEXPORT int headerHeight(); @@ -58,6 +63,8 @@ namespace TomahawkUtils DLLEXPORT void prepareStyleOption( QStyleOptionViewItemV4* option, const QModelIndex& index, PlayableItem* item ); DLLEXPORT void drawRoundedButton( QPainter* painter, const QRect& btnRect, const QColor& color, const QColor &gradient1bottom = QColor(), const QColor& gradient2top = QColor(), const QColor& gradient2bottom = QColor() ); + + DLLEXPORT void styleScrollBar( QScrollBar* scrollBar ); } #endif // TOMAHAWKUTILSGUI_H diff --git a/src/libtomahawk/utils/TomahawkUtils_Mac.mm b/src/libtomahawk/utils/TomahawkUtils_Mac.mm index fc5c3d08c..28b03e0e3 100644 --- a/src/libtomahawk/utils/TomahawkUtils_Mac.mm +++ b/src/libtomahawk/utils/TomahawkUtils_Mac.mm @@ -16,17 +16,17 @@ * along with Tomahawk. If not, see . */ -#include "TomahawkUtils.h" - -#include "TomahawkUtils_Mac.h" #include "mac/FileHelpers.h" -#include -#include - #import #import +#include "TomahawkUtils.h" +#include "TomahawkUtils_Mac.h" + +#include +#include + @implementation MoveDelegate @@ -61,6 +61,8 @@ if ( receiver ) QMetaObject::invokeMethod(receiver, "installSucceeded", Qt::DirectConnection, Q_ARG(QString, path)); + [target release]; + } - (void)moveFailedWithError:(NSError *)error diff --git a/src/libtomahawk/utils/WidgetDragFilter.cpp b/src/libtomahawk/utils/WidgetDragFilter.cpp index 46797ca46..3d427d097 100644 --- a/src/libtomahawk/utils/WidgetDragFilter.cpp +++ b/src/libtomahawk/utils/WidgetDragFilter.cpp @@ -38,34 +38,42 @@ WidgetDragFilter::WidgetDragFilter( QObject* parent ) bool WidgetDragFilter::eventFilter( QObject* obj, QEvent* event ) { - if( m_target.isNull() || m_target.data() != obj ) + if ( m_target.isNull() || m_target.data() != obj ) return false; - if( event->type() == QEvent::MouseButtonPress ) { + if ( event->type() == QEvent::MouseButtonPress ) + { QMouseEvent *mouseEvent = static_cast( event ); - if( !canDrag( obj, mouseEvent ) ) + if ( !canDrag( obj, mouseEvent ) ) return false; - if( !( mouseEvent->modifiers() == Qt::NoModifier && mouseEvent->button() == Qt::LeftButton ) ) + if ( !( mouseEvent->modifiers() == Qt::NoModifier && mouseEvent->button() == Qt::LeftButton ) ) return false; + m_dragPoint = mouseEvent->pos(); m_dragStarted = true; return false; - } else if( event->type() == QEvent::MouseMove ) { - if( !m_dragStarted ) + } + else if ( event->type() == QEvent::MouseMove ) + { + if ( !m_dragStarted ) return false; - QMouseEvent* e = static_cast(event); - if( !canDrag( obj, e ) ) { - m_dragStarted = false; + QMouseEvent* e = static_cast(event); + if ( !canDrag( obj, e ) ) + { + m_dragStarted = false; return false; } - if( e->buttons().testFlag( Qt::LeftButton ) ) { + + if ( e->buttons().testFlag( Qt::LeftButton ) ) + { m_target.data()->window()->move( m_target.data()->window()->pos() + ( e->pos() - m_dragPoint ) ); return true; } - } else if( event->type() == QEvent::MouseButtonRelease ) { - m_dragStarted = false; } + else if ( event->type() == QEvent::MouseButtonRelease ) + m_dragStarted = false; + return false; } @@ -76,38 +84,39 @@ WidgetDragFilter::eventFilter( QObject* obj, QEvent* event ) bool WidgetDragFilter::canDrag( QObject* obj, QMouseEvent* ev ) const { - if( !obj->isWidgetType() ) + if ( !obj->isWidgetType() ) return false; QWidget* w = static_cast< QWidget* >( obj ); - if( QWidget::mouseGrabber() ) + if ( QWidget::mouseGrabber() ) return false; - if( w->cursor().shape() != Qt::ArrowCursor ) + if ( w->cursor().shape() != Qt::ArrowCursor ) return false; // Now we check various things about the child position and mouse QPoint position( ev->pos() ); QWidget* child = w->childAt( position ); - if( child && child->cursor().shape() != Qt::ArrowCursor ) return false; + if ( child && child->cursor().shape() != Qt::ArrowCursor ) + return false; // Don't want to drag menubars when selecting an action - if( QMenuBar* menuBar = qobject_cast( w ) ) + if ( QMenuBar* menuBar = qobject_cast( w ) ) { // check if there is an active action - if( menuBar->activeAction() && menuBar->activeAction()->isEnabled() ) return false; + if ( menuBar->activeAction() && menuBar->activeAction()->isEnabled() ) + return false; // check if action at position exists and is enabled - if( QAction* action = menuBar->actionAt( position ) ) + if ( QAction* action = menuBar->actionAt( position ) ) { - if( action->isSeparator() ) return true; - if( action->isEnabled() ) return false; + if ( action->isSeparator() ) + return true; + if ( action->isEnabled() ) + return false; } - // return true in all other cases - return true; - } return true; diff --git a/src/libtomahawk/widgets/AnimatedSplitter.cpp b/src/libtomahawk/widgets/AnimatedSplitter.cpp index 93a941c83..539433136 100644 --- a/src/libtomahawk/widgets/AnimatedSplitter.cpp +++ b/src/libtomahawk/widgets/AnimatedSplitter.cpp @@ -63,6 +63,7 @@ AnimatedSplitter::addWidget( AnimatedWidget* widget ) connect( widget, SIGNAL( hideWidget() ), SLOT( onHideRequest() ) ); connect( widget, SIGNAL( sizeHintChanged( QSize ) ), SLOT( onShowRequest() ) ); connect( widget, SIGNAL( sizeChanged( QSize ) ), SLOT( onSizeChanged( QSize ) ) ); + connect( widget, SIGNAL( resizeBy( QPoint ) ), SLOT( onResizeRequest( QPoint ) ) ); connect( this, SIGNAL( shown( QWidget*, bool ) ), widget, SLOT( onShown( QWidget*, bool ) ) ); connect( this, SIGNAL( hidden( QWidget*, bool ) ), widget, SLOT( onHidden( QWidget*, bool ) ) ); @@ -70,32 +71,9 @@ AnimatedSplitter::addWidget( AnimatedWidget* widget ) void -AnimatedSplitter::onShowRequest() +AnimatedSplitter::changeSize( QWidget* child, const QSize& size ) { - AnimatedWidget* w = (AnimatedWidget*)(sender()); - if ( indexOf( w ) > 0 ) - show( indexOf( w ) ); - else - qDebug() << "Could not find widget:" << sender(); -} - - -void -AnimatedSplitter::onHideRequest() -{ - AnimatedWidget* w = (AnimatedWidget*)(sender()); - if ( indexOf( w ) > 0 ) - hide( indexOf( w ) ); - else - qDebug() << "Could not find widget:" << sender(); -} - - -void -AnimatedSplitter::onSizeChanged( const QSize& size ) -{ - AnimatedWidget* w = (AnimatedWidget*)(sender()); - int wi = indexOf( w ); + int wi = indexOf( child ); QList< int > sizes; for ( int i = 0; i < count(); i ++ ) @@ -127,6 +105,58 @@ AnimatedSplitter::onSizeChanged( const QSize& size ) } +void +AnimatedSplitter::onResizeRequest( const QPoint& delta ) +{ + AnimatedWidget* w = (AnimatedWidget*)(sender()); + if ( indexOf( w ) > 0 ) + { + int newheight = w->height() + delta.y(); + if ( newheight <= w->hiddenSize().height() ) + { + w->hide(); + } + else + changeSize( w, QSize( w->width(), newheight ) ); + } + else + Q_ASSERT( false ); +} + + +void +AnimatedSplitter::onShowRequest() +{ + AnimatedWidget* w = (AnimatedWidget*)(sender()); + if ( indexOf( w ) > 0 ) + show( indexOf( w ) ); + else + Q_ASSERT( false ); +} + + +void +AnimatedSplitter::onHideRequest() +{ + AnimatedWidget* w = (AnimatedWidget*)(sender()); + if ( indexOf( w ) > 0 ) + hide( indexOf( w ) ); + else + Q_ASSERT( false ); +} + + +void +AnimatedSplitter::onSizeChanged( const QSize& size ) +{ + AnimatedWidget* w = (AnimatedWidget*)(sender()); + if ( indexOf( w ) > 0 ) + changeSize( w, size ); + else + Q_ASSERT( false ); +} + + void AnimatedSplitter::setGreedyWidget( int index ) { @@ -247,6 +277,8 @@ AnimatedWidget::onAnimationFinished() { setFixedHeight( hiddenSize().height() ); } + + emit animationFinished(); } diff --git a/src/libtomahawk/widgets/AnimatedSplitter.h b/src/libtomahawk/widgets/AnimatedSplitter.h index 4e47d77b9..d113e769e 100644 --- a/src/libtomahawk/widgets/AnimatedSplitter.h +++ b/src/libtomahawk/widgets/AnimatedSplitter.h @@ -49,11 +49,14 @@ protected: virtual QSplitterHandle* createHandle(); private slots: + void changeSize( QWidget* child, const QSize& size ); + void onShowRequest(); void onHideRequest(); void onSizeChanged( const QSize& size ); - + void onResizeRequest( const QPoint& delta ); + private: int m_greedyIndex; }; @@ -95,10 +98,16 @@ public slots: virtual void onShown( QWidget*, bool animated ); virtual void onHidden( QWidget*, bool animated ); + virtual void hide() { emit hideWidget(); } + virtual void show() { emit showWidget(); } + signals: void showWidget(); void hideWidget(); + + void animationFinished(); + void resizeBy( const QPoint& delta ); void sizeChanged( const QSize& size ); void sizeHintChanged( const QSize& size ); void hiddenSizeChanged(); diff --git a/src/libtomahawk/widgets/BreadcrumbButton.cpp b/src/libtomahawk/widgets/BreadcrumbButton.cpp index 3f1aa2809..f4f385123 100644 --- a/src/libtomahawk/widgets/BreadcrumbButton.cpp +++ b/src/libtomahawk/widgets/BreadcrumbButton.cpp @@ -34,7 +34,11 @@ using namespace Tomahawk; class BreadcrumbArrow : public QWidget { public: - BreadcrumbArrow(QWidget* parent) : QWidget(parent) {} + BreadcrumbArrow( QWidget* parent ) + : QWidget(parent) + { + setSizePolicy( QSizePolicy::Fixed, QSizePolicy::Fixed ); + } protected: virtual void paintEvent( QPaintEvent* ) { diff --git a/src/libtomahawk/widgets/FadingPixmap.h b/src/libtomahawk/widgets/FadingPixmap.h index 9096e2a40..5e4928817 100644 --- a/src/libtomahawk/widgets/FadingPixmap.h +++ b/src/libtomahawk/widgets/FadingPixmap.h @@ -20,6 +20,7 @@ #ifndef FADINGPIXMAP_H #define FADINGPIXMAP_H +#include "utils/SharedTimeLine.h" #include "utils/TomahawkUtils.h" #include diff --git a/src/libtomahawk/widgets/HeaderLabel.cpp b/src/libtomahawk/widgets/HeaderLabel.cpp index cfd3542a9..edec62258 100644 --- a/src/libtomahawk/widgets/HeaderLabel.cpp +++ b/src/libtomahawk/widgets/HeaderLabel.cpp @@ -20,17 +20,20 @@ #include #include +#include #include "utils/Logger.h" #include "utils/StyleHelper.h" #include "utils/TomahawkUtilsGui.h" - static const int s_defaultFontSize = 12; + HeaderLabel::HeaderLabel( QWidget* parent ) : QLabel( parent ) , m_parent( parent ) + , m_pressed( false ) + , m_moved( false ) { QFont f( font() ); f.setBold( true ); @@ -38,6 +41,7 @@ HeaderLabel::HeaderLabel( QWidget* parent ) setFont( f ); setFixedHeight( TomahawkUtils::headerHeight() ); + setMouseTracking( true ); } @@ -52,6 +56,7 @@ HeaderLabel::sizeHint() const return QLabel::sizeHint(); } + int HeaderLabel::defaultFontSize() { @@ -63,7 +68,14 @@ void HeaderLabel::mousePressEvent( QMouseEvent* event ) { QFrame::mousePressEvent( event ); - m_time.start(); + + if ( !m_moved ) + { + m_time.start(); + + m_pressed = true; + m_dragPoint = event->pos(); + } } @@ -71,8 +83,27 @@ void HeaderLabel::mouseReleaseEvent( QMouseEvent* event ) { QFrame::mouseReleaseEvent( event ); - if ( m_time.elapsed() < qApp->doubleClickInterval() ) + + if ( !m_moved && m_time.elapsed() < qApp->doubleClickInterval() ) emit clicked(); + + m_pressed = false; + m_moved = false; +} + + +void +HeaderLabel::mouseMoveEvent( QMouseEvent* event ) +{ + if ( m_pressed ) + { + QPoint delta = m_dragPoint - event->pos(); + if ( abs( delta.y() ) > 3 ) + { + m_moved = true; + emit resized( delta ); + } + } } diff --git a/src/libtomahawk/widgets/HeaderLabel.h b/src/libtomahawk/widgets/HeaderLabel.h index 4d015d5c9..88f244c7e 100644 --- a/src/libtomahawk/widgets/HeaderLabel.h +++ b/src/libtomahawk/widgets/HeaderLabel.h @@ -43,6 +43,7 @@ public: signals: void clicked(); + void resized( const QPoint& delta ); protected: // void changeEvent( QEvent* e ); @@ -50,10 +51,15 @@ protected: void mousePressEvent( QMouseEvent* event ); void mouseReleaseEvent( QMouseEvent* event ); + void mouseMoveEvent( QMouseEvent* event ); private: QWidget* m_parent; QTime m_time; + + QPoint m_dragPoint; + bool m_pressed; + bool m_moved; }; #endif // HEADERLABEL_H diff --git a/src/libtomahawk/widgets/NewReleasesWidget.cpp b/src/libtomahawk/widgets/NewReleasesWidget.cpp index f3ae283fe..c4e7631bc 100644 --- a/src/libtomahawk/widgets/NewReleasesWidget.cpp +++ b/src/libtomahawk/widgets/NewReleasesWidget.cpp @@ -38,8 +38,7 @@ #include "playlist/PlaylistModel.h" #include "playlist/TreeProxyModel.h" #include "playlist/PlaylistChartItemDelegate.h" -#include "widgets/OverlayWidget.h" -#include "utils/TomahawkUtils.h" +#include "utils/TomahawkUtilsGui.h" #include "utils/Logger.h" #include "Pipeline.h" @@ -60,9 +59,6 @@ NewReleasesWidget::NewReleasesWidget( QWidget* parent ) { ui->setupUi( this ); - ui->albumsView->setFrameShape( QFrame::NoFrame ); - ui->albumsView->setAttribute( Qt::WA_MacShowFocusRect, 0 ); - TomahawkUtils::unmarginLayout( layout() ); TomahawkUtils::unmarginLayout( ui->verticalLayout_2 ); TomahawkUtils::unmarginLayout( ui->breadCrumbLeft->layout() ); @@ -76,7 +72,6 @@ NewReleasesWidget::NewReleasesWidget( QWidget* parent ) connect( ui->breadCrumbLeft, SIGNAL( activateIndex( QModelIndex ) ), SLOT( leftCrumbIndexChanged(QModelIndex) ) ); - //m_playlistInterface = Tomahawk::playlistinterface_ptr( new ChartsPlaylistInterface( this ) ); m_workerThread = new QThread( this ); @@ -190,13 +185,12 @@ NewReleasesWidget::infoSystemInfo( Tomahawk::InfoSystem::InfoRequestData request if ( type == "albums" ) { - loader->setType( ChartDataLoader::Album ); loader->setData( returnedData[ "albums" ].value< QList< Tomahawk::InfoSystem::InfoStringHash > >() ); connect( loader, SIGNAL( albums( Tomahawk::ChartDataLoader*, QList< Tomahawk::album_ptr > ) ), this, SLOT( newReleasesLoaded( Tomahawk::ChartDataLoader*, QList ) ) ); - AlbumModel* albumModel = new AlbumModel( ui->albumsView ); + PlayableModel* albumModel = new PlayableModel( ui->albumsView ); m_albumModels[ releaseId ] = albumModel; @@ -348,12 +342,13 @@ NewReleasesWidget::parseNode( QStandardItem* parentItem, const QString &label, c void -NewReleasesWidget::setLeftViewAlbums( AlbumModel* model ) +NewReleasesWidget::setLeftViewAlbums( PlayableModel* model ) { - ui->albumsView->setAlbumModel( model ); + ui->albumsView->setPlayableModel( model ); ui->albumsView->proxyModel()->sort( -1 ); // disable sorting, must be called after artistsViewLeft->setTreeModel } + void NewReleasesWidget::newReleasesLoaded( ChartDataLoader* loader, const QList< album_ptr >& albums ) { @@ -361,7 +356,7 @@ NewReleasesWidget::newReleasesLoaded( ChartDataLoader* loader, const QList< albu Q_ASSERT( m_albumModels.contains( chartId ) ); if ( m_albumModels.contains( chartId ) ) - m_albumModels[ chartId ]->addAlbums( albums ); + m_albumModels[ chartId ]->append( albums ); m_workers.remove( loader ); loader->deleteLater(); diff --git a/src/libtomahawk/widgets/NewReleasesWidget.h b/src/libtomahawk/widgets/NewReleasesWidget.h index f61afb398..5e6c21cf7 100644 --- a/src/libtomahawk/widgets/NewReleasesWidget.h +++ b/src/libtomahawk/widgets/NewReleasesWidget.h @@ -30,8 +30,6 @@ #include "infosystem/InfoSystem.h" #include "ViewPage.h" -#include "utils/TomahawkUtils.h" - #include "DllMacro.h" class QSortFilterProxyModel; @@ -39,9 +37,9 @@ class QStandardItemModel; class QStandardItem; class TreeModel; class PlaylistModel; -class OverlayWidget; class TreeProxyModel; class AlbumModel; +class PlayableModel; namespace Ui { @@ -97,7 +95,7 @@ private slots: private: void setLeftViewArtists( TreeModel* artistModel ); - void setLeftViewAlbums( AlbumModel* albumModel ); + void setLeftViewAlbums( PlayableModel* albumModel ); void setLeftViewTracks( PlaylistModel* trackModel ); @@ -115,7 +113,7 @@ private: QSet< Tomahawk::ChartDataLoader* > m_workers; // Cache our model data - QHash< QString, AlbumModel* > m_albumModels; + QHash< QString, PlayableModel* > m_albumModels; QString m_queueItemToShow; QSet< QString > m_queuedFetches; QTimer* m_timer; diff --git a/src/libtomahawk/widgets/NewReleasesWidget.ui b/src/libtomahawk/widgets/NewReleasesWidget.ui index 1dc057717..f1e8a1b9e 100644 --- a/src/libtomahawk/widgets/NewReleasesWidget.ui +++ b/src/libtomahawk/widgets/NewReleasesWidget.ui @@ -16,7 +16,7 @@ - + true @@ -29,9 +29,9 @@ - AlbumView + GridView QListView -
playlist/AlbumView.h
+
playlist/GridView.h
Tomahawk::Breadcrumb diff --git a/src/libtomahawk/widgets/OverlayWidget.cpp b/src/libtomahawk/widgets/OverlayWidget.cpp index 83e43a2fc..a72066f23 100644 --- a/src/libtomahawk/widgets/OverlayWidget.cpp +++ b/src/libtomahawk/widgets/OverlayWidget.cpp @@ -22,6 +22,7 @@ #include #include +#include "PlayableProxyModel.h" #include "utils/Logger.h" #define CORNER_ROUNDNESS 8.0 @@ -32,22 +33,28 @@ OverlayWidget::OverlayWidget( QWidget* parent ) : QWidget( parent ) // this is on purpose! - , m_opacity( 0.00 ) , m_parent( parent ) + , m_itemView( 0 ) { - resize( 380, 128 ); - setAttribute( Qt::WA_TranslucentBackground, true ); + init(); +} - setOpacity( m_opacity ); - m_timer.setSingleShot( true ); - connect( &m_timer, SIGNAL( timeout() ), this, SLOT( hide() ) ); +OverlayWidget::OverlayWidget( QAbstractItemView* parent ) + : QWidget( parent ) // this is on purpose! + , m_parent( parent ) + , m_itemView( parent ) +{ + init(); -#ifdef Q_WS_MAC - QFont f( font() ); - f.setPointSize( f.pointSize() - 2 ); - setFont( f ); -#endif + if ( m_itemView->model() ) + { + connect( m_itemView->model(), SIGNAL( rowsInserted( QModelIndex, int, int ) ), SLOT( onViewChanged() ), Qt::UniqueConnection ); + connect( m_itemView->model(), SIGNAL( rowsRemoved( QModelIndex, int, int ) ), SLOT( onViewChanged() ), Qt::UniqueConnection ); + connect( m_itemView->model(), SIGNAL( loadingStarted() ), SLOT( onViewChanged() ), Qt::UniqueConnection ); + connect( m_itemView->model(), SIGNAL( loadingFinished() ), SLOT( onViewChanged() ), Qt::UniqueConnection ); + } + connect( m_itemView, SIGNAL( modelChanged() ), SLOT( onViewModelChanged() ) ); } @@ -56,6 +63,27 @@ OverlayWidget::~OverlayWidget() } +void +OverlayWidget::init() +{ + installEventFilter( m_parent ); + setAcceptDrops( true ); + + setAttribute( Qt::WA_TranslucentBackground, true ); + m_opacity = 0.00; + setOpacity( m_opacity ); + + m_timer.setSingleShot( true ); + connect( &m_timer, SIGNAL( timeout() ), this, SLOT( hide() ) ); + +#ifdef Q_WS_MAC + QFont f( font() ); + f.setPointSize( f.pointSize() - 2 ); + setFont( f ); +#endif +} + + void OverlayWidget::setOpacity( qreal opacity ) { @@ -78,6 +106,7 @@ void OverlayWidget::setText( const QString& text ) { m_text = text; + onViewChanged(); } @@ -92,7 +121,7 @@ OverlayWidget::show( int timeoutSecs ) animation->setEndValue( 1.0 ); animation->start(); - if( timeoutSecs > 0 ) + if ( timeoutSecs > 0 ) m_timer.start( timeoutSecs * 1000 ); } @@ -120,11 +149,61 @@ OverlayWidget::shown() const } +void +OverlayWidget::onViewChanged() +{ + if ( !m_itemView ) + return; + + PlayableProxyModel* model = qobject_cast( m_itemView->model() ); + if ( !model ) + return; + + if ( m_text.isEmpty() || model->rowCount( QModelIndex() ) || model->isLoading() ) + { + hide(); + } + else + { + show(); + } +} + + +void +OverlayWidget::onViewModelChanged() +{ + if ( !m_itemView ) + return; + + if ( m_itemView->model() ) + { + connect( m_itemView->model(), SIGNAL( rowsInserted( QModelIndex, int, int ) ), SLOT( onViewChanged() ), Qt::UniqueConnection ); + connect( m_itemView->model(), SIGNAL( rowsRemoved( QModelIndex, int, int ) ), SLOT( onViewChanged() ), Qt::UniqueConnection ); + connect( m_itemView->model(), SIGNAL( loadingStarted() ), SLOT( onViewChanged() ), Qt::UniqueConnection ); + connect( m_itemView->model(), SIGNAL( loadingFinished() ), SLOT( onViewChanged() ), Qt::UniqueConnection ); + + onViewChanged(); + } +} + + void OverlayWidget::paintEvent( QPaintEvent* event ) { Q_UNUSED( event ); + { + QSize maxiSize = QSize( (double)m_parent->width() * 0.70, (double)m_parent->height() * 0.70 ); + QSize prefSize = QSize( 380, 128 ); + int width = qMin( maxiSize.width(), prefSize.width() ); + int height = qMin( maxiSize.height(), prefSize.height() ); + QSize newSize = QSize( width, height ); + + if ( newSize != size() ) + resize( newSize ); + } + QPoint center( ( m_parent->width() - width() ) / 2, ( m_parent->height() - height() ) / 2 ); if ( center != pos() ) { @@ -169,6 +248,7 @@ OverlayWidget::paintEvent( QPaintEvent* event ) } p.setFont( f ); - p.setPen( palette().highlightedText().color() ); +// p.setPen( palette().highlightedText().color() ); + p.setPen( Qt::white ); p.drawText( r.adjusted( 8, 8, -8, -8 ), text(), to ); } diff --git a/src/libtomahawk/widgets/OverlayWidget.h b/src/libtomahawk/widgets/OverlayWidget.h index 91de2d2bf..c618cd118 100644 --- a/src/libtomahawk/widgets/OverlayWidget.h +++ b/src/libtomahawk/widgets/OverlayWidget.h @@ -32,6 +32,7 @@ Q_PROPERTY( qreal opacity READ opacity WRITE setOpacity ) public: OverlayWidget( QWidget* parent ); + OverlayWidget( QAbstractItemView* parent ); ~OverlayWidget(); qreal opacity() const { return m_opacity; } @@ -49,12 +50,20 @@ public slots: protected: // void changeEvent( QEvent* e ); void paintEvent( QPaintEvent* event ); + +private slots: + void onViewChanged(); + void onViewModelChanged(); private: + void init(); + QString m_text; qreal m_opacity; QWidget* m_parent; + QAbstractItemView* m_itemView; + QTimer m_timer; }; diff --git a/src/libtomahawk/widgets/QueryLabel.cpp b/src/libtomahawk/widgets/QueryLabel.cpp index d81e32843..017e9b3f2 100644 --- a/src/libtomahawk/widgets/QueryLabel.cpp +++ b/src/libtomahawk/widgets/QueryLabel.cpp @@ -30,6 +30,7 @@ #include "ContextMenu.h" #include "utils/TomahawkUtilsGui.h" #include "utils/Logger.h" +#include "ViewManager.h" #include "Source.h" #define BOXMARGIN 2 @@ -89,8 +90,11 @@ QueryLabel::init() m_useCustomPen = false; m_useCustomFont = false; - m_align = Qt::AlignLeft; + m_align = Qt::AlignLeft | Qt::AlignVCenter; m_mode = Qt::ElideMiddle; + + m_jumpLinkVisible = false; + m_jumpPixmap = QPixmap( RESPATH "images/jump-link.png" ).scaled( QSize( fontMetrics().height(), fontMetrics().height() ), Qt::KeepAspectRatio, Qt::SmoothTransformation ); } @@ -240,6 +244,14 @@ QueryLabel::setQuery( const Tomahawk::query_ptr& query ) } +void +QueryLabel::setJumpLinkVisible( bool visible ) +{ + m_jumpLinkVisible = visible; + repaint(); +} + + Qt::Alignment QueryLabel::alignment() const { @@ -466,6 +478,13 @@ QueryLabel::paintEvent( QPaintEvent* event ) p.drawText( r, m_align, track() ); r.adjust( trackX, 0, 0, 0 ); } + + if ( m_jumpLinkVisible ) + { + r.adjust( 6, 0, 0, 0 ); + r.setSize( m_jumpPixmap.size() ); + p.drawPixmap( r, m_jumpPixmap ); + } } p.restore(); @@ -527,6 +546,10 @@ QueryLabel::mouseReleaseEvent( QMouseEvent* event ) case Track: emit clickedTrack(); break; + + case Complete: + ViewManager::instance()->showCurrentTrack(); + break; default: emit clicked(); @@ -583,6 +606,7 @@ QueryLabel::mouseMoveEvent( QMouseEvent* event ) QRect hoverArea; m_hoverType = None; + if ( m_type & Artist && x < artistX ) { m_hoverType = Artist; @@ -603,12 +627,22 @@ QueryLabel::mouseMoveEvent( QMouseEvent* event ) hoverArea.setLeft( albumX + spacing ); hoverArea.setRight( trackX + contentsMargins().left() - 1 ); } + else if ( m_jumpLinkVisible && x < trackX + 6 + m_jumpPixmap.width() && x > trackX + 6 ) + { + m_hoverType = Complete; + } if ( hoverArea.width() ) { hoverArea.setY( 1 ); hoverArea.setHeight( height() - 2 ); } + + if ( m_hoverType != None ) + setCursor( Qt::PointingHandCursor ); + else + setCursor( Qt::ArrowCursor ); + if ( hoverArea != m_hoverArea ) { m_hoverArea = hoverArea; diff --git a/src/libtomahawk/widgets/QueryLabel.h b/src/libtomahawk/widgets/QueryLabel.h index f9d655dd4..3667a2c9e 100644 --- a/src/libtomahawk/widgets/QueryLabel.h +++ b/src/libtomahawk/widgets/QueryLabel.h @@ -22,6 +22,7 @@ #include #include #include +#include #include "Result.h" #include "Query.h" @@ -80,6 +81,7 @@ public: QFont font() const; void setExtraContentsMargins( int left, int top, int right, int bottom ); + void setJumpLinkVisible( bool visible ); virtual QSize sizeHint() const; virtual QSize minimumSizeHint() const; @@ -137,6 +139,9 @@ private: QRect m_hoverArea; QPoint m_dragPos; QMargins m_textMargins; + + bool m_jumpLinkVisible; + QPixmap m_jumpPixmap; }; #endif // QUERYLABEL_H diff --git a/src/libtomahawk/widgets/RecentPlaylistsModel.cpp b/src/libtomahawk/widgets/RecentPlaylistsModel.cpp index 573f02e07..ba0eca7bd 100644 --- a/src/libtomahawk/widgets/RecentPlaylistsModel.cpp +++ b/src/libtomahawk/widgets/RecentPlaylistsModel.cpp @@ -63,6 +63,8 @@ RecentPlaylistsModel::onRefresh() if ( m_timer->isActive() ) m_timer->stop(); + emit loadingStarted(); + DatabaseCommand_LoadAllSortedPlaylists* cmd = new DatabaseCommand_LoadAllSortedPlaylists( source_ptr() ); cmd->setLimit( 15 ); cmd->setSortOrder( DatabaseCommand_LoadAllPlaylists::ModificationTime ); @@ -117,6 +119,7 @@ RecentPlaylistsModel::playlistsLoaded( const QListresultsView->setGuid( "searchwidget" ); m_resultsModel = new PlaylistModel( ui->resultsView ); ui->resultsView->setPlaylistModel( m_resultsModel ); - ui->resultsView->overlay()->setEnabled( false ); ui->resultsView->sortByColumn( PlaylistModel::Score, Qt::DescendingOrder ); - m_albumsModel = new AlbumModel( ui->albumView ); - ui->albumView->setAlbumModel( m_albumsModel ); + m_albumsModel = new PlayableModel( ui->albumView ); + ui->albumView->setPlayableModel( m_albumsModel ); - m_artistsModel = new AlbumModel( ui->artistView ); - ui->artistView->setAlbumModel( m_artistsModel ); - - ui->artistView->setAutoFitItems( false ); - ui->albumView->setAutoFitItems( false ); - ui->artistView->setSpacing( 8 ); - ui->albumView->setSpacing( 8 ); + m_artistsModel = new PlayableModel( ui->artistView ); + ui->artistView->setPlayableModel( m_artistsModel ); ui->artistView->proxyModel()->sort( -1 ); ui->albumView->proxyModel()->sort( -1 ); TomahawkUtils::unmarginLayout( ui->verticalLayout ); - ui->artistView->setContentsMargins( 0, 0, 0, 0 ); - ui->artistView->setFrameShape( QFrame::NoFrame ); - ui->artistView->setAttribute( Qt::WA_MacShowFocusRect, 0 ); - - ui->albumView->setContentsMargins( 0, 0, 0, 0 ); - ui->albumView->setFrameShape( QFrame::NoFrame ); - ui->albumView->setAttribute( Qt::WA_MacShowFocusRect, 0 ); - - ui->resultsView->setContentsMargins( 0, 0, 0, 0 ); - ui->resultsView->setFrameShape( QFrame::NoFrame ); - ui->resultsView->setAttribute( Qt::WA_MacShowFocusRect, 0 ); - ui->resultsView->loadingSpinner()->fadeIn(); m_queries << Tomahawk::Query::get( search, uuid() ); @@ -151,22 +132,22 @@ SearchWidget::onResultsFound( const QList& results ) albums << result->album(); } - m_artistsModel->addArtists( artists ); - m_albumsModel->addAlbums( albums ); + m_artistsModel->append( artists ); + m_albumsModel->append( albums ); } void SearchWidget::onAlbumsFound( const QList& albums ) { - m_albumsModel->addAlbums( albums ); + m_albumsModel->append( albums ); } void SearchWidget::onArtistsFound( const QList& artists ) { - m_artistsModel->addArtists( artists ); + m_artistsModel->append( artists ); } diff --git a/src/libtomahawk/widgets/SearchWidget.h b/src/libtomahawk/widgets/SearchWidget.h index b7d026740..70f942bfe 100644 --- a/src/libtomahawk/widgets/SearchWidget.h +++ b/src/libtomahawk/widgets/SearchWidget.h @@ -31,7 +31,7 @@ #include "DllMacro.h" class QPushButton; -class AlbumModel; +class PlayableModel; class PlaylistModel; namespace Ui @@ -77,8 +77,8 @@ private: QString m_search; - AlbumModel* m_artistsModel; - AlbumModel* m_albumsModel; + PlayableModel* m_artistsModel; + PlayableModel* m_albumsModel; PlaylistModel* m_resultsModel; QList< Tomahawk::query_ptr > m_queries; }; diff --git a/src/libtomahawk/widgets/SearchWidget.ui b/src/libtomahawk/widgets/SearchWidget.ui index d1f81af0c..e2df0a078 100644 --- a/src/libtomahawk/widgets/SearchWidget.ui +++ b/src/libtomahawk/widgets/SearchWidget.ui @@ -29,8 +29,8 @@ 1 - - + + @@ -44,9 +44,9 @@
playlist/PlaylistView.h
- AlbumView + GridView QListView -
playlist/AlbumView.h
+
playlist/GridView.h
diff --git a/src/libtomahawk/widgets/SeekSlider.cpp b/src/libtomahawk/widgets/SeekSlider.cpp index 9a03f5c62..f956a5a70 100644 --- a/src/libtomahawk/widgets/SeekSlider.cpp +++ b/src/libtomahawk/widgets/SeekSlider.cpp @@ -31,7 +31,7 @@ SeekSlider::SeekSlider( QWidget* parent ) , m_timeLine( 0 ) { setFixedHeight( 20 ); - setStyleSheet( "QSlider::groove::horizontal {" + setStyleSheet( "QSlider::groove:horizontal {" "margin: 5px; border-width: 3px;" "border-image: url(" RESPATH "images/seek-slider-bkg.png) 3 3 3 3 stretch stretch;" "}" @@ -41,7 +41,7 @@ SeekSlider::SeekSlider( QWidget* parent ) "border-image: url(" RESPATH "images/seek-slider-level.png) 3 3 3 3 stretch stretch;" "}" - "QSlider::handle::horizontal {" + "QSlider::handle:horizontal {" "margin-bottom: -7px; margin-top: -7px;" "margin-left: -4px; margin-right: -4px;" "height: 17px; width: 16px;" diff --git a/src/libtomahawk/widgets/SocialPlaylistWidget.cpp b/src/libtomahawk/widgets/SocialPlaylistWidget.cpp index 69572d81f..cd42b8dfe 100644 --- a/src/libtomahawk/widgets/SocialPlaylistWidget.cpp +++ b/src/libtomahawk/widgets/SocialPlaylistWidget.cpp @@ -23,6 +23,7 @@ #include "database/DatabaseCommand_LoadDynamicPlaylist.h" #include "database/Database.h" #include "SourceList.h" +#include "PlayableModel.h" #include "dynamic/GeneratorInterface.h" #include "dynamic/database/DatabaseGenerator.h" #include "utils/Logger.h" @@ -36,7 +37,7 @@ QString SocialPlaylistWidget::s_mostPlayedPlaylistsQuery = "asd"; QString SocialPlaylistWidget::s_topForeignTracksQuery = "select track.name, artist.name, count(*) as counter from (select track from playback_log group by track, source), track, artist where track not in (select track from playback_log where source is null group by track) and track.id = track and artist.id = track.artist group by track order by counter desc"; SocialPlaylistWidget::SocialPlaylistWidget ( QWidget* parent ) - : QWidget ( parent ) + : QWidget( parent ) , ui( new Ui_SocialPlaylistWidget ) , m_topForeignTracksModel( 0 ) , m_popularNewAlbumsModel( 0 ) @@ -53,10 +54,6 @@ SocialPlaylistWidget::SocialPlaylistWidget ( QWidget* parent ) ui->mostPlayedPlaylists->setFrameShape( QFrame::NoFrame ); ui->mostPlayedPlaylists->setAttribute( Qt::WA_MacShowFocusRect, 0 ); - ui->newTracksView->setFrameShape( QFrame::NoFrame ); - ui->newTracksView->setAttribute( Qt::WA_MacShowFocusRect, 0 ); - ui->newAlbumsView->setFrameShape( QFrame::NoFrame ); - ui->newAlbumsView->setAttribute( Qt::WA_MacShowFocusRect, 0 ); TomahawkUtils::unmarginLayout( layout() ); TomahawkUtils::unmarginLayout( ui->verticalLayout->layout() ); @@ -75,8 +72,8 @@ SocialPlaylistWidget::SocialPlaylistWidget ( QWidget* parent ) m_topForeignTracksModel->setStyle( PlayableModel::Short ); ui->newTracksView->overlay()->setEnabled( false ); - m_popularNewAlbumsModel = new AlbumModel( ui->newAlbumsView ); - ui->newAlbumsView->setAlbumModel( m_popularNewAlbumsModel ); + m_popularNewAlbumsModel = new PlayableModel( ui->newAlbumsView ); + ui->newAlbumsView->setPlayableModel( m_popularNewAlbumsModel ); // TODO run the genericselect command // m_recentAlbumsModel->addFilteredCollection( collection_ptr(), 20, DatabaseCommand_AllAlbums::ModificationTime ); /* @@ -94,7 +91,6 @@ SocialPlaylistWidget::SocialPlaylistWidget ( QWidget* parent ) SocialPlaylistWidget::~SocialPlaylistWidget() { - } @@ -144,7 +140,7 @@ SocialPlaylistWidget::popularAlbumsFetched( QList< album_ptr > albums ) { m_popularNewAlbumsModel->clear(); - m_popularNewAlbumsModel->addAlbums( albums ); + m_popularNewAlbumsModel->append( albums ); } diff --git a/src/libtomahawk/widgets/SocialPlaylistWidget.h b/src/libtomahawk/widgets/SocialPlaylistWidget.h index 0afb813da..14ae0b7f4 100644 --- a/src/libtomahawk/widgets/SocialPlaylistWidget.h +++ b/src/libtomahawk/widgets/SocialPlaylistWidget.h @@ -38,7 +38,7 @@ #include "Album.h" #include "Query.h" -class AlbumModel; +class PlayableModel; class PlaylistModel; class TreeModel; @@ -81,7 +81,7 @@ private: Ui_SocialPlaylistWidget *ui; PlaylistModel* m_topForeignTracksModel; - AlbumModel* m_popularNewAlbumsModel; + PlayableModel* m_popularNewAlbumsModel; QString m_title; QString m_description; diff --git a/src/libtomahawk/widgets/SocialPlaylistWidget.ui b/src/libtomahawk/widgets/SocialPlaylistWidget.ui index bf1015e98..1dfc5327b 100644 --- a/src/libtomahawk/widgets/SocialPlaylistWidget.ui +++ b/src/libtomahawk/widgets/SocialPlaylistWidget.ui @@ -36,7 +36,7 @@
- + @@ -92,9 +92,9 @@
widgets/HeaderLabel.h
- AlbumView + GridView QListView -
playlist/AlbumView.h
+
playlist/GridView.h
PlaylistWidget diff --git a/src/libtomahawk/widgets/WelcomeWidget.cpp b/src/libtomahawk/widgets/WelcomeWidget.cpp index 1411799bc..0280b3285 100644 --- a/src/libtomahawk/widgets/WelcomeWidget.cpp +++ b/src/libtomahawk/widgets/WelcomeWidget.cpp @@ -32,6 +32,7 @@ #include "playlist/AlbumModel.h" #include "playlist/RecentlyPlayedModel.h" #include "widgets/OverlayWidget.h" +#include "utils/AnimatedSpinner.h" #include "utils/TomahawkUtils.h" #include "utils/Logger.h" #include "dynamic/GeneratorInterface.h" @@ -54,10 +55,6 @@ WelcomeWidget::WelcomeWidget( QWidget* parent ) ui->playlistWidget->setFrameShape( QFrame::NoFrame ); ui->playlistWidget->setAttribute( Qt::WA_MacShowFocusRect, 0 ); - ui->tracksView->setFrameShape( QFrame::NoFrame ); - ui->tracksView->setAttribute( Qt::WA_MacShowFocusRect, 0 ); - ui->additionsView->setFrameShape( QFrame::NoFrame ); - ui->additionsView->setAttribute( Qt::WA_MacShowFocusRect, 0 ); TomahawkUtils::unmarginLayout( layout() ); TomahawkUtils::unmarginLayout( ui->verticalLayout->layout() ); @@ -77,7 +74,7 @@ WelcomeWidget::WelcomeWidget( QWidget* parent ) ui->tracksView->setPlaylistModel( m_tracksModel ); m_recentAlbumsModel = new AlbumModel( ui->additionsView ); - ui->additionsView->setAlbumModel( m_recentAlbumsModel ); + ui->additionsView->setPlayableModel( m_recentAlbumsModel ); ui->additionsView->proxyModel()->sort( -1 ); connect( SourceList::instance(), SIGNAL( ready() ), SLOT( onSourcesReady() ) ); @@ -245,7 +242,7 @@ PlaylistDelegate::paint( QPainter* painter, const QStyleOptionViewItem& option, // right edge 10px past right edge of pixmapRect // bottom edge flush with bottom of pixmap QRect rect( pixmapRect.right() - width , 0, width - 8, 0 ); - rect.adjust( -1, 0, 0, 0 ); + rect.adjust( -2, 0, 0, 0 ); rect.setTop( pixmapRect.bottom() - painter->fontMetrics().height() - 1 ); rect.setBottom( pixmapRect.bottom() + 1 ); @@ -311,4 +308,14 @@ PlaylistWidget::PlaylistWidget( QWidget* parent ) : QListView( parent ) { m_overlay = new OverlayWidget( this ); + LoadingSpinner* spinner = new LoadingSpinner( this ); } + + +void +PlaylistWidget::setModel( QAbstractItemModel* model ) +{ + QListView::setModel( model ); + emit modelChanged(); +} + diff --git a/src/libtomahawk/widgets/WelcomeWidget.h b/src/libtomahawk/widgets/WelcomeWidget.h index bb5754fce..658f6e8aa 100644 --- a/src/libtomahawk/widgets/WelcomeWidget.h +++ b/src/libtomahawk/widgets/WelcomeWidget.h @@ -64,12 +64,20 @@ private: QPixmap m_playlistIcon, m_autoIcon, m_stationIcon, m_defaultAvatar; }; + class DLLEXPORT PlaylistWidget : public QListView { +Q_OBJECT + public: PlaylistWidget( QWidget* parent = 0 ); OverlayWidget* overlay() const { return m_overlay; } + + virtual void setModel( QAbstractItemModel* model ); + +signals: + void modelChanged(); private: OverlayWidget* m_overlay; diff --git a/src/libtomahawk/widgets/WelcomeWidget.ui b/src/libtomahawk/widgets/WelcomeWidget.ui index a46ad774f..e91e39612 100644 --- a/src/libtomahawk/widgets/WelcomeWidget.ui +++ b/src/libtomahawk/widgets/WelcomeWidget.ui @@ -36,7 +36,7 @@ - + true @@ -94,9 +94,9 @@
widgets/HeaderLabel.h
- AlbumView + GridView QListView -
playlist/AlbumView.h
+
playlist/GridView.h
PlaylistView diff --git a/src/libtomahawk/widgets/WhatsHotWidget.cpp b/src/libtomahawk/widgets/WhatsHotWidget.cpp index 94068899a..2d2c8ddef 100644 --- a/src/libtomahawk/widgets/WhatsHotWidget.cpp +++ b/src/libtomahawk/widgets/WhatsHotWidget.cpp @@ -34,11 +34,11 @@ #include "audio/AudioEngine.h" #include "dynamic/GeneratorInterface.h" +#include "playlist/PlayableModel.h" #include "playlist/PlaylistModel.h" #include "playlist/TreeProxyModel.h" #include "playlist/PlaylistChartItemDelegate.h" -#include "widgets/OverlayWidget.h" -#include "utils/TomahawkUtils.h" +#include "utils/TomahawkUtilsGui.h" #include "utils/Logger.h" #include "Pipeline.h" @@ -59,9 +59,6 @@ WhatsHotWidget::WhatsHotWidget( QWidget* parent ) { ui->setupUi( this ); - ui->albumsView->setFrameShape( QFrame::NoFrame ); - ui->albumsView->setAttribute( Qt::WA_MacShowFocusRect, 0 ); - TomahawkUtils::unmarginLayout( layout() ); TomahawkUtils::unmarginLayout( ui->stackLeft->layout() ); TomahawkUtils::unmarginLayout( ui->horizontalLayout->layout() ); @@ -78,9 +75,6 @@ WhatsHotWidget::WhatsHotWidget( QWidget* parent ) connect( ui->breadCrumbLeft, SIGNAL( activateIndex( QModelIndex ) ), SLOT( leftCrumbIndexChanged(QModelIndex) ) ); - ui->tracksViewLeft->setFrameShape( QFrame::NoFrame ); - ui->tracksViewLeft->setAttribute( Qt::WA_MacShowFocusRect, 0 ); - ui->tracksViewLeft->overlay()->setEnabled( false ); ui->tracksViewLeft->setHeaderHidden( true ); ui->tracksViewLeft->setHorizontalScrollBarPolicy( Qt::ScrollBarAlwaysOff ); PlaylistChartItemDelegate* del = new PlaylistChartItemDelegate( ui->tracksViewLeft, ui->tracksViewLeft->proxyModel() ); @@ -93,8 +87,6 @@ WhatsHotWidget::WhatsHotWidget( QWidget* parent ) artistsProxy->setDynamicSortFilter( true ); ui->artistsViewLeft->setProxyModel( artistsProxy ); - ui->artistsViewLeft->setFrameShape( QFrame::NoFrame ); - ui->artistsViewLeft->setAttribute( Qt::WA_MacShowFocusRect, 0 ); ui->artistsViewLeft->setHorizontalScrollBarPolicy( Qt::ScrollBarAlwaysOff ); ui->artistsViewLeft->header()->setVisible( true ); @@ -179,9 +171,15 @@ WhatsHotWidget::infoSystemInfo( Tomahawk::InfoSystem::InfoRequestData requestDat if ( requestData.caller != s_whatsHotIdentifier ) return; + if ( output.isNull() ) + { + tDebug( LOGVERBOSE ) << Q_FUNC_INFO << "Info came back empty"; + return; + } + if ( !output.canConvert< QVariantMap >() ) { - tDebug( LOGVERBOSE ) << Q_FUNC_INFO << "WhatsHot: Could not parse output"; + tDebug( LOGVERBOSE ) << Q_FUNC_INFO << "WhatsHot: Could not parse output into a map"; return; } @@ -264,7 +262,7 @@ WhatsHotWidget::infoSystemInfo( Tomahawk::InfoSystem::InfoRequestData requestDat TreeModel* artistsModel = new TreeModel( ui->artistsViewLeft ); artistsModel->setMode( InfoSystemMode ); - artistsModel->setColumnStyle( TreeModel::AllColumns ); + artistsModel->setStyle( PlayableModel::Collection ); m_artistModels[ chartId ] = artistsModel; @@ -273,13 +271,12 @@ WhatsHotWidget::infoSystemInfo( Tomahawk::InfoSystem::InfoRequestData requestDat } else if ( type == "albums" ) { - loader->setType( ChartDataLoader::Album ); loader->setData( returnedData[ "albums" ].value< QList< Tomahawk::InfoSystem::InfoStringHash > >() ); connect( loader, SIGNAL( albums( Tomahawk::ChartDataLoader*, QList< Tomahawk::album_ptr > ) ), this, SLOT( chartAlbumsLoaded( Tomahawk::ChartDataLoader*, QList< Tomahawk::album_ptr > ) ) ); - AlbumModel* albumModel = new AlbumModel( ui->albumsView ); + PlayableModel* albumModel = new PlayableModel( ui->albumsView ); m_albumModels[ chartId ] = albumModel; @@ -288,7 +285,6 @@ WhatsHotWidget::infoSystemInfo( Tomahawk::InfoSystem::InfoRequestData requestDat } else if ( type == "tracks" ) { - loader->setType( ChartDataLoader::Track ); loader->setData( returnedData[ "tracks" ].value< QList< Tomahawk::InfoSystem::InfoStringHash > >() ); @@ -453,9 +449,9 @@ WhatsHotWidget::parseNode( QStandardItem* parentItem, const QString &label, cons void -WhatsHotWidget::setLeftViewAlbums( AlbumModel* model ) +WhatsHotWidget::setLeftViewAlbums( PlayableModel* model ) { - ui->albumsView->setAlbumModel( model ); + ui->albumsView->setPlayableModel( model ); ui->albumsView->proxyModel()->sort( -1 ); // disable sorting, must be called after artistsViewLeft->setTreeModel ui->stackLeft->setCurrentIndex( 2 ); } @@ -523,7 +519,7 @@ WhatsHotWidget::chartAlbumsLoaded( ChartDataLoader* loader, const QList< album_p Q_ASSERT( m_albumModels.contains( chartId ) ); if ( m_albumModels.contains( chartId ) ) - m_albumModels[ chartId ]->addAlbums( albums ); + m_albumModels[ chartId ]->append( albums ); m_workers.remove( loader ); loader->deleteLater(); diff --git a/src/libtomahawk/widgets/WhatsHotWidget.h b/src/libtomahawk/widgets/WhatsHotWidget.h index cb8a8f635..851b4c281 100644 --- a/src/libtomahawk/widgets/WhatsHotWidget.h +++ b/src/libtomahawk/widgets/WhatsHotWidget.h @@ -29,8 +29,6 @@ #include "infosystem/InfoSystem.h" #include "ViewPage.h" -#include "utils/TomahawkUtils.h" - #include "DllMacro.h" class QSortFilterProxyModel; @@ -38,9 +36,8 @@ class QStandardItemModel; class QStandardItem; class TreeModel; class PlaylistModel; -class OverlayWidget; class TreeProxyModel; -class AlbumModel; +class PlayableModel; namespace Ui { @@ -98,7 +95,7 @@ private slots: private: void setLeftViewArtists( TreeModel* artistModel ); - void setLeftViewAlbums( AlbumModel* albumModel ); + void setLeftViewAlbums( PlayableModel* albumModel ); void setLeftViewTracks( PlaylistModel* trackModel ); @@ -116,7 +113,7 @@ private: QSet< Tomahawk::ChartDataLoader* > m_workers; // Cache our model data - QHash< QString, AlbumModel* > m_albumModels; + QHash< QString, PlayableModel* > m_albumModels; QHash< QString, TreeModel* > m_artistModels; QHash< QString, PlaylistModel* > m_trackModels; QString m_queueItemToShow; diff --git a/src/libtomahawk/widgets/WhatsHotWidget.ui b/src/libtomahawk/widgets/WhatsHotWidget.ui index 95e51f4d3..88eb41339 100644 --- a/src/libtomahawk/widgets/WhatsHotWidget.ui +++ b/src/libtomahawk/widgets/WhatsHotWidget.ui @@ -33,7 +33,7 @@ - + 320 @@ -47,7 +47,7 @@ - + true @@ -64,14 +64,14 @@ - AlbumView + GridView QListView -
playlist/AlbumView.h
+
playlist/GridView.h
- ArtistView + TreeView QTreeView -
ArtistView.h
+
TreeView.h
PlaylistView diff --git a/src/libtomahawk/widgets/infowidgets/AlbumInfoWidget.cpp b/src/libtomahawk/widgets/infowidgets/AlbumInfoWidget.cpp index aab6d209d..3dc71d192 100644 --- a/src/libtomahawk/widgets/infowidgets/AlbumInfoWidget.cpp +++ b/src/libtomahawk/widgets/infowidgets/AlbumInfoWidget.cpp @@ -25,43 +25,37 @@ #include "ViewManager.h" #include "database/Database.h" #include "playlist/TreeModel.h" -#include "playlist/AlbumModel.h" +#include "playlist/PlayableModel.h" +#include "Source.h" #include "database/DatabaseCommand_AllTracks.h" #include "database/DatabaseCommand_AllAlbums.h" -#include "utils/TomahawkUtils.h" +#include "utils/TomahawkUtilsGui.h" #include "utils/Logger.h" -#include "widgets/OverlayButton.h" -#include "widgets/OverlayWidget.h" - using namespace Tomahawk; AlbumInfoWidget::AlbumInfoWidget( const Tomahawk::album_ptr& album, QWidget* parent ) : QWidget( parent ) , ui( new Ui::AlbumInfoWidget ) - , m_infoId( uuid() ) { ui->setupUi( this ); - ui->albumsView->setFrameShape( QFrame::NoFrame ); - ui->albumsView->setAttribute( Qt::WA_MacShowFocusRect, 0 ); - ui->tracksView->setFrameShape( QFrame::NoFrame ); - ui->tracksView->setAttribute( Qt::WA_MacShowFocusRect, 0 ); - TomahawkUtils::unmarginLayout( layout() ); TomahawkUtils::unmarginLayout( ui->verticalLayout ); TomahawkUtils::unmarginLayout( ui->verticalLayout_2 ); - m_albumsModel = new AlbumModel( ui->albumsView ); - ui->albumsView->setAlbumModel( m_albumsModel ); + m_albumsModel = new PlayableModel( ui->albumsView ); + ui->albumsView->setPlayableModel( m_albumsModel ); + ui->albumsView->setEmptyTip( tr( "Sorry, we could not find any other albums for this artist!" ) ); m_tracksModel = new TreeModel( ui->tracksView ); m_tracksModel->setMode( Mixed ); ui->tracksView->setTreeModel( m_tracksModel ); ui->tracksView->setRootIsDecorated( false ); + ui->tracksView->setEmptyTip( tr( "Sorry, we could not find any tracks for this album!" ) ); m_pixmap = TomahawkUtils::defaultPixmap( TomahawkUtils::DefaultAlbumCover, TomahawkUtils::ScaledCover, QSize( 48, 48 ) ); @@ -162,7 +156,8 @@ AlbumInfoWidget::loadAlbums( bool autoRefetch ) connect( m_album->artist().data(), SIGNAL( albumsAdded( QList, Tomahawk::ModelMode ) ), SLOT( gotAlbums( QList ) ) ); - gotAlbums( m_album->artist()->albums( Mixed ) ); + if ( !m_album->artist()->albums( Mixed ).isEmpty() ) + gotAlbums( m_album->artist()->albums( Mixed ) ); /* tDebug() << "Auto refetching"; m_buttonAlbums->setChecked( false ); @@ -188,7 +183,7 @@ AlbumInfoWidget::gotAlbums( const QList& albums ) if ( al.contains( m_album ) ) al.removeAll( m_album ); - m_albumsModel->addAlbums( al ); + m_albumsModel->append( al ); } diff --git a/src/libtomahawk/widgets/infowidgets/AlbumInfoWidget.h b/src/libtomahawk/widgets/infowidgets/AlbumInfoWidget.h index 9cc4f9ccd..9d00c2847 100644 --- a/src/libtomahawk/widgets/infowidgets/AlbumInfoWidget.h +++ b/src/libtomahawk/widgets/infowidgets/AlbumInfoWidget.h @@ -39,9 +39,8 @@ #include "DllMacro.h" #include "Typedefs.h" -class AlbumModel; +class PlayableModel; class TreeModel; -class OverlayButton; namespace Ui { @@ -104,15 +103,13 @@ private: Tomahawk::album_ptr m_album; - AlbumModel* m_albumsModel; + PlayableModel* m_albumsModel; TreeModel* m_tracksModel; QString m_title; QString m_description; QString m_longDescription; QPixmap m_pixmap; - - QString m_infoId; }; #endif // ALBUMINFOWIDGET_H diff --git a/src/libtomahawk/widgets/infowidgets/AlbumInfoWidget.ui b/src/libtomahawk/widgets/infowidgets/AlbumInfoWidget.ui index 9ad34c135..ec146f484 100644 --- a/src/libtomahawk/widgets/infowidgets/AlbumInfoWidget.ui +++ b/src/libtomahawk/widgets/infowidgets/AlbumInfoWidget.ui @@ -22,7 +22,7 @@ 1 - + @@ -33,7 +33,7 @@
- +
@@ -48,14 +48,14 @@
widgets/HeaderLabel.h
- ArtistView + TreeView QTreeView -
ArtistView.h
+
TreeView.h
- AlbumView + GridView QListView -
playlist/AlbumView.h
+
playlist/GridView.h
diff --git a/src/libtomahawk/widgets/infowidgets/ArtistInfoWidget.cpp b/src/libtomahawk/widgets/infowidgets/ArtistInfoWidget.cpp index 7a32abff6..f2222479b 100644 --- a/src/libtomahawk/widgets/infowidgets/ArtistInfoWidget.cpp +++ b/src/libtomahawk/widgets/infowidgets/ArtistInfoWidget.cpp @@ -21,8 +21,11 @@ #include "ArtistInfoWidget_p.h" #include "ui_ArtistInfoWidget.h" +#include +#include + #include "audio/AudioEngine.h" -#include "playlist/TrackHeader.h" +#include "playlist/PlayableModel.h" #include "playlist/TreeModel.h" #include "playlist/PlaylistModel.h" #include "playlist/TreeProxyModel.h" @@ -31,15 +34,11 @@ #include "database/DatabaseCommand_AllTracks.h" #include "database/DatabaseCommand_AllAlbums.h" +#include "Pipeline.h" #include "utils/StyleHelper.h" #include "utils/TomahawkUtilsGui.h" #include "utils/Logger.h" -#include "widgets/OverlayButton.h" -#include "widgets/OverlayWidget.h" - -#include "Pipeline.h" - using namespace Tomahawk; @@ -47,47 +46,90 @@ ArtistInfoWidget::ArtistInfoWidget( const Tomahawk::artist_ptr& artist, QWidget* : QWidget( parent ) , ui( new Ui::ArtistInfoWidget ) , m_artist( artist ) - , m_infoId( uuid() ) { - ui->setupUi( this ); + QWidget* widget = new QWidget; + ui->setupUi( widget ); + + QPalette pal = palette(); + pal.setColor( QPalette::Window, QColor( "#323435" ) ); + + widget->setPalette( pal ); + widget->setAutoFillBackground( true ); m_plInterface = Tomahawk::playlistinterface_ptr( new MetaPlaylistInterface( this ) ); - ui->albums->setFrameShape( QFrame::NoFrame ); - ui->albums->setAttribute( Qt::WA_MacShowFocusRect, 0 ); - ui->relatedArtists->setFrameShape( QFrame::NoFrame ); - ui->relatedArtists->setAttribute( Qt::WA_MacShowFocusRect, 0 ); - ui->topHits->setFrameShape( QFrame::NoFrame ); - ui->topHits->setAttribute( Qt::WA_MacShowFocusRect, 0 ); - - TomahawkUtils::unmarginLayout( layout() ); - TomahawkUtils::unmarginLayout( ui->layoutWidget->layout() ); +/* TomahawkUtils::unmarginLayout( ui->layoutWidget->layout() ); TomahawkUtils::unmarginLayout( ui->layoutWidget1->layout() ); TomahawkUtils::unmarginLayout( ui->layoutWidget2->layout() ); - TomahawkUtils::unmarginLayout( ui->albumHeader->layout() ); + TomahawkUtils::unmarginLayout( ui->albumHeader->layout() );*/ - m_albumsModel = new AlbumModel( ui->albums ); - ui->albums->setAlbumModel( m_albumsModel ); + m_albumsModel = new PlayableModel( ui->albums ); + ui->albums->setPlayableModel( m_albumsModel ); + ui->topHits->setEmptyTip( tr( "Sorry, we could not find any albums for this artist!" ) ); - m_relatedModel = new AlbumModel( ui->relatedArtists ); -// m_relatedModel->setColumnStyle( TreeModel::TrackOnly ); - ui->relatedArtists->setAlbumModel( m_relatedModel ); -// ui->relatedArtists->setSortingEnabled( false ); + m_relatedModel = new PlayableModel( ui->relatedArtists ); + ui->relatedArtists->setPlayableModel( m_relatedModel ); ui->relatedArtists->proxyModel()->sort( -1 ); + ui->topHits->setEmptyTip( tr( "Sorry, we could not find any related artists!" ) ); m_topHitsModel = new PlaylistModel( ui->topHits ); m_topHitsModel->setStyle( PlayableModel::Short ); ui->topHits->setPlayableModel( m_topHitsModel ); ui->topHits->setSortingEnabled( false ); + ui->topHits->setEmptyTip( tr( "Sorry, we could not find any top hits for this artist!" ) ); + + ui->relatedArtists->setAutoFitItems( false ); + ui->relatedArtists->setWrapping( false ); + ui->relatedArtists->setVerticalScrollBarPolicy( Qt::ScrollBarAlwaysOff ); + ui->relatedArtists->setHorizontalScrollBarPolicy( Qt::ScrollBarAsNeeded ); + m_relatedModel->setItemSize( QSize( 170, 170 ) ); + ui->albums->setAutoFitItems( false ); + ui->albums->setWrapping( false ); + ui->albums->setVerticalScrollBarPolicy( Qt::ScrollBarAlwaysOff ); + ui->albums->setHorizontalScrollBarPolicy( Qt::ScrollBarAsNeeded ); + m_albumsModel->setItemSize( QSize( 170, 170 ) ); + + ui->topHits->setFrameShape( QFrame::StyledPanel ); + ui->topHits->setAttribute( Qt::WA_MacShowFocusRect, 0 ); m_pixmap = TomahawkUtils::defaultPixmap( TomahawkUtils::DefaultArtistImage, TomahawkUtils::ScaledCover, QSize( 48, 48 ) ); + ui->cover->setPixmap( TomahawkUtils::defaultPixmap( TomahawkUtils::DefaultArtistImage, TomahawkUtils::ScaledCover, QSize( ui->cover->sizeHint() ) ) ); connect( m_albumsModel, SIGNAL( loadingStarted() ), SLOT( onLoadingStarted() ) ); connect( m_albumsModel, SIGNAL( loadingFinished() ), SLOT( onLoadingFinished() ) ); - connect( Tomahawk::InfoSystem::InfoSystem::instance(), - SIGNAL( info( Tomahawk::InfoSystem::InfoRequestData, QVariant ) ), - SLOT( infoSystemInfo( Tomahawk::InfoSystem::InfoRequestData, QVariant ) ) ); + ui->biography->setStyleSheet( "QTextBrowser#biography { background-color: transparent; }" ); + ui->biography->setFrameShape( QFrame::NoFrame ); + ui->biography->setAttribute( Qt::WA_MacShowFocusRect, 0 ); + + QPalette p = ui->biography->palette(); + p.setColor( QPalette::Foreground, Qt::white ); + p.setColor( QPalette::Text, Qt::white ); + + ui->biography->setPalette( p ); + ui->label->setPalette( p ); + ui->label_2->setPalette( p ); + ui->label_3->setPalette( p ); + + ui->label->setContentsMargins( 0, 0, 0, 0 ); + ui->label_2->setContentsMargins( 0, 16, 0, 0 ); + ui->label_3->setContentsMargins( 0, 16, 0, 0 ); + + QScrollArea* area = new QScrollArea(); + area->setWidgetResizable( true ); + area->setWidget( widget ); + + area->setStyleSheet( "QScrollArea { background-color: #323435; }" ); + area->setFrameShape( QFrame::NoFrame ); + area->setAttribute( Qt::WA_MacShowFocusRect, 0 ); + + QVBoxLayout* layout = new QVBoxLayout(); + layout->addWidget( area ); + setLayout( layout ); + TomahawkUtils::unmarginLayout( layout ); + + TomahawkUtils::styleScrollBar( ui->albums->horizontalScrollBar() ); + TomahawkUtils::styleScrollBar( ui->relatedArtists->horizontalScrollBar() ); load( artist ); } @@ -154,38 +196,39 @@ void ArtistInfoWidget::load( const artist_ptr& artist ) { if ( !m_artist.isNull() ) + { disconnect( m_artist.data(), SIGNAL( updated() ), this, SLOT( onArtistImageUpdated() ) ); + disconnect( m_artist.data(), SIGNAL( similarArtistsLoaded() ), this, SLOT( onSimilarArtistsLoaded() ) ); + disconnect( m_artist.data(), SIGNAL( biographyLoaded() ), this, SLOT( onBiographyLoaded() ) ); + disconnect( m_artist.data(), SIGNAL( albumsAdded( QList, Tomahawk::ModelMode ) ), + this, SLOT( onAlbumsFound( QList, Tomahawk::ModelMode ) ) ); + disconnect( m_artist.data(), SIGNAL( tracksAdded( QList, Tomahawk::ModelMode, Tomahawk::collection_ptr ) ), + this, SLOT( onTracksFound( QList, Tomahawk::ModelMode ) ) ); + } m_artist = artist; m_title = artist->name(); - connect( artist.data(), SIGNAL( albumsAdded( QList, Tomahawk::ModelMode ) ), - SLOT( onAlbumsFound( QList, Tomahawk::ModelMode ) ) ); - - onAlbumsFound( artist->albums( Mixed ), Mixed ); - - Tomahawk::InfoSystem::InfoStringHash artistInfo; - artistInfo["artist"] = artist->name(); - - Tomahawk::InfoSystem::InfoRequestData requestData; - requestData.caller = m_infoId; - requestData.customData = QVariantMap(); - - requestData.input = artist->name(); - requestData.type = Tomahawk::InfoSystem::InfoArtistBiography; - Tomahawk::InfoSystem::InfoSystem::instance()->getInfo( requestData ); - - requestData.input = QVariant::fromValue< Tomahawk::InfoSystem::InfoStringHash >( artistInfo ); - - requestData.type = Tomahawk::InfoSystem::InfoArtistSimilars; - requestData.requestId = TomahawkUtils::infosystemRequestId(); - Tomahawk::InfoSystem::InfoSystem::instance()->getInfo( requestData ); - - requestData.type = Tomahawk::InfoSystem::InfoArtistSongs; - requestData.requestId = TomahawkUtils::infosystemRequestId(); - Tomahawk::InfoSystem::InfoSystem::instance()->getInfo( requestData ); - + connect( m_artist.data(), SIGNAL( biographyLoaded() ), SLOT( onBiographyLoaded() ) ); + connect( m_artist.data(), SIGNAL( similarArtistsLoaded() ), SLOT( onSimilarArtistsLoaded() ) ); connect( m_artist.data(), SIGNAL( updated() ), SLOT( onArtistImageUpdated() ) ); + connect( m_artist.data(), SIGNAL( albumsAdded( QList, Tomahawk::ModelMode ) ), + SLOT( onAlbumsFound( QList, Tomahawk::ModelMode ) ) ); + connect( m_artist.data(), SIGNAL( tracksAdded( QList, Tomahawk::ModelMode, Tomahawk::collection_ptr ) ), + SLOT( onTracksFound( QList, Tomahawk::ModelMode ) ) ); + + if ( !m_artist->albums( Mixed ).isEmpty() ) + onAlbumsFound( m_artist->albums( Mixed ), Mixed ); + + if ( !m_artist->tracks().isEmpty() ) + onTracksFound( m_artist->tracks(), Mixed ); + + if ( !m_artist->similarArtists().isEmpty() ) + onSimilarArtistsLoaded(); + + if ( !m_artist->biography().isEmpty() ) + onBiographyLoaded(); + onArtistImageUpdated(); } @@ -195,79 +238,33 @@ ArtistInfoWidget::onAlbumsFound( const QList& albums, Model { Q_UNUSED( mode ); - m_albumsModel->addAlbums( albums ); + m_albumsModel->append( albums ); } void -ArtistInfoWidget::infoSystemInfo( Tomahawk::InfoSystem::InfoRequestData requestData, QVariant output ) +ArtistInfoWidget::onTracksFound( const QList& queries, ModelMode mode ) { - if ( requestData.caller != m_infoId ) - return; + Q_UNUSED( mode ); - InfoSystem::InfoStringHash trackInfo; - trackInfo = requestData.input.value< InfoSystem::InfoStringHash >(); + m_topHitsModel->append( queries ); +} - if ( output.canConvert< QVariantMap >() ) - { - const QString artist = requestData.input.toString(); - if ( trackInfo["artist"] != m_artist->name() && artist != m_artist->name() ) - { - qDebug() << "Returned info was for:" << trackInfo["artist"] << "- was looking for:" << m_artist->name(); - return; - } - } - QVariantMap returnedData = output.value< QVariantMap >(); - switch ( requestData.type ) - { - case InfoSystem::InfoArtistBiography: - { - QVariantMap bmap = output.toMap(); +void +ArtistInfoWidget::onSimilarArtistsLoaded() +{ + m_relatedModel->append( m_artist->similarArtists() ); +} - foreach ( const QString& source, bmap.keys() ) - { - if ( m_longDescription.isEmpty() || source == "last.fm" ) - m_longDescription = bmap[ source ].toHash()[ "text" ].toString(); - } - emit longDescriptionChanged( m_longDescription ); - break; - } - case InfoSystem::InfoArtistSongs: - { - const QStringList tracks = returnedData["tracks"].toStringList(); - - QList< query_ptr > queries; - int i = 0; - foreach ( const QString& track, tracks ) - { - queries << Query::get( m_artist->name(), track, QString() ); - Pipeline::instance()->resolve( queries ); - - if ( ++i == 15 ) - break; - } - - m_topHitsModel->append( queries ); - break; - } - - case InfoSystem::InfoArtistSimilars: - { - const QStringList artists = returnedData["artists"].toStringList(); - QList al; - foreach ( const QString& artist, artists ) - { - al << Artist::get( artist ); - } - m_relatedModel->addArtists( al ); - break; - } - - default: - return; - } +void +ArtistInfoWidget::onBiographyLoaded() +{ + m_longDescription = m_artist->biography(); + emit longDescriptionChanged( m_longDescription ); + + ui->biography->setHtml( m_artist->biography() ); } @@ -279,6 +276,8 @@ ArtistInfoWidget::onArtistImageUpdated() m_pixmap = m_artist->cover( QSize( 0, 0 ) ); emit pixmapChanged( m_pixmap ); + + ui->cover->setPixmap( m_artist->cover( ui->cover->sizeHint() ) ); } diff --git a/src/libtomahawk/widgets/infowidgets/ArtistInfoWidget.h b/src/libtomahawk/widgets/infowidgets/ArtistInfoWidget.h index adebbb21c..9e1ac0279 100644 --- a/src/libtomahawk/widgets/infowidgets/ArtistInfoWidget.h +++ b/src/libtomahawk/widgets/infowidgets/ArtistInfoWidget.h @@ -35,13 +35,11 @@ #include "Typedefs.h" #include "PlaylistInterface.h" #include "ViewPage.h" -#include "infosystem/InfoSystem.h" #include "DllMacro.h" -class AlbumModel; +class PlayableModel; class PlaylistModel; -class OverlayButton; namespace Ui { @@ -78,6 +76,7 @@ public: virtual bool isTemporaryPage() const { return true; } virtual bool showStatsBar() const { return false; } + virtual bool showInfoBar() const { return false; } virtual bool jumpToCurrentTrack(); virtual bool isBeingPlayed() const; @@ -91,10 +90,12 @@ protected: void changeEvent( QEvent* e ); private slots: - void infoSystemInfo( Tomahawk::InfoSystem::InfoRequestData requestData, QVariant output ); void onArtistImageUpdated(); + void onBiographyLoaded(); void onAlbumsFound( const QList& albums, Tomahawk::ModelMode mode ); + void onTracksFound( const QList& queries, Tomahawk::ModelMode mode ); + void onSimilarArtistsLoaded(); void onLoadingStarted(); void onLoadingFinished(); @@ -104,15 +105,14 @@ private: Tomahawk::artist_ptr m_artist; - AlbumModel* m_relatedModel; - AlbumModel* m_albumsModel; + PlayableModel* m_relatedModel; + PlayableModel* m_albumsModel; PlaylistModel* m_topHitsModel; Tomahawk::playlistinterface_ptr m_plInterface; QString m_title; QString m_description; QString m_longDescription; - QString m_infoId; QPixmap m_pixmap; friend class MetaPlaylistInterface; diff --git a/src/libtomahawk/widgets/infowidgets/ArtistInfoWidget.ui b/src/libtomahawk/widgets/infowidgets/ArtistInfoWidget.ui index d7ca40046..ba975d2d0 100644 --- a/src/libtomahawk/widgets/infowidgets/ArtistInfoWidget.ui +++ b/src/libtomahawk/widgets/infowidgets/ArtistInfoWidget.ui @@ -6,84 +6,182 @@ 0 0 - 902 - 696 + 965 + 824
Form - + - - - Qt::Vertical + + + 16 - - 1 + + 12 - - - Qt::Horizontal - - - 1 - - - - - - - Top Hits - - - - - - - true - - - - - - - - - - - Related Artists - - - - - - - - - - - - + + 16 + + + 12 + + + - - - - - - Albums - - - - + + + + 20 + 75 + true + + + + Top Hits + + + 0 + - + + + + 0 + 300 + + + + true + + + + + + + + Arial + 20 + 75 + true + + + + Albums + + + 0 + + + + + + + + 0 + 0 + + + + + 0 + 190 + + + + + + + + + Arial + 20 + 75 + true + + + + Related Artists + + + 0 + + + + + + + + 0 + 0 + + + + + 0 + 190 + + + - - + + + + + 16 + + + + + + 0 + 0 + + + + + 220 + 220 + + + + Cover + + + Qt::AlignCenter + + + + + + + + 0 + 0 + + + + + 0 + 240 + + + + Qt::ScrollBarAlwaysOff + + + Qt::ScrollBarAlwaysOff + + + + + + @@ -94,29 +192,9 @@
playlist/PlaylistView.h
- HeaderLabel - QLabel -
widgets/HeaderLabel.h
-
- - HeaderWidget - QWidget -
widgets/HeaderWidget.h
-
- - ToggleButton - QPushButton -
widgets/ToggleButton.h
-
- - ArtistView - QTreeView -
ArtistView.h
-
- - AlbumView + GridView QListView -
AlbumView.h
+
GridView.h
diff --git a/src/libtomahawk/widgets/infowidgets/SourceInfoWidget.cpp b/src/libtomahawk/widgets/infowidgets/SourceInfoWidget.cpp index 7dc557539..fb02f275a 100644 --- a/src/libtomahawk/widgets/infowidgets/SourceInfoWidget.cpp +++ b/src/libtomahawk/widgets/infowidgets/SourceInfoWidget.cpp @@ -23,18 +23,15 @@ #include "ViewManager.h" #include "playlist/AlbumModel.h" -#include "playlist/CollectionFlatModel.h" #include "playlist/RecentlyAddedModel.h" #include "playlist/RecentlyPlayedModel.h" #include "database/Database.h" #include "database/DatabaseCommand_AllAlbums.h" -#include "utils/TomahawkUtils.h" +#include "utils/TomahawkUtilsGui.h" #include "utils/Logger.h" -#include "widgets/OverlayWidget.h" - SourceInfoWidget::SourceInfoWidget( const Tomahawk::source_ptr& source, QWidget* parent ) : QWidget( parent ) @@ -43,13 +40,6 @@ SourceInfoWidget::SourceInfoWidget( const Tomahawk::source_ptr& source, QWidget* { ui->setupUi( this ); - ui->historyView->setFrameShape( QFrame::NoFrame ); - ui->historyView->setAttribute( Qt::WA_MacShowFocusRect, 0 ); - ui->recentAlbumView->setFrameShape( QFrame::NoFrame ); - ui->recentAlbumView->setAttribute( Qt::WA_MacShowFocusRect, 0 ); - ui->recentCollectionView->setFrameShape( QFrame::NoFrame ); - ui->recentCollectionView->setAttribute( Qt::WA_MacShowFocusRect, 0 ); - TomahawkUtils::unmarginLayout( layout() ); TomahawkUtils::unmarginLayout( ui->horizontalLayout ); TomahawkUtils::unmarginLayout( ui->verticalLayout ); @@ -59,8 +49,6 @@ SourceInfoWidget::SourceInfoWidget( const Tomahawk::source_ptr& source, QWidget* ui->splitter->setStretchFactor( 0, 0 ); ui->splitter->setStretchFactor( 1, 1 ); - ui->historyView->overlay()->setEnabled( false ); - m_recentTracksModel = new RecentlyAddedModel( source, ui->recentCollectionView ); m_recentTracksModel->setStyle( PlayableModel::Short ); ui->recentCollectionView->setPlayableModel( m_recentTracksModel ); @@ -71,7 +59,7 @@ SourceInfoWidget::SourceInfoWidget( const Tomahawk::source_ptr& source, QWidget* ui->historyView->setPlaylistModel( m_historyModel ); m_recentAlbumModel = new AlbumModel( ui->recentAlbumView ); - ui->recentAlbumView->setAlbumModel( m_recentAlbumModel ); + ui->recentAlbumView->setPlayableModel( m_recentAlbumModel ); ui->recentAlbumView->proxyModel()->sort( -1 ); onCollectionChanged(); diff --git a/src/libtomahawk/widgets/infowidgets/SourceInfoWidget.ui b/src/libtomahawk/widgets/infowidgets/SourceInfoWidget.ui index e11eeaa15..de7638fff 100644 --- a/src/libtomahawk/widgets/infowidgets/SourceInfoWidget.ui +++ b/src/libtomahawk/widgets/infowidgets/SourceInfoWidget.ui @@ -32,7 +32,7 @@ - + 0 @@ -76,7 +76,7 @@ - + @@ -107,9 +107,9 @@
widgets/HeaderLabel.h
- AlbumView + GridView QListView -
playlist/AlbumView.h
+
playlist/GridView.h
PlaylistView @@ -117,9 +117,9 @@
playlist/PlaylistView.h
- CollectionView + TrackView QTreeView -
playlist/CollectionView.h
+
playlist/TrackView.h
diff --git a/src/libtomahawk/widgets/infowidgets/TrackInfoWidget.cpp b/src/libtomahawk/widgets/infowidgets/TrackInfoWidget.cpp index 89faf53bd..3354b4e19 100644 --- a/src/libtomahawk/widgets/infowidgets/TrackInfoWidget.cpp +++ b/src/libtomahawk/widgets/infowidgets/TrackInfoWidget.cpp @@ -21,12 +21,15 @@ #include "TrackInfoWidget.h" #include "ui_TrackInfoWidget.h" +#include +#include + #include "ViewManager.h" #include "SourceList.h" -#include "playlist/AlbumModel.h" +#include "playlist/PlayableModel.h" #include "audio/AudioEngine.h" -#include "utils/TomahawkUtils.h" +#include "utils/TomahawkUtilsGui.h" #include "utils/Logger.h" using namespace Tomahawk; @@ -35,23 +38,32 @@ using namespace Tomahawk; TrackInfoWidget::TrackInfoWidget( const Tomahawk::query_ptr& query, QWidget* parent ) : QWidget( parent ) , ui( new Ui::TrackInfoWidget ) - , m_infoId( uuid() ) { - ui->setupUi( this ); + QWidget* widget = new QWidget; + ui->setupUi( widget ); + QPalette pal = palette(); pal.setColor( QPalette::Window, QColor( "#323435" ) ); - setPalette( pal ); - setAutoFillBackground( true ); + widget->setPalette( pal ); + widget->setAutoFillBackground( true ); - layout()->setSpacing( 0 ); - ui->tracksWidget->setStyleSheet( "QWidget#tracksWidget { background-color: #323435; }" ); +// layout()->setSpacing( 0 ); +// ui->tracksWidget->setStyleSheet( "QWidget#tracksWidget { background-color: #323435; }" ); // ui->headerWidget->setStyleSheet( "QWidget#headerWidget { background-image: url(" RESPATH "images/playlist-header-tiled.png); }" ); // ui->headerWidget->setStyleSheet( "background-color: #323435;" ); // ui->tracksWidget->setStyleSheet( "background-color: #323435;" ); ui->statsLabel->setStyleSheet( "QLabel { background-image:url(); border: 2px solid #dddddd; background-color: #faf9f9; border-radius: 4px; padding: 12px; }" ); ui->lyricsView->setStyleSheet( "QTextBrowser#lyricsView { background-color: transparent; }" ); + ui->lyricsView->setFrameShape( QFrame::NoFrame ); + ui->lyricsView->setAttribute( Qt::WA_MacShowFocusRect, 0 ); + + ui->similarTracksView->setAutoResize( true ); + ui->similarTracksView->setVerticalScrollBarPolicy( Qt::ScrollBarAlwaysOff ); + TomahawkUtils::styleScrollBar( ui->similarTracksView->verticalScrollBar() ); + TomahawkUtils::styleScrollBar( ui->lyricsView->verticalScrollBar() ); + QFont f = font(); f.setBold( true ); f.setPixelSize( 18 ); @@ -61,16 +73,10 @@ TrackInfoWidget::TrackInfoWidget( const Tomahawk::query_ptr& query, QWidget* par f.setPixelSize( 14 ); ui->artistLabel->setFont( f ); ui->albumLabel->setFont( f ); - ui->byLabel->setFont( f ); - ui->fromLabel->setFont( f ); f.setPixelSize( 12 ); ui->statsLabel->setFont( f ); - ui->similarTracksView->setFrameShape( QFrame::NoFrame ); - ui->similarTracksView->setAttribute( Qt::WA_MacShowFocusRect, 0 ); - ui->lyricsView->setFrameShape( QFrame::NoFrame ); - ui->lyricsView->setAttribute( Qt::WA_MacShowFocusRect, 0 ); // ui->similarTracksView->setStyleSheet( "QListView { background-color: transparent; } QListView::item { background-color: transparent; }" ); QPalette p = ui->trackLabel->palette(); @@ -80,18 +86,38 @@ TrackInfoWidget::TrackInfoWidget( const Tomahawk::query_ptr& query, QWidget* par ui->trackLabel->setPalette( p ); ui->artistLabel->setPalette( p ); ui->albumLabel->setPalette( p ); - ui->byLabel->setPalette( p ); - ui->fromLabel->setPalette( p ); ui->lyricsView->setPalette( p ); + ui->label->setPalette( p ); // ui->similarTracksLabel->setPalette( p ); - m_albumsModel = new AlbumModel( ui->similarTracksView ); - ui->similarTracksView->setAlbumModel( m_albumsModel ); + ui->artistLabel->setType( QueryLabel::Artist ); + ui->albumLabel->setType( QueryLabel::Album ); + + m_relatedTracksModel = new PlayableModel( ui->similarTracksView ); + ui->similarTracksView->setPlayableModel( m_relatedTracksModel ); ui->similarTracksView->proxyModel()->sort( -1 ); + ui->similarTracksView->setEmptyTip( tr( "Sorry, but we could not find similar tracks for this song!" ) ); m_pixmap = TomahawkUtils::defaultPixmap( TomahawkUtils::DefaultAlbumCover, TomahawkUtils::ScaledCover, QSize( 48, 48 ) ); + ui->cover->setPixmap( TomahawkUtils::defaultPixmap( TomahawkUtils::DefaultTrackImage, TomahawkUtils::ScaledCover, QSize( ui->cover->sizeHint() ) ) ); + + QScrollArea* area = new QScrollArea(); + area->setWidgetResizable( true ); + area->setWidget( widget ); + + area->setStyleSheet( "QScrollArea { background-color: #323435; }" ); + area->setFrameShape( QFrame::NoFrame ); + area->setAttribute( Qt::WA_MacShowFocusRect, 0 ); + + QVBoxLayout* layout = new QVBoxLayout(); + layout->addWidget( area ); + setLayout( layout ); + TomahawkUtils::unmarginLayout( layout ); load( query ); + + connect( ui->artistLabel, SIGNAL( clickedArtist() ), SLOT( onArtistClicked() ) ); + connect( ui->albumLabel, SIGNAL( clickedAlbum() ), SLOT( onAlbumClicked() ) ); } @@ -130,6 +156,8 @@ TrackInfoWidget::load( const query_ptr& query ) if ( !m_query.isNull() ) { + disconnect( m_query.data(), SIGNAL( lyricsLoaded() ), this, SLOT( onLyricsLoaded() ) ); + disconnect( m_query.data(), SIGNAL( similarTracksLoaded() ), this, SLOT( onSimilarTracksLoaded() ) ); disconnect( m_query.data(), SIGNAL( statsLoaded() ), this, SLOT( onStatsLoaded() ) ); disconnect( m_query.data(), SIGNAL( updated() ), this, SLOT( onCoverUpdated() ) ); disconnect( m_artist.data(), SIGNAL( statsLoaded() ), this, SLOT( onStatsLoaded() ) ); @@ -145,17 +173,17 @@ TrackInfoWidget::load( const query_ptr& query ) m_artist->loadStats(); m_query->loadStats(); + m_query->lyrics(); onCoverUpdated(); ui->trackLabel->setText( query->track() ); - ui->artistLabel->setText( query->artist() ); - ui->albumLabel->setText( query->album() ); - ui->fromLabel->setVisible( !query->album().isEmpty() ); + ui->artistLabel->setQuery( query ); + ui->albumLabel->setQuery( query ); - m_query->lyrics(); - m_query->similarTracks(); - m_albumsModel->addArtists( m_artist->similarArtists() ); - m_albumsModel->clear(); + m_relatedTracksModel->clear(); + + if ( !m_query->similarTracks().isEmpty() ) + onSimilarTracksLoaded(); } @@ -201,16 +229,16 @@ TrackInfoWidget::onStatsLoaded() void TrackInfoWidget::onSimilarArtistsLoaded() { -// Artist* artist = qobject_cast( sender() ); +/* Artist* artist = qobject_cast( sender() ); -// m_albumsModel->addArtists( artist->similarArtists() ); + m_relatedArtistsModel->addArtists( artist->similarArtists() );*/ } void TrackInfoWidget::onSimilarTracksLoaded() { - m_albumsModel->addQueries( m_query->similarTracks() ); + m_relatedTracksModel->append( m_query->similarTracks() ); } @@ -221,6 +249,21 @@ TrackInfoWidget::onLyricsLoaded() } +void +TrackInfoWidget::onArtistClicked() +{ + ViewManager::instance()->show( Artist::get( m_query->artist(), false ) ); +} + + +void +TrackInfoWidget::onAlbumClicked() +{ + artist_ptr artist = Artist::get( m_query->artist(), false ); + ViewManager::instance()->show( Album::get( artist, m_query->album(), false ) ); +} + + void TrackInfoWidget::changeEvent( QEvent* e ) { diff --git a/src/libtomahawk/widgets/infowidgets/TrackInfoWidget.h b/src/libtomahawk/widgets/infowidgets/TrackInfoWidget.h index 849e36043..dc9c3de64 100644 --- a/src/libtomahawk/widgets/infowidgets/TrackInfoWidget.h +++ b/src/libtomahawk/widgets/infowidgets/TrackInfoWidget.h @@ -39,7 +39,7 @@ #include "DllMacro.h" #include "Typedefs.h" -class AlbumModel; +class PlayableModel; namespace Ui { @@ -82,16 +82,18 @@ private slots: void onSimilarTracksLoaded(); void onLyricsLoaded(); + void onArtistClicked(); + void onAlbumClicked(); + private: Ui::TrackInfoWidget *ui; Tomahawk::query_ptr m_query; Tomahawk::artist_ptr m_artist; - AlbumModel* m_albumsModel; + PlayableModel* m_relatedTracksModel; QString m_title; QPixmap m_pixmap; - QString m_infoId; }; #endif // TRACKINFOWIDGET_H diff --git a/src/libtomahawk/widgets/infowidgets/TrackInfoWidget.ui b/src/libtomahawk/widgets/infowidgets/TrackInfoWidget.ui index 4814e2de0..1004806b6 100644 --- a/src/libtomahawk/widgets/infowidgets/TrackInfoWidget.ui +++ b/src/libtomahawk/widgets/infowidgets/TrackInfoWidget.ui @@ -6,232 +6,206 @@ 0 0 - 852 - 571 + 951 + 771 Form - - - 0 - + - - - - 12 - - - - - - 0 - 0 - - - - - 128 - 128 - - - - Cover - - - - - - - Qt::Horizontal - - - QSizePolicy::Fixed - - - - 16 - 20 - - - - - - - - - - Track - - - - - - - - - - 0 - 0 - - - - by - - - - - - - Artist - - - - - - - - - - - - 0 - 0 - - - - from - - - - - - - Album - - - - - - - - - Qt::Vertical - - - QSizePolicy::Expanding - - - - 20 - 40 - - - - - - - - - - Qt::Horizontal - - - QSizePolicy::Fixed - - - - 16 - 20 - - - - - - - - Statistics - - - Qt::AlignCenter - - - - - - - - - - Lyrics + + + 16 - - 8 + + 12 - - - - - - false + + 16 - - - - - - - 0 - - - 0 - - - 4 - - - 0 - - - 0 - - - - - Similar Tracks - - - 8 - - - - - - - - 0 - 0 - - - - - - + + 12 + + + + + + + + Arial + 20 + 75 + true + + + + Similar Tracks + + + 0 + + + + + + + + 0 + 0 + + + + + + + + + + 16 + + + + + + 0 + 0 + + + + + 220 + 220 + + + + Cover + + + Qt::AlignCenter + + + + + + + + + Track + + + Qt::AlignCenter + + + + + + + + + Artist + + + Qt::AlignCenter + + + + + + + + + + + Album + + + Qt::AlignCenter + + + + + + + + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 20 + 12 + + + + + + + + Statistics + + + Qt::AlignCenter + + + + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 20 + 12 + + + + + + + + + 0 + 0 + + + + + 300 + 0 + + + + false + + + + + + - AlbumView + GridView QListView -
playlist/AlbumView.h
+
GridView.h
- HeaderLabel + QueryLabel QLabel -
widgets/HeaderLabel.h
+
widgets/QueryLabel.h
diff --git a/src/mac/TomahawkApp_Mac.h b/src/mac/TomahawkApp_Mac.h index e0957177f..e258c6719 100644 --- a/src/mac/TomahawkApp_Mac.h +++ b/src/mac/TomahawkApp_Mac.h @@ -23,6 +23,7 @@ // copyright David Sansome 2010 class QString; +class QObject; namespace Tomahawk { @@ -43,7 +44,9 @@ void setShortcutHandler(Tomahawk::MacShortcutHandler* engine); // used for opening files with tomahawk void setApplicationHandler(PlatformInterface* handler); void checkForUpdates(); -void enableFullscreen(); + +// Pass in a QObject with slots "fullScreenEntered() and fullScreenExited() in order to be notified +void enableFullscreen( QObject* notifier ); }; diff --git a/src/mac/TomahawkApp_Mac.mm b/src/mac/TomahawkApp_Mac.mm index 6187fab4e..c9ab976a6 100644 --- a/src/mac/TomahawkApp_Mac.mm +++ b/src/mac/TomahawkApp_Mac.mm @@ -43,6 +43,8 @@ #include #include +#include +#include @interface MacApplication :NSApplication { AppDelegate* delegate_; @@ -164,14 +166,14 @@ NSAppleEventManager *em = [NSAppleEventManager sharedAppleEventManager]; [em setEventHandler:self - andSelector:@selector(getUrl:withReplyEvent:) - forEventClass:kInternetEventClass - andEventID:kAEGetURL]; + andSelector:@selector(getUrl:withReplyEvent:) + forEventClass:kInternetEventClass + andEventID:kAEGetURL]; [em setEventHandler:self - andSelector:@selector(getUrl:withReplyEvent:) - forEventClass:'WWW!' - andEventID:'OURL']; + andSelector:@selector(getUrl:withReplyEvent:) + forEventClass:'WWW!' + andEventID:'OURL']; NSString *bundleID = [[NSBundle mainBundle] bundleIdentifier]; OSStatus httpResult = LSSetDefaultHandlerForURLScheme((CFStringRef)@"tomahawk", (CFStringRef)bundleID); @@ -251,11 +253,15 @@ void Tomahawk::checkForUpdates() { #ifdef LION #define SET_LION_FULLSCREEN NSWindowCollectionBehaviorFullScreenPrimary +#define LION_FULLSCREEN_ENTER_NOTIFICATION_VALUE NSWindowWillEnterFullScreenNotification +#define LION_FULLSCREEN_EXIT_NOTIFICATION_VALUE NSWindowDidExitFullScreenNotification #else #define SET_LION_FULLSCREEN (NSUInteger)(1 << 7) // Defined as NSWindowCollectionBehaviorFullScreenPrimary in lion's NSWindow.h +#define LION_FULLSCREEN_ENTER_NOTIFICATION_VALUE @"NSWindowWillEnterFullScreenNotification" +#define LION_FULLSCREEN_EXIT_NOTIFICATION_VALUE @"NSWindowDidExitFullScreenNotification" #endif -void Tomahawk::enableFullscreen() +void Tomahawk::enableFullscreen( QObject* receiver ) { // We don't support anything below leopard, so if it's not [snow] leopard it must be lion // Can't check for lion as Qt 4.7 doesn't have the enum val, not checking for Unknown as it will be lion @@ -273,6 +279,24 @@ void Tomahawk::enableFullscreen() NSView *nsview = (NSView *)w->winId(); NSWindow *nswindow = [nsview window]; [nswindow setCollectionBehavior:SET_LION_FULLSCREEN]; + + if ( !receiver ) + continue; + + [[NSNotificationCenter defaultCenter] addObserverForName:LION_FULLSCREEN_ENTER_NOTIFICATION_VALUE + object:nswindow + queue:nil + usingBlock:^(NSNotification * note) { + NSLog(@"Became Full Screen!"); + QMetaObject::invokeMethod( receiver, "fullScreenEntered", Qt::DirectConnection ); + }]; + [[NSNotificationCenter defaultCenter] addObserverForName:LION_FULLSCREEN_EXIT_NOTIFICATION_VALUE + object:nswindow + queue:nil + usingBlock:^(NSNotification * note) { + NSLog(@"Left Full Screen!"); + QMetaObject::invokeMethod( receiver, "fullScreenExited", Qt::DirectConnection ); + }]; } } } diff --git a/src/main.cpp b/src/main.cpp index dfb01ff1c..9b360299d 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -25,8 +25,6 @@ #include "config.h" #include "utils/Logger.h" -#include - #ifdef Q_WS_MAC #include "TomahawkApp_Mac.h" #include @@ -38,50 +36,53 @@ #include "breakpad/BreakPad.h" #endif + #ifdef Q_OS_WIN // code from patch attached to QTBUG-19064 by Honglei Zhang -LRESULT QT_WIN_CALLBACK qt_LowLevelKeyboardHookProc(int nCode, WPARAM wParam, LPARAM lParam); +LRESULT QT_WIN_CALLBACK qt_LowLevelKeyboardHookProc( int nCode, WPARAM wParam, LPARAM lParam ); HHOOK hKeyboardHook; HINSTANCE hGuiLibInstance; -LRESULT QT_WIN_CALLBACK qt_LowLevelKeyboardHookProc(int nCode, WPARAM wParam, LPARAM lParam) +LRESULT QT_WIN_CALLBACK qt_LowLevelKeyboardHookProc( int nCode, WPARAM wParam, LPARAM lParam ) { LPKBDLLHOOKSTRUCT kbHookStruct = reinterpret_cast(lParam); - switch(kbHookStruct->vkCode){ - case VK_VOLUME_MUTE: - case VK_VOLUME_DOWN: - case VK_VOLUME_UP: - case VK_MEDIA_NEXT_TRACK: - case VK_MEDIA_PREV_TRACK: - case VK_MEDIA_STOP: - case VK_MEDIA_PLAY_PAUSE: - case VK_LAUNCH_MEDIA_SELECT: - // send message - { - HWND hWnd = NULL; - foreach (QWidget *widget, QApplication::topLevelWidgets()) { - // relay message to each top level widgets(window) - // if the window has focus, we don't send a duplicate message - if(QApplication::activeWindow() == widget){ - continue; + switch(kbHookStruct->vkCode) + { + case VK_VOLUME_MUTE: + case VK_VOLUME_DOWN: + case VK_VOLUME_UP: + case VK_MEDIA_NEXT_TRACK: + case VK_MEDIA_PREV_TRACK: + case VK_MEDIA_STOP: + case VK_MEDIA_PLAY_PAUSE: + case VK_LAUNCH_MEDIA_SELECT: + // send message + { + HWND hWnd = NULL; + foreach ( QWidget *widget, QApplication::topLevelWidgets() ) + { + // relay message to each top level widgets(window) + // if the window has focus, we don't send a duplicate message + if ( QApplication::activeWindow() == widget ) + continue; + + hWnd = widget->winId(); + + // generate message and post it to the message queue + LPKBDLLHOOKSTRUCT pKeyboardHookStruct = reinterpret_cast(lParam); + WPARAM _wParam = pKeyboardHookStruct->vkCode; + LPARAM _lParam = MAKELPARAM( pKeyboardHookStruct->scanCode, pKeyboardHookStruct->flags ); + PostMessage( hWnd, wParam, _wParam, _lParam ); } - - hWnd = widget->winId(); - - // generate message and post it to the message queue - LPKBDLLHOOKSTRUCT pKeyboardHookStruct = reinterpret_cast(lParam); - WPARAM _wParam = pKeyboardHookStruct->vkCode; - LPARAM _lParam = MAKELPARAM(pKeyboardHookStruct->scanCode, pKeyboardHookStruct->flags); - PostMessage(hWnd, wParam, _wParam, _lParam); } - } - break; - default: - break; + break; + + default: + break; } - return CallNextHookEx(0, nCode, wParam, lParam); + return CallNextHookEx( 0, nCode, wParam, lParam ); } #include @@ -89,32 +90,29 @@ LRESULT QT_WIN_CALLBACK qt_LowLevelKeyboardHookProc(int nCode, WPARAM wParam, LP #define argv __argv // code taken from AbiWord, (c) AbiSource Inc. -int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, - PSTR szCmdLine, int iCmdShow) +int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow ) { hKeyboardHook = NULL; hGuiLibInstance = hInstance; - // setup keyboard hook to receive multimedia key events when application is at background - hKeyboardHook = SetWindowsHookEx(WH_KEYBOARD_LL,(HOOKPROC) qt_LowLevelKeyboardHookProc, hGuiLibInstance, 0); + hKeyboardHook = SetWindowsHookEx( WH_KEYBOARD_LL,(HOOKPROC) qt_LowLevelKeyboardHookProc, hGuiLibInstance, 0 ); - if (fileno (stdout) != -1 && _get_osfhandle (fileno (stdout)) != -1) + if ( fileno( stdout ) != -1 && _get_osfhandle( fileno( stdout ) ) != -1 ) { /* stdout is fine, presumably redirected to a file or pipe */ } else { typedef BOOL (WINAPI * AttachConsole_t) (DWORD); + AttachConsole_t p_AttachConsole = (AttachConsole_t) GetProcAddress( GetModuleHandleW( L"kernel32.dll" ), "AttachConsole" ); - AttachConsole_t p_AttachConsole = (AttachConsole_t) GetProcAddress (GetModuleHandleW(L"kernel32.dll"), "AttachConsole"); - - if (p_AttachConsole != NULL && p_AttachConsole (ATTACH_PARENT_PROCESS)) + if ( p_AttachConsole != NULL && p_AttachConsole( ATTACH_PARENT_PROCESS ) ) { - _wfreopen (L"CONOUT$", L"w", stdout); - dup2 (fileno (stdout), 1); - _wfreopen (L"CONOUT$", L"w", stderr); - dup2 (fileno (stderr), 2); + _wfreopen ( L"CONOUT$", L"w", stdout ); + dup2( fileno( stdout ), 1 ); + _wfreopen ( L"CONOUT$", L"w", stderr ); + dup2( fileno( stderr ), 2 ); } } #else // Q_OS_WIN @@ -127,6 +125,10 @@ main( int argc, char *argv[] ) // This must go before QApplication initialisation. Tomahawk::macMain(); + // Fixes focus issue with NSSearchField, see QTBUG-11401 + // code taken from clementine:main.cpp:336 + QCoreApplication::setAttribute( Qt::AA_NativeWindows, true ); + // used for url handler AEEventHandlerUPP h = AEEventHandlerUPP( appleEventHandler ); AEInstallEventHandler( 'GURL', 'GURL', h, 0, false ); @@ -145,7 +147,6 @@ main( int argc, char *argv[] ) new TomahawkSettingsGui( &a ); #endif - #ifndef ENABLE_HEADLESSs #ifdef WITH_BREAKPAD new BreakPad( QDir::tempPath(), TomahawkSettings::instance()->crashReporterEnabled() ); @@ -158,21 +159,6 @@ main( int argc, char *argv[] ) if ( guard.isPrimaryInstance() ) a.init(); - QString locale = QLocale::system().name(); - if ( locale == "C" ) - locale = "en"; - QTranslator translator; - if ( translator.load( QString( ":/lang/tomahawk_" ) + locale ) ) - { - tDebug() << "Using system locale:" << locale; - } - else - { - tDebug() << "Using default locale, system locale one not found:" << locale; - translator.load( QString( ":/lang/tomahawk_en" ) ); - } - a.installTranslator( &translator ); - if ( argc > 1 ) { QString arg = a.arguments()[ 1 ]; @@ -182,12 +168,13 @@ main( int argc, char *argv[] ) int returnCode = a.exec(); #ifdef Q_OS_WIN // clean up keyboard hook - if( hKeyboardHook ) + if ( hKeyboardHook ) { - UnhookWindowsHookEx(hKeyboardHook); + UnhookWindowsHookEx( hKeyboardHook ); hKeyboardHook = NULL; } #endif + return returnCode; } diff --git a/src/sourcetree/SourceDelegate.cpp b/src/sourcetree/SourceDelegate.cpp index bd3c4a8eb..1f434a924 100644 --- a/src/sourcetree/SourceDelegate.cpp +++ b/src/sourcetree/SourceDelegate.cpp @@ -145,10 +145,13 @@ SourceDelegate::paintDecorations( QPainter* painter, const QStyleOptionViewItem& void SourceDelegate::paintCollection( QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index ) const { - QFont normal = painter->font(); - QFont bold = painter->font(); + QFont normal = option.font; + QFont bold = option.font; bold.setBold( true ); + QFont figFont = bold; + figFont.setFamily( "Arial Bold" ); + figFont.setWeight( QFont::Black ); figFont.setPixelSize( 10 ); SourceTreeItem* item = index.data( SourcesModel::SourceTreeItemRole ).value< SourceTreeItem* >(); @@ -183,17 +186,10 @@ SourceDelegate::paintCollection( QPainter* painter, const QStyleOptionViewItem& QString text = painter->fontMetrics().elidedText( name, Qt::ElideRight, textRect.width() ); painter->drawText( textRect, text ); - bool isPlaying = false; - QString desc = status ? colItem->source()->textStatus() : tr( "Offline" ); + bool isPlaying = !( colItem->source()->currentTrack().isNull() ); + QString desc = colItem->source()->textStatus(); if ( colItem->source().isNull() ) desc = tr( "All available tracks" ); - if ( status && desc.isEmpty() && !colItem->source()->currentTrack().isNull() ) - { - desc = colItem->source()->currentTrack()->artist() + " - " + colItem->source()->currentTrack()->track(); - isPlaying = true; - } - if ( desc.isEmpty() ) - desc = tr( "Online" ); painter->setFont( normal ); textRect = option.rect.adjusted( iconRect.width() + 8, option.rect.height() / 2, -figWidth - 24, -6 ); @@ -254,7 +250,7 @@ SourceDelegate::paintCollection( QPainter* painter, const QStyleOptionViewItem& { painter->setRenderHint( QPainter::Antialiasing ); - QRect figRect = option.rect.adjusted( option.rect.width() - figWidth - 8, 0, -13, -option.rect.height() + 16 ); + QRect figRect = option.rect.adjusted( option.rect.width() - figWidth - 13, 0, -14, -option.rect.height() + 16 ); int hd = ( option.rect.height() - figRect.height() ) / 2; figRect.adjust( 0, hd, 0, hd ); diff --git a/src/sourcetree/SourceTreeView.cpp b/src/sourcetree/SourceTreeView.cpp index c47ce9617..23b1a0b81 100644 --- a/src/sourcetree/SourceTreeView.cpp +++ b/src/sourcetree/SourceTreeView.cpp @@ -2,6 +2,7 @@ * * Copyright 2010-2011, Christian Muehlhaeuser * Copyright 2010-2012, Jeff Mitchell + * Copyright 2010-2012, Leo Franchi * * Tomahawk is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -26,8 +27,9 @@ #include #include #include -#include #include +#include +#include #include "ActionCollection.h" #include "Playlist.h" @@ -42,12 +44,13 @@ #include "TomahawkSettings.h" #include "GlobalActionManager.h" #include "DropJob.h" -#include "utils/Logger.h" #include "items/GenericPageItems.h" #include "items/TemporaryPageItem.h" #include "database/DatabaseCommand_SocialAction.h" #include "database/Database.h" #include "LatchManager.h" +#include "utils/TomahawkUtilsGui.h" +#include "utils/Logger.h" using namespace Tomahawk; @@ -109,7 +112,7 @@ SourceTreeView::SourceTreeView( QWidget* parent ) header()->setResizeMode( 0, QHeaderView::Stretch ); connect( this, SIGNAL( expanded( QModelIndex ) ), SLOT( onItemExpanded( QModelIndex ) ) ); -// connect( selectionModel(), SIGNAL( selectionChanged( QItemSelection, QItemSelection ) ), SLOT( onSelectionChanged() ) ); + connect( selectionModel(), SIGNAL( selectionChanged( QItemSelection, QItemSelection ) ), SLOT( onSelectionChanged() ) ); showOfflineSources( TomahawkSettings::instance()->showOfflineSources() ); @@ -168,11 +171,11 @@ SourceTreeView::setupMenus() { if ( m_latchManager->isLatched( source ) ) { - QAction *latchOffAction = ActionCollection::instance()->getAction( "latchOff" ); + QAction* latchOffAction = ActionCollection::instance()->getAction( "latchOff" ); m_latchMenu.addAction( latchOffAction ); connect( latchOffAction, SIGNAL( triggered() ), SLOT( latchOff() ) ); m_latchMenu.addSeparator(); - QAction *latchRealtimeAction = ActionCollection::instance()->getAction( "realtimeFollowingAlong" ); + QAction* latchRealtimeAction = ActionCollection::instance()->getAction( "realtimeFollowingAlong" ); latchRealtimeAction->setChecked( source->playlistInterface()->latchMode() == Tomahawk::PlaylistModes::RealTime ); m_latchMenu.addAction( latchRealtimeAction ); connect( latchRealtimeAction, SIGNAL( toggled( bool ) ), SLOT( latchModeToggled( bool ) ) ); @@ -180,24 +183,31 @@ SourceTreeView::setupMenus() } } - QAction *loadPlaylistAction = ActionCollection::instance()->getAction( "loadPlaylist" ); + QAction* loadPlaylistAction = ActionCollection::instance()->getAction( "loadPlaylist" ); m_playlistMenu.addAction( loadPlaylistAction ); - QAction *renamePlaylistAction = ActionCollection::instance()->getAction( "renamePlaylist" ); + QAction* renamePlaylistAction = ActionCollection::instance()->getAction( "renamePlaylist" ); m_playlistMenu.addAction( renamePlaylistAction ); m_playlistMenu.addSeparator(); - QAction *copyPlaylistAction = m_playlistMenu.addAction( tr( "&Copy Link" ) ); - QAction *deletePlaylistAction = m_playlistMenu.addAction( tr( "&Delete %1" ).arg( SourcesModel::rowTypeToString( type ) ) ); + QAction* copyPlaylistAction = m_playlistMenu.addAction( tr( "&Copy Link" ) ); - QString addToText = QString( "Add to my %1" ); if ( type == SourcesModel::StaticPlaylist ) - addToText = addToText.arg( "playlists" ); - if ( type == SourcesModel::AutomaticPlaylist ) - addToText = addToText.arg( "Automatic Playlists" ); - else if ( type == SourcesModel::Station ) - addToText = addToText.arg( "Stations" ); + { + QAction* exportPlaylist = m_playlistMenu.addAction( tr( "&Export Playlist") ); + connect( exportPlaylist, SIGNAL( triggered() ), this, SLOT( exportPlaylist() ) ); + } - QAction *addToLocalAction = m_roPlaylistMenu.addAction( tr( addToText.toUtf8(), "Adds the given playlist, dynamic playlist, or station to the users's own list" ) ); + QAction* deletePlaylistAction = m_playlistMenu.addAction( tr( "&Delete %1" ).arg( SourcesModel::rowTypeToString( type ) ) ); + + QString addToText; + if ( type == SourcesModel::StaticPlaylist ) + addToText = tr( "Add to my Playlists" ); + if ( type == SourcesModel::AutomaticPlaylist ) + addToText = tr( "Add to my Automatic Playlists" ); + else if ( type == SourcesModel::Station ) + addToText = tr( "Add to my Stations" ); + + QAction* addToLocalAction = m_roPlaylistMenu.addAction( addToText ); m_roPlaylistMenu.addAction( copyPlaylistAction ); deletePlaylistAction->setEnabled( !readonly ); @@ -210,7 +220,6 @@ SourceTreeView::setupMenus() { m_playlistMenu.addSeparator(); - const PlaylistItem* item = itemFromIndex< PlaylistItem >( m_contextMenuIndex ); const playlist_ptr playlist = item->playlist(); foreach ( QAction* action, ActionCollection::instance()->getAction( ActionCollection::LocalPlaylists ) ) @@ -225,10 +234,6 @@ SourceTreeView::setupMenus() } } - - if ( type == SourcesModel::StaticPlaylist ) - copyPlaylistAction->setText( tr( "&Export Playlist" ) ); - connect( loadPlaylistAction, SIGNAL( triggered() ), SLOT( loadPlaylist() ) ); connect( renamePlaylistAction, SIGNAL( triggered() ), SLOT( renamePlaylist() ) ); connect( deletePlaylistAction, SIGNAL( triggered() ), SLOT( deletePlaylist() ) ); @@ -245,6 +250,18 @@ SourceTreeView::showOfflineSources( bool offlineSourcesShown ) } +void +SourceTreeView::onSelectionChanged() +{ + if ( currentIndex() != m_selectedIndex ) + { + selectionModel()->blockSignals( true ); + selectionModel()->select( m_selectedIndex, QItemSelectionModel::ClearAndSelect | QItemSelectionModel::Current ); + selectionModel()->blockSignals( false ); + } +} + + void SourceTreeView::onItemActivated( const QModelIndex& index ) { @@ -271,7 +288,7 @@ void SourceTreeView::onItemExpanded( const QModelIndex& idx ) { // make sure to expand children nodes for collections - if( idx.data( SourcesModel::SourceTreeItemTypeRole ) == SourcesModel::Collection ) + if ( idx.data( SourcesModel::SourceTreeItemTypeRole ) == SourcesModel::Collection ) { for( int i = 0; i < model()->rowCount( idx ); i++ ) { @@ -284,6 +301,8 @@ SourceTreeView::onItemExpanded( const QModelIndex& idx ) void SourceTreeView::selectRequest( const QPersistentModelIndex& idx ) { + m_selectedIndex = idx; + if ( !selectionModel()->selectedIndexes().contains( idx ) ) { scrollTo( idx, QTreeView::EnsureVisible ); @@ -319,20 +338,50 @@ SourceTreeView::loadPlaylist() void SourceTreeView::deletePlaylist( const QModelIndex& idxIn ) { - qDebug() << Q_FUNC_INFO; - QModelIndex idx = idxIn.isValid() ? idxIn : m_contextMenuIndex; if ( !idx.isValid() ) return; SourcesModel::RowType type = ( SourcesModel::RowType )model()->data( idx, SourcesModel::SourceTreeItemTypeRole ).toInt(); + QString typeDesc; + switch ( type ) + { + case SourcesModel::StaticPlaylist: + typeDesc = tr( "playlist" ); + break; + + case SourcesModel::AutomaticPlaylist: + typeDesc = tr( "automatic playlist" ); + break; + + case SourcesModel::Station: + typeDesc = tr( "station" ); + break; + + default: + Q_ASSERT( false ); + } + + QMessageBox askDelete( QMessageBox::Question, tr( "Delete %1?", "playlist/station/..." ).arg( typeDesc ), + tr( "Would you like to delete the %1 \"%2\"?", "e.g. Would you like to delete the playlist named Foobar?" ) + .arg( typeDesc ).arg( idx.data().toString() ), + QMessageBox::Yes | QMessageBox::No, this ); + +#ifdef Q_OS_MAC + askDelete.setWindowModality( Qt::WindowModal ); +#endif + + int r = askDelete.exec(); + if ( r != QMessageBox::Yes ) + return; + if ( type == SourcesModel::StaticPlaylist ) { PlaylistItem* item = itemFromIndex< PlaylistItem >( idx ); playlist_ptr playlist = item->playlist(); Playlist::remove( playlist ); } - else if( type == SourcesModel::AutomaticPlaylist || type == SourcesModel::Station ) + else if ( type == SourcesModel::AutomaticPlaylist || type == SourcesModel::Station ) { DynamicPlaylistItem* item = itemFromIndex< DynamicPlaylistItem >( idx ); dynplaylist_ptr playlist = item->dynPlaylist(); @@ -349,7 +398,7 @@ SourceTreeView::copyPlaylistLink() return; SourcesModel::RowType type = ( SourcesModel::RowType )model()->data( m_contextMenuIndex, SourcesModel::SourceTreeItemTypeRole ).toInt(); - if( type == SourcesModel::AutomaticPlaylist || type == SourcesModel::Station ) + if ( type == SourcesModel::AutomaticPlaylist || type == SourcesModel::Station ) { DynamicPlaylistItem* item = itemFromIndex< DynamicPlaylistItem >( m_contextMenuIndex ); dynplaylist_ptr playlist = item->dynPlaylist(); @@ -357,22 +406,37 @@ SourceTreeView::copyPlaylistLink() } else if ( type == SourcesModel::StaticPlaylist ) { + const PlaylistItem* item = itemFromIndex< PlaylistItem >( m_contextMenuIndex ); + const playlist_ptr playlist = item->playlist(); - // Disable toma.hk playlist mode until ready - // GlobalActionManager::instance()->getShortLink( playlist ); + GlobalActionManager::instance()->getShortLink( playlist ); + } +} - PlaylistItem* item = itemFromIndex< PlaylistItem >( m_contextMenuIndex ); - playlist_ptr playlist = item->playlist(); - QString suggestedFilename = TomahawkSettings::instance()->playlistDefaultPath() + "/" + playlist->title(); - QString filename = QFileDialog::getSaveFileName( TomahawkUtils::tomahawkWindow(), tr( "Save XSPF" ), - suggestedFilename, tr( "Playlists (*.xspf)" ) ); - if ( !filename.isEmpty() ) - { - QFileInfo playlistAbsoluteFilePath = filename; - TomahawkSettings::instance()->setPlaylistDefaultPath( playlistAbsoluteFilePath.absolutePath() ); - GlobalActionManager::instance()->savePlaylistToFile( playlist, filename ); - } +void +SourceTreeView::exportPlaylist() +{ + const QModelIndex idx = m_contextMenuIndex; + if ( !idx.isValid() ) + return; + + const SourcesModel::RowType type = ( SourcesModel::RowType )model()->data( m_contextMenuIndex, SourcesModel::SourceTreeItemTypeRole ).toInt(); + Q_ASSERT( type == SourcesModel::StaticPlaylist ); + if ( type != SourcesModel::StaticPlaylist ) + return; + + const PlaylistItem* item = itemFromIndex< PlaylistItem >( m_contextMenuIndex ); + const playlist_ptr playlist = item->playlist(); + + const QString suggestedFilename = TomahawkSettings::instance()->playlistDefaultPath() + "/" + playlist->title(); + const QString filename = QFileDialog::getSaveFileName( TomahawkUtils::tomahawkWindow(), tr( "Save XSPF" ), + suggestedFilename, tr( "Playlists (*.xspf)" ) ); + if ( !filename.isEmpty() ) + { + const QFileInfo playlistAbsoluteFilePath( filename ); + TomahawkSettings::instance()->setPlaylistDefaultPath( playlistAbsoluteFilePath.absolutePath() ); + GlobalActionManager::instance()->savePlaylistToFile( playlist, filename ); } } @@ -385,7 +449,7 @@ SourceTreeView::addToLocal() return; SourcesModel::RowType type = ( SourcesModel::RowType )model()->data( m_contextMenuIndex, SourcesModel::SourceTreeItemTypeRole ).toInt(); - if( type == SourcesModel::AutomaticPlaylist || type == SourcesModel::Station ) + if ( type == SourcesModel::AutomaticPlaylist || type == SourcesModel::Station ) { DynamicPlaylistItem* item = itemFromIndex< DynamicPlaylistItem >( m_contextMenuIndex ); dynplaylist_ptr playlist = item->dynPlaylist(); @@ -418,7 +482,7 @@ SourceTreeView::latchOnOrCatchUp() return; SourcesModel::RowType type = ( SourcesModel::RowType )model()->data( m_contextMenuIndex, SourcesModel::SourceTreeItemTypeRole ).toInt(); - if( type != SourcesModel::Collection ) + if ( type != SourcesModel::Collection ) return; SourceItem* item = itemFromIndex< SourceItem >( m_contextMenuIndex ); @@ -437,7 +501,7 @@ SourceTreeView::latchOff() return; SourcesModel::RowType type = ( SourcesModel::RowType )model()->data( m_contextMenuIndex, SourcesModel::SourceTreeItemTypeRole ).toInt(); - if( type != SourcesModel::Collection ) + if ( type != SourcesModel::Collection ) return; const SourceItem* item = itemFromIndex< SourceItem >( m_contextMenuIndex ); @@ -474,7 +538,7 @@ SourceTreeView::latchModeToggled( bool checked ) return; SourcesModel::RowType type = ( SourcesModel::RowType )model()->data( m_contextMenuIndex, SourcesModel::SourceTreeItemTypeRole ).toInt(); - if( type != SourcesModel::Collection ) + if ( type != SourcesModel::Collection ) return; const SourceItem* item = itemFromIndex< SourceItem >( m_contextMenuIndex ); @@ -486,7 +550,7 @@ SourceTreeView::latchModeToggled( bool checked ) void SourceTreeView::renamePlaylist() { - if( !m_contextMenuIndex.isValid() && !selectionModel()->selectedIndexes().isEmpty() ) + if ( !m_contextMenuIndex.isValid() && !selectionModel()->selectedIndexes().isEmpty() ) edit( selectionModel()->selectedIndexes().first() ); else edit( m_contextMenuIndex ); @@ -509,7 +573,7 @@ SourceTreeView::onCustomContextMenu( const QPoint& pos ) model()->data( m_contextMenuIndex, SourcesModel::SourceTreeItemTypeRole ) == SourcesModel::Station ) { PlaylistItem* item = itemFromIndex< PlaylistItem >( m_contextMenuIndex ); - if( item->playlist()->author()->isLocal() ) + if ( item->playlist()->author()->isLocal() ) m_playlistMenu.exec( mapToGlobal( pos ) ); else m_roPlaylistMenu.exec( mapToGlobal( pos ) ); @@ -586,7 +650,7 @@ SourceTreeView::dragMoveEvent( QDragMoveEvent* event ) m_dropRect = rect; SourceTreeItem* item = itemFromIndex< SourceTreeItem >( index ); - if( item->willAcceptDrag( event->mimeData() ) ) + if ( item->willAcceptDrag( event->mimeData() ) ) { accept = true; @@ -643,7 +707,7 @@ SourceTreeView::dropEvent( QDropEvent* event ) if ( DropJob::isDropType( DropJob::Playlist, event->mimeData() ) ) { qDebug() << Q_FUNC_INFO << "Current Event"; - DropJob *dropThis = new DropJob; + DropJob* dropThis = new DropJob; dropThis->setDropTypes( DropJob::Playlist ); dropThis->setDropAction( DropJob::Create ); dropThis->parseMimeData( event->mimeData() ); @@ -672,9 +736,9 @@ SourceTreeView::dropEvent( QDropEvent* event ) void -SourceTreeView::keyPressEvent( QKeyEvent *event ) +SourceTreeView::keyPressEvent( QKeyEvent* event ) { - if( ( event->key() == Qt::Key_Delete || event->key() == Qt::Key_Backspace ) && !selectionModel()->selectedIndexes().isEmpty() ) + if ( ( event->key() == Qt::Key_Delete || event->key() == Qt::Key_Backspace ) && !selectionModel()->selectedIndexes().isEmpty() ) { QModelIndex idx = selectionModel()->selectedIndexes().first(); if ( model()->data( idx, SourcesModel::SourceTreeItemTypeRole ) == SourcesModel::StaticPlaylist || @@ -684,9 +748,8 @@ SourceTreeView::keyPressEvent( QKeyEvent *event ) PlaylistItem* item = itemFromIndex< PlaylistItem >( idx ); Q_ASSERT( item ); - if( item->playlist()->author()->isLocal() ) { + if ( item->playlist()->author()->isLocal() ) deletePlaylist( idx ); - } } event->accept(); } diff --git a/src/sourcetree/SourceTreeView.h b/src/sourcetree/SourceTreeView.h index f9f71af47..775ecb62b 100644 --- a/src/sourcetree/SourceTreeView.h +++ b/src/sourcetree/SourceTreeView.h @@ -72,6 +72,7 @@ private slots: void loadPlaylist(); void deletePlaylist( const QModelIndex& = QModelIndex() ); void copyPlaylistLink(); + void exportPlaylist(); void addToLocal(); void latchOnOrCatchUp(); @@ -81,6 +82,7 @@ private slots: void latchModeToggled( bool checked ); void onCustomContextMenu( const QPoint& pos ); + void onSelectionChanged(); protected: void drawRow( QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index ) const; @@ -113,6 +115,8 @@ private: bool m_dragging; QRect m_dropRect; QPersistentModelIndex m_dropIndex; + + QPersistentModelIndex m_selectedIndex; }; #endif // SOURCETREEVIEW_H diff --git a/src/sourcetree/SourcesModel.cpp b/src/sourcetree/SourcesModel.cpp index e0934a368..1b532e3b8 100644 --- a/src/sourcetree/SourcesModel.cpp +++ b/src/sourcetree/SourcesModel.cpp @@ -40,7 +40,7 @@ #include "GlobalActionManager.h" #include "DropJob.h" #include "items/PlaylistItems.h" -#include "playlist/ArtistView.h" +#include "playlist/TreeView.h" #include "playlist/PlaylistView.h" #include "playlist/dynamic/widgets/DynamicWidget.h" @@ -101,41 +101,48 @@ SourcesModel::data( const QModelIndex& index, int role ) const if ( !index.isValid() ) return QVariant(); + SourceTreeItem* item = itemFromIndex( index ); + if ( !item ) + return QVariant(); + switch ( role ) { case Qt::SizeHintRole: return QSize( 0, 18 ); case SourceTreeItemRole: - return QVariant::fromValue< SourceTreeItem* >( itemFromIndex( index ) ); + return QVariant::fromValue< SourceTreeItem* >( item ); case SourceTreeItemTypeRole: - return itemFromIndex( index )->type(); + return item->type(); case Qt::DisplayRole: case Qt::EditRole: - return itemFromIndex( index )->text(); + return item->text(); case Qt::DecorationRole: - return itemFromIndex( index )->icon(); + return item->icon(); case SourcesModel::SortRole: - return itemFromIndex( index )->peerSortValue(); + return item->peerSortValue(); case SourcesModel::IDRole: - return itemFromIndex( index )->IDValue(); + return item->IDValue(); case SourcesModel::LatchedOnRole: { - if ( itemFromIndex( index )->type() == Collection ) + if ( item->type() == Collection ) { - SourceItem* cItem = qobject_cast< SourceItem* >( itemFromIndex( index ) ); + SourceItem* cItem = qobject_cast< SourceItem* >( item ); return cItem->localLatchedOn(); } return false; } case SourcesModel::LatchedRealtimeRole: { - if ( itemFromIndex( index )->type() == Collection ) + if ( item->type() == Collection ) { - SourceItem* cItem = qobject_cast< SourceItem* >( itemFromIndex( index ) ); + SourceItem* cItem = qobject_cast< SourceItem* >( item ); return cItem->localLatchMode() == Tomahawk::PlaylistModes::RealTime; } return false; } + case Qt::ToolTipRole: + if ( !item->tooltip().isEmpty() ) + return item->tooltip(); } return QVariant(); } @@ -549,7 +556,7 @@ SourcesModel::linkSourceItemToPage( SourceTreeItem* item, ViewPage* p ) // TODO handle removal m_sourceTreeLinks[ p ] = item; - if( m_viewPageDelayedCacheItem == p ) + if ( p && m_viewPageDelayedCacheItem == p ) emit selectRequest( QPersistentModelIndex( indexFromItem( item ) ) ); if ( QObject* obj = dynamic_cast< QObject* >( p ) ) diff --git a/src/sourcetree/items/CategoryItems.cpp b/src/sourcetree/items/CategoryItems.cpp index 9ea1e005b..7ef745226 100644 --- a/src/sourcetree/items/CategoryItems.cpp +++ b/src/sourcetree/items/CategoryItems.cpp @@ -29,7 +29,6 @@ #include "utils/TomahawkUtils.h" #include "widgets/NewPlaylistWidget.h" #include "TomahawkWindow.h" -#include "widgets/PlaylistTypeSelectorDialog.h" #include #include "utils/Logger.h" #include "DropJob.h" @@ -57,11 +56,13 @@ CategoryAddItem::~CategoryAddItem() QString CategoryAddItem::text() const { - switch( m_categoryType ) { + switch( m_categoryType ) + { case SourcesModel::PlaylistsCategory: - return tr( "New Playlist" ); + return tr( "Create new Playlist" ); + case SourcesModel::StationsCategory: - return tr( "New Station" ); + return tr( "Create new Station" ); } return QString(); @@ -73,46 +74,16 @@ CategoryAddItem::activate() { switch( m_categoryType ) { - case SourcesModel::PlaylistsCategory: { - - PlaylistTypeSelectorDlg* playlistSelectorDlg = new PlaylistTypeSelectorDlg( TomahawkApp::instance()->mainWindow(), Qt::Sheet ); -#ifndef Q_WS_MAC - playlistSelectorDlg->setModal( true ); -#endif - connect( playlistSelectorDlg, SIGNAL( finished( int ) ), this, SLOT( dialogClosed( int ) ) ); - - playlistSelectorDlg->show(); + case SourcesModel::PlaylistsCategory: + APP->mainWindow()->createPlaylist(); break; - } + case SourcesModel::StationsCategory: APP->mainWindow()->createStation(); break; } } -void -CategoryAddItem::dialogClosed( int ret ) -{ - PlaylistTypeSelectorDlg* playlistSelectorDlg = qobject_cast< PlaylistTypeSelectorDlg* >( sender() ); - Q_ASSERT( playlistSelectorDlg ); - - QString playlistName = playlistSelectorDlg->playlistName(); - if ( playlistName.isEmpty() ) - playlistName = tr( "New Playlist" ); - - if ( !playlistSelectorDlg->playlistTypeIsAuto() && ret ) { - - playlist_ptr playlist = Tomahawk::Playlist::create( SourceList::instance()->getLocal(), uuid(), playlistName, "", "", false, QList< query_ptr>() ); - ViewManager::instance()->show( playlist ); - - } else if ( playlistSelectorDlg->playlistTypeIsAuto() && ret ) { - // create Auto Playlist - APP->mainWindow()->createAutomaticPlaylist( playlistName ); - } else if ( !ret ) { - model()->viewPageActivated( ViewManager::instance()->currentPage() ); - } - playlistSelectorDlg->deleteLater(); -} Qt::ItemFlags CategoryAddItem::flags() const @@ -121,8 +92,10 @@ CategoryAddItem::flags() const { case SourcesModel::PlaylistsCategory: return Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsDropEnabled; + case SourcesModel::StationsCategory: return Qt::ItemIsEnabled | Qt::ItemIsDropEnabled; + default: return Qt::ItemIsEnabled; break; @@ -144,9 +117,11 @@ CategoryAddItem::willAcceptDrag( const QMimeData* data ) const { return true; } + return false; } + SourceTreeItem::DropTypes CategoryAddItem::supportedDropTypes( const QMimeData* data ) const { @@ -284,6 +259,7 @@ CategoryAddItem::dropMimeData( const QMimeData* data, Qt::DropAction ) return true; } + void CategoryAddItem::playlistToRenameLoaded() { diff --git a/src/sourcetree/items/CategoryItems.h b/src/sourcetree/items/CategoryItems.h index 6c03d6d5f..85db4578f 100644 --- a/src/sourcetree/items/CategoryItems.h +++ b/src/sourcetree/items/CategoryItems.h @@ -40,10 +40,10 @@ public: private slots: void parsedDroppedTracks( const QList< Tomahawk::query_ptr >& tracks ); - void dialogClosed( int ret ); // Do the rename only after the revision is loaded void playlistToRenameLoaded(); + private: SourcesModel::CategoryType m_categoryType; QIcon m_icon; diff --git a/src/sourcetree/items/PlaylistItems.cpp b/src/sourcetree/items/PlaylistItems.cpp index f7b37ac5a..24780ce16 100644 --- a/src/sourcetree/items/PlaylistItems.cpp +++ b/src/sourcetree/items/PlaylistItems.cpp @@ -251,18 +251,10 @@ PlaylistItem::parsedDroppedTracks( const QList< query_ptr >& tracks ) void PlaylistItem::onUpdated() { - // No work todo - if ( !m_overlaidIcon.isNull() && m_overlaidUpdaters.operator==( m_playlist->updaters() ) ) - { - emit updated(); - return; - } - const bool newOverlay = createOverlay(); if ( !newOverlay && !m_overlaidIcon.isNull() ) m_overlaidIcon = QIcon(); - emit updated(); } @@ -278,7 +270,7 @@ PlaylistItem::createOverlay() QList< QPixmap > icons; foreach ( PlaylistUpdaterInterface* updater, m_playlist->updaters() ) { - if ( !updater->typeIcon().isNull() ) + if ( updater->sync() && !updater->typeIcon().isNull() ) icons << updater->typeIcon(); } diff --git a/src/sourcetree/items/SourceItem.cpp b/src/sourcetree/items/SourceItem.cpp index 5df62ad39..4847d8512 100644 --- a/src/sourcetree/items/SourceItem.cpp +++ b/src/sourcetree/items/SourceItem.cpp @@ -28,7 +28,6 @@ #include "utils/Logger.h" #include "widgets/SocialPlaylistWidget.h" #include "playlist/CustomPlaylistView.h" -#include "playlist/CollectionView.h" #include "playlist/PlaylistView.h" #include "playlist/RecentlyAddedModel.h" #include "playlist/RecentlyPlayedModel.h" @@ -105,8 +104,8 @@ SourceItem::SourceItem( SourcesModel* mdl, SourceTreeItem* parent, const Tomahaw onStationsAdded( stations ); } - if ( ViewManager::instance()->pageForCollection( source->collection() ) ) - model()->linkSourceItemToPage( this, ViewManager::instance()->pageForCollection( source->collection() ) ); +/* if ( ViewManager::instance()->pageForCollection( source->collection() ) ) + model()->linkSourceItemToPage( this, ViewManager::instance()->pageForCollection( source->collection() ) );*/ m_defaultAvatar = TomahawkUtils::createAvatarFrame( QPixmap( RESPATH "images/user-avatar.png" ) ); @@ -114,7 +113,6 @@ SourceItem::SourceItem( SourcesModel* mdl, SourceTreeItem* parent, const Tomahaw connect( source.data(), SIGNAL( stats( QVariantMap ) ), SIGNAL( updated() ) ); connect( source.data(), SIGNAL( syncedWithDatabase() ), SIGNAL( updated() ) ); - connect( source.data(), SIGNAL( playbackStarted( Tomahawk::query_ptr ) ), SIGNAL( updated() ) ); connect( source.data(), SIGNAL( stateChanged() ), SIGNAL( updated() ) ); connect( source.data(), SIGNAL( offline() ), SIGNAL( updated() ) ); connect( source.data(), SIGNAL( online() ), SIGNAL( updated() ) ); @@ -147,6 +145,16 @@ SourceItem::text() const } +QString +SourceItem::tooltip() const +{ + if ( !m_source.isNull() && !m_source->currentTrack().isNull() ) + return m_source->textStatus(); + + return QString(); +} + + int SourceItem::IDValue() const { @@ -507,6 +515,7 @@ SourceItem::lovedTracksClicked() PlaylistLargeItemDelegate* del = new PlaylistLargeItemDelegate( PlaylistLargeItemDelegate::LovedTracks, view, view->proxyModel() ); connect( del, SIGNAL( updateIndex( QModelIndex ) ), view, SLOT( update( QModelIndex ) ) ); view->setItemDelegate( del ); + view->setEmptyTip( tr( "Sorry, we could not find any loved tracks!" ) ); m_lovedTracksPage = view; } @@ -528,7 +537,7 @@ SourceItem::latestAdditionsClicked() { if ( !m_latestAdditionsPage ) { - CollectionView* cv = new CollectionView( ViewManager::instance()->widget() ); + TrackView* cv = new TrackView( ViewManager::instance()->widget() ); cv->setFrameShape( QFrame::NoFrame ); cv->setAttribute( Qt::WA_MacShowFocusRect, 0 ); @@ -547,6 +556,7 @@ SourceItem::latestAdditionsClicked() cv->setPlayableModel( raModel ); cv->sortByColumn( PlayableModel::Age, Qt::DescendingOrder ); + cv->setEmptyTip( tr( "Sorry, we could not find any recent additions!" ) ); m_latestAdditionsPage = cv; } @@ -586,6 +596,7 @@ SourceItem::recentPlaysClicked() pv->setItemDelegate( del ); pv->setPlaylistModel( raModel ); + pv->setEmptyTip( tr( "Sorry, we could not find any recent plays!" ) ); m_recentPlaysPage = pv; } diff --git a/src/sourcetree/items/SourceItem.h b/src/sourcetree/items/SourceItem.h index 7f4a87ed8..cd6711735 100644 --- a/src/sourcetree/items/SourceItem.h +++ b/src/sourcetree/items/SourceItem.h @@ -38,6 +38,7 @@ public: SourceItem( SourcesModel* model, SourceTreeItem* parent, const Tomahawk::source_ptr& source ); virtual QString text() const; + virtual QString tooltip() const; virtual QIcon icon() const; virtual int peerSortValue() const; virtual int IDValue() const; diff --git a/src/sourcetree/items/SourceTreeItem.h b/src/sourcetree/items/SourceTreeItem.h index b2a527a05..410542e9e 100644 --- a/src/sourcetree/items/SourceTreeItem.h +++ b/src/sourcetree/items/SourceTreeItem.h @@ -58,6 +58,7 @@ public: // varies depending on the type of the item virtual QString text() const { return QString(); } + virtual QString tooltip() const { return QString(); } virtual Qt::ItemFlags flags() const { return Qt::ItemIsSelectable | Qt::ItemIsEnabled; } virtual QIcon icon() const { return QIcon(); } virtual bool willAcceptDrag( const QMimeData* ) const { return false; } diff --git a/src/sourcetree/items/TemporaryPageItem.cpp b/src/sourcetree/items/TemporaryPageItem.cpp index 669948e33..dc9f4a169 100644 --- a/src/sourcetree/items/TemporaryPageItem.cpp +++ b/src/sourcetree/items/TemporaryPageItem.cpp @@ -36,7 +36,7 @@ TemporaryPageItem::TemporaryPageItem ( SourcesModel* mdl, SourceTreeItem* parent else if ( dynamic_cast< AlbumInfoWidget* >( page ) ) m_icon = QIcon( RESPATH "images/album-icon.png" ); else if ( dynamic_cast< TrackInfoWidget* >( page ) ) - m_icon = QIcon( RESPATH "images/track-icon.png" ); + m_icon = QIcon( RESPATH "images/track-icon-sidebar.png" ); else if ( dynamic_cast< SearchWidget* >( page ) ) m_icon = QIcon( RESPATH "images/search-icon.png" ); @@ -82,7 +82,7 @@ TemporaryPageItem::IDValue() const void TemporaryPageItem::removeFromList() { - ViewManager::instance()->removeFromHistory( m_page ); + ViewManager::instance()->destroyPage( m_page ); model()->removeSourceItemLink( this ); diff --git a/thirdparty/CMakeLists.txt b/thirdparty/CMakeLists.txt index 9612d4e16..7aa197296 100644 --- a/thirdparty/CMakeLists.txt +++ b/thirdparty/CMakeLists.txt @@ -1,5 +1,4 @@ ADD_SUBDIRECTORY( qxt ) -ADD_SUBDIRECTORY( liblastfm2 ) IF( WITH_BREAKPAD ) ADD_SUBDIRECTORY( breakpad ) ENDIF() diff --git a/thirdparty/liblastfm2/CMakeLists.txt b/thirdparty/liblastfm2/CMakeLists.txt deleted file mode 100644 index b0f71bd5d..000000000 --- a/thirdparty/liblastfm2/CMakeLists.txt +++ /dev/null @@ -1,27 +0,0 @@ -cmake_minimum_required(VERSION 2.6) - -set( CMAKE_MODULE_PATH - ${CMAKE_MODULE_PATH} - ${CMAKE_CURRENT_SOURCE_DIR}/cmake/modules - ) - -if(${CMAKE_BUILD_TYPE} MATCHES "Release") - add_definitions(-DNDEBUG) -endif(${CMAKE_BUILD_TYPE} MATCHES "Release") - -# Set up definitions and paths -add_definitions(${QT_DEFINITIONS}) -include(${QT_USE_FILE}) - -# Main Library -add_subdirectory(src) - -# Optionally build the fingerprint library -option(BUILD_FINGERPRINT "Build the lastfm-fingerprint library" OFF) -find_package(LibSamplerate) -find_package(LibFFTW3) - -if (BUILD_FINGERPRINT AND LIBFFTW3_FOUND AND LIBSAMPLERATE_FOUND) - add_subdirectory(src/fingerprint) -endif (BUILD_FINGERPRINT AND LIBFFTW3_FOUND AND LIBSAMPLERATE_FOUND) - diff --git a/thirdparty/liblastfm2/COPYING b/thirdparty/liblastfm2/COPYING deleted file mode 100644 index 94a045322..000000000 --- a/thirdparty/liblastfm2/COPYING +++ /dev/null @@ -1,621 +0,0 @@ - GNU GENERAL PUBLIC LICENSE - Version 3, 29 June 2007 - - Copyright (C) 2007 Free Software Foundation, Inc. - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - Preamble - - The GNU General Public License is a free, copyleft license for -software and other kinds of works. - - The licenses for most software and other practical works are designed -to take away your freedom to share and change the works. By contrast, -the GNU General Public License is intended to guarantee your freedom to -share and change all versions of a program--to make sure it remains free -software for all its users. We, the Free Software Foundation, use the -GNU General Public License for most of our software; it applies also to -any other work released this way by its authors. You can apply it to -your programs, too. - - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -them if you wish), that you receive source code or can get it if you -want it, that you can change the software or use pieces of it in new -free programs, and that you know you can do these things. - - To protect your rights, we need to prevent others from denying you -these rights or asking you to surrender the rights. Therefore, you have -certain responsibilities if you distribute copies of the software, or if -you modify it: responsibilities to respect the freedom of others. - - For example, if you distribute copies of such a program, whether -gratis or for a fee, you must pass on to the recipients the same -freedoms that you received. You must make sure that they, too, receive -or can get the source code. And you must show them these terms so they -know their rights. - - Developers that use the GNU GPL protect your rights with two steps: -(1) assert copyright on the software, and (2) offer you this License -giving you legal permission to copy, distribute and/or modify it. - - For the developers' and authors' protection, the GPL clearly explains -that there is no warranty for this free software. For both users' and -authors' sake, the GPL requires that modified versions be marked as -changed, so that their problems will not be attributed erroneously to -authors of previous versions. - - Some devices are designed to deny users access to install or run -modified versions of the software inside them, although the manufacturer -can do so. This is fundamentally incompatible with the aim of -protecting users' freedom to change the software. The systematic -pattern of such abuse occurs in the area of products for individuals to -use, which is precisely where it is most unacceptable. Therefore, we -have designed this version of the GPL to prohibit the practice for those -products. If such problems arise substantially in other domains, we -stand ready to extend this provision to those domains in future versions -of the GPL, as needed to protect the freedom of users. - - Finally, every program is threatened constantly by software patents. -States should not allow patents to restrict development and use of -software on general-purpose computers, but in those that do, we wish to -avoid the special danger that patents applied to a free program could -make it effectively proprietary. To prevent this, the GPL assures that -patents cannot be used to render the program non-free. - - The precise terms and conditions for copying, distribution and -modification follow. - - TERMS AND CONDITIONS - - 0. Definitions. - - "This License" refers to version 3 of the GNU General Public License. - - "Copyright" also means copyright-like laws that apply to other kinds of -works, such as semiconductor masks. - - "The Program" refers to any copyrightable work licensed under this -License. Each licensee is addressed as "you". "Licensees" and -"recipients" may be individuals or organizations. - - To "modify" a work means to copy from or adapt all or part of the work -in a fashion requiring copyright permission, other than the making of an -exact copy. The resulting work is called a "modified version" of the -earlier work or a work "based on" the earlier work. - - A "covered work" means either the unmodified Program or a work based -on the Program. - - To "propagate" a work means to do anything with it that, without -permission, would make you directly or secondarily liable for -infringement under applicable copyright law, except executing it on a -computer or modifying a private copy. Propagation includes copying, -distribution (with or without modification), making available to the -public, and in some countries other activities as well. - - To "convey" a work means any kind of propagation that enables other -parties to make or receive copies. Mere interaction with a user through -a computer network, with no transfer of a copy, is not conveying. - - An interactive user interface displays "Appropriate Legal Notices" -to the extent that it includes a convenient and prominently visible -feature that (1) displays an appropriate copyright notice, and (2) -tells the user that there is no warranty for the work (except to the -extent that warranties are provided), that licensees may convey the -work under this License, and how to view a copy of this License. If -the interface presents a list of user commands or options, such as a -menu, a prominent item in the list meets this criterion. - - 1. Source Code. - - The "source code" for a work means the preferred form of the work -for making modifications to it. "Object code" means any non-source -form of a work. - - A "Standard Interface" means an interface that either is an official -standard defined by a recognized standards body, or, in the case of -interfaces specified for a particular programming language, one that -is widely used among developers working in that language. - - The "System Libraries" of an executable work include anything, other -than the work as a whole, that (a) is included in the normal form of -packaging a Major Component, but which is not part of that Major -Component, and (b) serves only to enable use of the work with that -Major Component, or to implement a Standard Interface for which an -implementation is available to the public in source code form. A -"Major Component", in this context, means a major essential component -(kernel, window system, and so on) of the specific operating system -(if any) on which the executable work runs, or a compiler used to -produce the work, or an object code interpreter used to run it. - - The "Corresponding Source" for a work in object code form means all -the source code needed to generate, install, and (for an executable -work) run the object code and to modify the work, including scripts to -control those activities. However, it does not include the work's -System Libraries, or general-purpose tools or generally available free -programs which are used unmodified in performing those activities but -which are not part of the work. For example, Corresponding Source -includes interface definition files associated with source files for -the work, and the source code for shared libraries and dynamically -linked subprograms that the work is specifically designed to require, -such as by intimate data communication or control flow between those -subprograms and other parts of the work. - - The Corresponding Source need not include anything that users -can regenerate automatically from other parts of the Corresponding -Source. - - The Corresponding Source for a work in source code form is that -same work. - - 2. Basic Permissions. - - All rights granted under this License are granted for the term of -copyright on the Program, and are irrevocable provided the stated -conditions are met. This License explicitly affirms your unlimited -permission to run the unmodified Program. The output from running a -covered work is covered by this License only if the output, given its -content, constitutes a covered work. This License acknowledges your -rights of fair use or other equivalent, as provided by copyright law. - - You may make, run and propagate covered works that you do not -convey, without conditions so long as your license otherwise remains -in force. You may convey covered works to others for the sole purpose -of having them make modifications exclusively for you, or provide you -with facilities for running those works, provided that you comply with -the terms of this License in conveying all material for which you do -not control copyright. Those thus making or running the covered works -for you must do so exclusively on your behalf, under your direction -and control, on terms that prohibit them from making any copies of -your copyrighted material outside their relationship with you. - - Conveying under any other circumstances is permitted solely under -the conditions stated below. Sublicensing is not allowed; section 10 -makes it unnecessary. - - 3. Protecting Users' Legal Rights From Anti-Circumvention Law. - - No covered work shall be deemed part of an effective technological -measure under any applicable law fulfilling obligations under article -11 of the WIPO copyright treaty adopted on 20 December 1996, or -similar laws prohibiting or restricting circumvention of such -measures. - - When you convey a covered work, you waive any legal power to forbid -circumvention of technological measures to the extent such circumvention -is effected by exercising rights under this License with respect to -the covered work, and you disclaim any intention to limit operation or -modification of the work as a means of enforcing, against the work's -users, your or third parties' legal rights to forbid circumvention of -technological measures. - - 4. Conveying Verbatim Copies. - - You may convey verbatim copies of the Program's source code as you -receive it, in any medium, provided that you conspicuously and -appropriately publish on each copy an appropriate copyright notice; -keep intact all notices stating that this License and any -non-permissive terms added in accord with section 7 apply to the code; -keep intact all notices of the absence of any warranty; and give all -recipients a copy of this License along with the Program. - - You may charge any price or no price for each copy that you convey, -and you may offer support or warranty protection for a fee. - - 5. Conveying Modified Source Versions. - - You may convey a work based on the Program, or the modifications to -produce it from the Program, in the form of source code under the -terms of section 4, provided that you also meet all of these conditions: - - a) The work must carry prominent notices stating that you modified - it, and giving a relevant date. - - b) The work must carry prominent notices stating that it is - released under this License and any conditions added under section - 7. This requirement modifies the requirement in section 4 to - "keep intact all notices". - - c) You must license the entire work, as a whole, under this - License to anyone who comes into possession of a copy. This - License will therefore apply, along with any applicable section 7 - additional terms, to the whole of the work, and all its parts, - regardless of how they are packaged. This License gives no - permission to license the work in any other way, but it does not - invalidate such permission if you have separately received it. - - d) If the work has interactive user interfaces, each must display - Appropriate Legal Notices; however, if the Program has interactive - interfaces that do not display Appropriate Legal Notices, your - work need not make them do so. - - A compilation of a covered work with other separate and independent -works, which are not by their nature extensions of the covered work, -and which are not combined with it such as to form a larger program, -in or on a volume of a storage or distribution medium, is called an -"aggregate" if the compilation and its resulting copyright are not -used to limit the access or legal rights of the compilation's users -beyond what the individual works permit. Inclusion of a covered work -in an aggregate does not cause this License to apply to the other -parts of the aggregate. - - 6. Conveying Non-Source Forms. - - You may convey a covered work in object code form under the terms -of sections 4 and 5, provided that you also convey the -machine-readable Corresponding Source under the terms of this License, -in one of these ways: - - a) Convey the object code in, or embodied in, a physical product - (including a physical distribution medium), accompanied by the - Corresponding Source fixed on a durable physical medium - customarily used for software interchange. - - b) Convey the object code in, or embodied in, a physical product - (including a physical distribution medium), accompanied by a - written offer, valid for at least three years and valid for as - long as you offer spare parts or customer support for that product - model, to give anyone who possesses the object code either (1) a - copy of the Corresponding Source for all the software in the - product that is covered by this License, on a durable physical - medium customarily used for software interchange, for a price no - more than your reasonable cost of physically performing this - conveying of source, or (2) access to copy the - Corresponding Source from a network server at no charge. - - c) Convey individual copies of the object code with a copy of the - written offer to provide the Corresponding Source. This - alternative is allowed only occasionally and noncommercially, and - only if you received the object code with such an offer, in accord - with subsection 6b. - - d) Convey the object code by offering access from a designated - place (gratis or for a charge), and offer equivalent access to the - Corresponding Source in the same way through the same place at no - further charge. You need not require recipients to copy the - Corresponding Source along with the object code. If the place to - copy the object code is a network server, the Corresponding Source - may be on a different server (operated by you or a third party) - that supports equivalent copying facilities, provided you maintain - clear directions next to the object code saying where to find the - Corresponding Source. Regardless of what server hosts the - Corresponding Source, you remain obligated to ensure that it is - available for as long as needed to satisfy these requirements. - - e) Convey the object code using peer-to-peer transmission, provided - you inform other peers where the object code and Corresponding - Source of the work are being offered to the general public at no - charge under subsection 6d. - - A separable portion of the object code, whose source code is excluded -from the Corresponding Source as a System Library, need not be -included in conveying the object code work. - - A "User Product" is either (1) a "consumer product", which means any -tangible personal property which is normally used for personal, family, -or household purposes, or (2) anything designed or sold for incorporation -into a dwelling. In determining whether a product is a consumer product, -doubtful cases shall be resolved in favor of coverage. For a particular -product received by a particular user, "normally used" refers to a -typical or common use of that class of product, regardless of the status -of the particular user or of the way in which the particular user -actually uses, or expects or is expected to use, the product. A product -is a consumer product regardless of whether the product has substantial -commercial, industrial or non-consumer uses, unless such uses represent -the only significant mode of use of the product. - - "Installation Information" for a User Product means any methods, -procedures, authorization keys, or other information required to install -and execute modified versions of a covered work in that User Product from -a modified version of its Corresponding Source. The information must -suffice to ensure that the continued functioning of the modified object -code is in no case prevented or interfered with solely because -modification has been made. - - If you convey an object code work under this section in, or with, or -specifically for use in, a User Product, and the conveying occurs as -part of a transaction in which the right of possession and use of the -User Product is transferred to the recipient in perpetuity or for a -fixed term (regardless of how the transaction is characterized), the -Corresponding Source conveyed under this section must be accompanied -by the Installation Information. But this requirement does not apply -if neither you nor any third party retains the ability to install -modified object code on the User Product (for example, the work has -been installed in ROM). - - The requirement to provide Installation Information does not include a -requirement to continue to provide support service, warranty, or updates -for a work that has been modified or installed by the recipient, or for -the User Product in which it has been modified or installed. Access to a -network may be denied when the modification itself materially and -adversely affects the operation of the network or violates the rules and -protocols for communication across the network. - - Corresponding Source conveyed, and Installation Information provided, -in accord with this section must be in a format that is publicly -documented (and with an implementation available to the public in -source code form), and must require no special password or key for -unpacking, reading or copying. - - 7. Additional Terms. - - "Additional permissions" are terms that supplement the terms of this -License by making exceptions from one or more of its conditions. -Additional permissions that are applicable to the entire Program shall -be treated as though they were included in this License, to the extent -that they are valid under applicable law. If additional permissions -apply only to part of the Program, that part may be used separately -under those permissions, but the entire Program remains governed by -this License without regard to the additional permissions. - - When you convey a copy of a covered work, you may at your option -remove any additional permissions from that copy, or from any part of -it. (Additional permissions may be written to require their own -removal in certain cases when you modify the work.) You may place -additional permissions on material, added by you to a covered work, -for which you have or can give appropriate copyright permission. - - Notwithstanding any other provision of this License, for material you -add to a covered work, you may (if authorized by the copyright holders of -that material) supplement the terms of this License with terms: - - a) Disclaiming warranty or limiting liability differently from the - terms of sections 15 and 16 of this License; or - - b) Requiring preservation of specified reasonable legal notices or - author attributions in that material or in the Appropriate Legal - Notices displayed by works containing it; or - - c) Prohibiting misrepresentation of the origin of that material, or - requiring that modified versions of such material be marked in - reasonable ways as different from the original version; or - - d) Limiting the use for publicity purposes of names of licensors or - authors of the material; or - - e) Declining to grant rights under trademark law for use of some - trade names, trademarks, or service marks; or - - f) Requiring indemnification of licensors and authors of that - material by anyone who conveys the material (or modified versions of - it) with contractual assumptions of liability to the recipient, for - any liability that these contractual assumptions directly impose on - those licensors and authors. - - All other non-permissive additional terms are considered "further -restrictions" within the meaning of section 10. If the Program as you -received it, or any part of it, contains a notice stating that it is -governed by this License along with a term that is a further -restriction, you may remove that term. If a license document contains -a further restriction but permits relicensing or conveying under this -License, you may add to a covered work material governed by the terms -of that license document, provided that the further restriction does -not survive such relicensing or conveying. - - If you add terms to a covered work in accord with this section, you -must place, in the relevant source files, a statement of the -additional terms that apply to those files, or a notice indicating -where to find the applicable terms. - - Additional terms, permissive or non-permissive, may be stated in the -form of a separately written license, or stated as exceptions; -the above requirements apply either way. - - 8. Termination. - - You may not propagate or modify a covered work except as expressly -provided under this License. Any attempt otherwise to propagate or -modify it is void, and will automatically terminate your rights under -this License (including any patent licenses granted under the third -paragraph of section 11). - - However, if you cease all violation of this License, then your -license from a particular copyright holder is reinstated (a) -provisionally, unless and until the copyright holder explicitly and -finally terminates your license, and (b) permanently, if the copyright -holder fails to notify you of the violation by some reasonable means -prior to 60 days after the cessation. - - Moreover, your license from a particular copyright holder is -reinstated permanently if the copyright holder notifies you of the -violation by some reasonable means, this is the first time you have -received notice of violation of this License (for any work) from that -copyright holder, and you cure the violation prior to 30 days after -your receipt of the notice. - - Termination of your rights under this section does not terminate the -licenses of parties who have received copies or rights from you under -this License. If your rights have been terminated and not permanently -reinstated, you do not qualify to receive new licenses for the same -material under section 10. - - 9. Acceptance Not Required for Having Copies. - - You are not required to accept this License in order to receive or -run a copy of the Program. Ancillary propagation of a covered work -occurring solely as a consequence of using peer-to-peer transmission -to receive a copy likewise does not require acceptance. However, -nothing other than this License grants you permission to propagate or -modify any covered work. These actions infringe copyright if you do -not accept this License. Therefore, by modifying or propagating a -covered work, you indicate your acceptance of this License to do so. - - 10. Automatic Licensing of Downstream Recipients. - - Each time you convey a covered work, the recipient automatically -receives a license from the original licensors, to run, modify and -propagate that work, subject to this License. You are not responsible -for enforcing compliance by third parties with this License. - - An "entity transaction" is a transaction transferring control of an -organization, or substantially all assets of one, or subdividing an -organization, or merging organizations. If propagation of a covered -work results from an entity transaction, each party to that -transaction who receives a copy of the work also receives whatever -licenses to the work the party's predecessor in interest had or could -give under the previous paragraph, plus a right to possession of the -Corresponding Source of the work from the predecessor in interest, if -the predecessor has it or can get it with reasonable efforts. - - You may not impose any further restrictions on the exercise of the -rights granted or affirmed under this License. For example, you may -not impose a license fee, royalty, or other charge for exercise of -rights granted under this License, and you may not initiate litigation -(including a cross-claim or counterclaim in a lawsuit) alleging that -any patent claim is infringed by making, using, selling, offering for -sale, or importing the Program or any portion of it. - - 11. Patents. - - A "contributor" is a copyright holder who authorizes use under this -License of the Program or a work on which the Program is based. The -work thus licensed is called the contributor's "contributor version". - - A contributor's "essential patent claims" are all patent claims -owned or controlled by the contributor, whether already acquired or -hereafter acquired, that would be infringed by some manner, permitted -by this License, of making, using, or selling its contributor version, -but do not include claims that would be infringed only as a -consequence of further modification of the contributor version. For -purposes of this definition, "control" includes the right to grant -patent sublicenses in a manner consistent with the requirements of -this License. - - Each contributor grants you a non-exclusive, worldwide, royalty-free -patent license under the contributor's essential patent claims, to -make, use, sell, offer for sale, import and otherwise run, modify and -propagate the contents of its contributor version. - - In the following three paragraphs, a "patent license" is any express -agreement or commitment, however denominated, not to enforce a patent -(such as an express permission to practice a patent or covenant not to -sue for patent infringement). To "grant" such a patent license to a -party means to make such an agreement or commitment not to enforce a -patent against the party. - - If you convey a covered work, knowingly relying on a patent license, -and the Corresponding Source of the work is not available for anyone -to copy, free of charge and under the terms of this License, through a -publicly available network server or other readily accessible means, -then you must either (1) cause the Corresponding Source to be so -available, or (2) arrange to deprive yourself of the benefit of the -patent license for this particular work, or (3) arrange, in a manner -consistent with the requirements of this License, to extend the patent -license to downstream recipients. "Knowingly relying" means you have -actual knowledge that, but for the patent license, your conveying the -covered work in a country, or your recipient's use of the covered work -in a country, would infringe one or more identifiable patents in that -country that you have reason to believe are valid. - - If, pursuant to or in connection with a single transaction or -arrangement, you convey, or propagate by procuring conveyance of, a -covered work, and grant a patent license to some of the parties -receiving the covered work authorizing them to use, propagate, modify -or convey a specific copy of the covered work, then the patent license -you grant is automatically extended to all recipients of the covered -work and works based on it. - - A patent license is "discriminatory" if it does not include within -the scope of its coverage, prohibits the exercise of, or is -conditioned on the non-exercise of one or more of the rights that are -specifically granted under this License. You may not convey a covered -work if you are a party to an arrangement with a third party that is -in the business of distributing software, under which you make payment -to the third party based on the extent of your activity of conveying -the work, and under which the third party grants, to any of the -parties who would receive the covered work from you, a discriminatory -patent license (a) in connection with copies of the covered work -conveyed by you (or copies made from those copies), or (b) primarily -for and in connection with specific products or compilations that -contain the covered work, unless you entered into that arrangement, -or that patent license was granted, prior to 28 March 2007. - - Nothing in this License shall be construed as excluding or limiting -any implied license or other defenses to infringement that may -otherwise be available to you under applicable patent law. - - 12. No Surrender of Others' Freedom. - - If conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot convey a -covered work so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you may -not convey it at all. For example, if you agree to terms that obligate you -to collect a royalty for further conveying from those to whom you convey -the Program, the only way you could satisfy both those terms and this -License would be to refrain entirely from conveying the Program. - - 13. Use with the GNU Affero General Public License. - - Notwithstanding any other provision of this License, you have -permission to link or combine any covered work with a work licensed -under version 3 of the GNU Affero General Public License into a single -combined work, and to convey the resulting work. The terms of this -License will continue to apply to the part which is the covered work, -but the special requirements of the GNU Affero General Public License, -section 13, concerning interaction through a network will apply to the -combination as such. - - 14. Revised Versions of this License. - - The Free Software Foundation may publish revised and/or new versions of -the GNU General Public License from time to time. Such new versions will -be similar in spirit to the present version, but may differ in detail to -address new problems or concerns. - - Each version is given a distinguishing version number. If the -Program specifies that a certain numbered version of the GNU General -Public License "or any later version" applies to it, you have the -option of following the terms and conditions either of that numbered -version or of any later version published by the Free Software -Foundation. If the Program does not specify a version number of the -GNU General Public License, you may choose any version ever published -by the Free Software Foundation. - - If the Program specifies that a proxy can decide which future -versions of the GNU General Public License can be used, that proxy's -public statement of acceptance of a version permanently authorizes you -to choose that version for the Program. - - Later license versions may give you additional or different -permissions. However, no additional obligations are imposed on any -author or copyright holder as a result of your choosing to follow a -later version. - - 15. Disclaimer of Warranty. - - THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY -APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT -HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY -OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, -THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM -IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF -ALL NECESSARY SERVICING, REPAIR OR CORRECTION. - - 16. Limitation of Liability. - - IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS -THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY -GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE -USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF -DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD -PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), -EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF -SUCH DAMAGES. - - 17. Interpretation of Sections 15 and 16. - - If the disclaimer of warranty and limitation of liability provided -above cannot be given local legal effect according to their terms, -reviewing courts shall apply local law that most closely approximates -an absolute waiver of all civil liability in connection with the -Program, unless a warranty or assumption of liability accompanies a -copy of the Program in return for a fee. - - END OF TERMS AND CONDITIONS diff --git a/thirdparty/liblastfm2/README.md b/thirdparty/liblastfm2/README.md deleted file mode 100644 index 4132ce5ea..000000000 --- a/thirdparty/liblastfm2/README.md +++ /dev/null @@ -1,126 +0,0 @@ -liblastfm -========= -liblastfm is a collection of libraries to help you integrate Last.fm services -into your rich desktop software. It is officially supported software developed -by Last.fm staff. - -Michael Coffey http://twitter.com/eartle - -Fork it: http://github.com/eartle/liblastfm - - -Dependencies -============ -liblastfm dynamically links to: - -* Qt 4.8 - http://qt.nokia.com/ -* FFTW 3.2 - Compiled with single precision - http://www.fftw.org -* Secret Rabbit code (aka libsamplerate) - http://www.mega-nerd.com/SRC - -Additionally, to build you will need Ruby and GNU make (or Microsoft nmake). - -Mac OS X --------- - sudo port selfupdate - sudo port upgrade installed - sudo port install libsamplerate fftw-3 qt4-mac-devel - -Linux/*NIX ----------- -Do something like this: - - sudo apt-get install qt4-qmake pkg-config libsamplerate-dev libfftw3-dev ruby g++ libqt4-dev - -Additionally on Linux the configure process requires lsb_release. This is -usually already installed (correct me if I'm wrong). - -Please note, we have only tested on Linux, but we think it'll work on all -varieties of UNIX. If it doesn't, report the bug to eartle on GitHub. - -Windows -------- -Install Ruby. Install Visual Studio 2008 or higher. Install Qt. Install the -Windows Server 2003 Platform SDK r2: - -http://www.microsoft.com/Downloads/details.aspx?FamilyID=484269e2-3b89-47e3-8eb7-1f2be6d7123a - -Set up your environment variables so all include paths and tools are -available. - -Build and install FFTW and Secret Rabbit Code. - -Open a plain Windows shell (Cygwin will work but we don't recommend it), and -see the next section. - - -Installing liblastfm -==================== - qmake && make && sudo make install - -Packaging liblastfm -------------------- -liblastfm builds to two dynamic libraries (liblastfm.so and -liblastfm_fingerprint.so). liblastfm.so links only to Qt, but the -fingerprinting part has additional dependencies. So ideally, you would -distribute two packages. - - -Using liblastfm -=============== -We have copied the API at http://last.fm/api onto C++, so like you find -artist.getInfo there you will find an lastfm::Artist::getInfo function in our -C++ API. lastfm is a namespace, Artist a class and getInfo a function. - -Thus the API is quite easy to learn. We suggest installing and checking the -include/lastfm/* directory to find out all capabilities. - -The demos directory shows some further basic usage including Audioscrobbling -and getting metadata for music via our fingerprinting technology. - -You need an API key from http://last.fm/api to use the webservice API. - -Your link line needs to include the following: - - -llastfm -lQtCore -lQtNetwork -lQtXml - -Radio ------ -Please set an identifiable UserAgent on your HTTP requests for the actual MP3s, -in extreme cases we'll contact you directly and demand you do so :P - -HTTP & Networking ------------------ -You can specify your own QNetworkAccessManager derived class for liblastfm to -use with lastfm::setNetworkAccessManager(). Our default is pretty good -though, auto-determining proxy settings on Windows and OS X for instance. - - -Using liblastfm_fingerprint -=========================== -The liblastfm_fingerprint library does not decode audio files. We anticipate -that Phonon will soon do that work for us. In the meantime, sample *Source -files for MP3, Ogg Vorbis, FLAC, and AAC/MP4 are available in -src/fingerprint/contrib. If you want to fingerprint files or get metadata -suggestions, you either need to add the *Source files to your project, or -implement your own. - - -Development -=========== -Public Headers --------------- -1. Header guards should be prefixed with LASTFM, eg. LASTFM_WS_REPLY_H -2. #includes should be to the system path eg. #include -3. Don't make a header public unless it is absolutely required! -4. To make the header public edit the headers.files line in the pro file - -Private Headers ---------------- -1. For consistency and to make it more obvious it is a private header, don't - prefix the header guard with LASTFM -2. #includes should be the full source tree path, eg. - #include "../core/UrlBuilder.h" diff --git a/thirdparty/liblastfm2/cmake/modules/FindLibFFTW3.cmake b/thirdparty/liblastfm2/cmake/modules/FindLibFFTW3.cmake deleted file mode 100644 index fa6419a2b..000000000 --- a/thirdparty/liblastfm2/cmake/modules/FindLibFFTW3.cmake +++ /dev/null @@ -1,45 +0,0 @@ -# This file is copyrighted under the BSD-license for buildsystem files of KDE -# copyright 2010, Patrick von Reth -# -# -# - Try to find the LIBFFTW3 library -# Once done this will define -# -# LIBFFTW3_FOUND Set to TRUE if LIBFFTW3 librarys and include directory is found -# LIBFFTW3_INCLUDE_DIR The libfftw3 include directory -# LIBFFTW3_LIBRARY The libfftw3 librarys - -if(NOT LIBFFTW3_PRECISION) - message(STATUS "Searching for LIBFFTW3, using default precision float") - set(LIBFFTW3_PRECISION FLOAT) -endif(NOT LIBFFTW3_PRECISION) - -find_path(LIBFFTW3_INCLUDE_DIR fftw3.h) - -if(LIBFFTW3_PRECISION STREQUAL FLOAT) - set(LIBFFTW3_PRECISION_SUFFIX f) -endif(LIBFFTW3_PRECISION STREQUAL FLOAT) - -if(LIBFFTW3_PRECISION STREQUAL DOUBLE) - set(LIBFFTW3_PRECISION_SUFFIX "") -endif(LIBFFTW3_PRECISION STREQUAL DOUBLE) - -if(LIBFFTW3_PRECISION STREQUAL LDOUBLE) - set(LIBFFTW3_PRECISION_SUFFIX l) -endif(LIBFFTW3_PRECISION STREQUAL LDOUBLE) - -find_library(LIBFFTW3_LIBRARY NAMES fftw3${LIBFFTW3_PRECISION_SUFFIX} libfftw3${LIBFFTW3_PRECISION_SUFFIX}-3 fftw3${LIBFFTW3_PRECISION_SUFFIX}-3) - -if(FIND_LIBFFTW3_VERBOSE) - message(STATUS - "LIBFFTW3_PRECISION ${LIBFFTW3_PRECISION}, searched for fftw3${LIBFFTW3_PRECISION_SUFFIX} libfftw3${LIBFFTW3_PRECISION_SUFFIX}-3 fftw3${LIBFFTW3_PRECISION_SUFFIX}-3 - and found ${LIBFFTW3_LIBRARY}" - ) -endif(FIND_LIBFFTW3_VERBOSE) - -if(LIBFFTW3_LIBRARY AND LIBFFTW3_INCLUDE_DIR) - set(LIBFFTW3_FOUND TRUE) - message(STATUS "Found libfftw3 ${LIBFFTW3_LIBRARY}") -else(LIBFFTW3_LIBRARY AND LIBFFTW3_PLUGIN_PATH) - message(STATUS "Could not find libfftw3, get it http://www.fftw.org/") -endif(LIBFFTW3_LIBRARY AND LIBFFTW3_INCLUDE_DIR) diff --git a/thirdparty/liblastfm2/cmake/modules/FindLibSamplerate.cmake b/thirdparty/liblastfm2/cmake/modules/FindLibSamplerate.cmake deleted file mode 100644 index d77536b2f..000000000 --- a/thirdparty/liblastfm2/cmake/modules/FindLibSamplerate.cmake +++ /dev/null @@ -1,22 +0,0 @@ -# This file is copyrighted under the BSD-license for buildsystem files of KDE -# copyright 2010, Patrick von Reth -# -# -# - Try to find the libsamplerate library -# Once done this will define -# -# LIBSAMPLERATE_FOUND Set to TRUE if libsamplerate librarys and include directory is found -# LIBSAMPLERATE_LIBRARY The libsamplerate librarys -# LIBSAMPLERATE_INCLUDE_DIR The libsamplerate include directory - - -find_library(LIBSAMPLERATE_LIBRARY NAMES samplerate libsamplerate-0 samplerate-0) - -find_path(LIBSAMPLERATE_INCLUDE_DIR samplerate.h) - -if(LIBSAMPLERATE_LIBRARY AND LIBSAMPLERATE_INCLUDE_DIR) - set(LIBSAMPLERATE_FOUND TRUE) - message(STATUS "Found libsamplerate ${LIBSAMPLERATE_LIBRARY}") -else(LIBSAMPLERATE_LIBRARY AND LIBSAMPLERATE_PLUGIN_PATH) - message(STATUS "Could not find libsamplerate, get it http://www.mega-nerd.com/SRC/") -endif(LIBSAMPLERATE_LIBRARY AND LIBSAMPLERATE_INCLUDE_DIR) diff --git a/thirdparty/liblastfm2/demos/demo1.cpp b/thirdparty/liblastfm2/demos/demo1.cpp deleted file mode 100644 index b0fd8df99..000000000 --- a/thirdparty/liblastfm2/demos/demo1.cpp +++ /dev/null @@ -1,95 +0,0 @@ -/* - This software is in the public domain, furnished "as is", without technical - support, and with no warranty, express or implied, as to its usefulness for - any purpose. -*/ -#include // this includes everything in liblastfm, you may prefer -#include // to just include what you need with your project. Still -#include // we've given you the option. -#include -#include - -class ArtistList : public QListWidget -{ - Q_OBJECT - - QPointer reply; - QString artist; - -public: - ArtistList() - { - connect( this, - SIGNAL(itemActivated( QListWidgetItem* )), - SLOT(onItemActivated( QListWidgetItem* )) ); - } - - void getSimilar( const QString& artist ) - { - this->artist = artist; - setWindowTitle( "Loading " + artist + "..." ); - - // deleting a reply cancels the request and disconnects all signals - delete reply; - reply = lastfm::Artist( artist ).getSimilar(); - connect( reply, SIGNAL(finished()), SLOT(onGotSimilar()) ); - } - -private slots: - void onGotSimilar() - { - QNetworkReply* r = static_cast(sender()); - // always enclose retrieval functions in a try block, as they will - // throw if they can't parse the data - try - { - // you decode the response using the equivalent static function - QMap artists = lastfm::Artist::getSimilar( r ); - - clear(); - - // we iterate backwards because best match is last because the map - // sorts itself by key - QStringListIterator i( artists.values() ); - i.toBack(); - while (i.hasPrevious()) - addItem( i.previous() ); - - setWindowTitle( artist ); - } - catch (std::runtime_error& e) - { - // if getSimilar() failed to parse the QNetworkReply, then e will - // be of type lastfm::ws::ParseError, which derives - // std::runtime_error - qWarning() << e.what(); - } - } - - void onItemActivated( QListWidgetItem* item ) - { - getSimilar( item->text() ); - } -}; - - -int main( int argc, char** argv ) -{ - QApplication app( argc, argv ); - app.setApplicationName( "liblastfm" ); // used to generate UserAgent - - // all you need for non-authenticated webservices is your API key - // this one is a public one, it can only do artist.getSimilar calls, so - // I suggest you don't use it :P - lastfm::ws::ApiKey = "b25b959554ed76058ac220b7b2e0a026"; - - ArtistList artists; - artists.getSimilar( "nirvana" ); - artists.resize( 300, 400 ); // Qt picks truly asanine default sizes for its widgets - artists.show(); - - return app.exec(); -} - - -#include "demo1.moc" diff --git a/thirdparty/liblastfm2/demos/demo2.cpp b/thirdparty/liblastfm2/demos/demo2.cpp deleted file mode 100644 index 53c9a7ec9..000000000 --- a/thirdparty/liblastfm2/demos/demo2.cpp +++ /dev/null @@ -1,114 +0,0 @@ -/* - This software is in the public domain, furnished "as is", without technical - support, and with no warranty, express or implied, as to its usefulness for - any purpose. -*/ -#include -#include - - -struct MyCoreApp : QCoreApplication -{ - Q_OBJECT - -public: - MyCoreApp( int& argc, char**& argv ) : QCoreApplication( argc, argv ) - {} - -private slots: - void onWsError( lastfm::ws::Error e ) - { - // QNetworkReply will invoke this slot on application level errors - // mostly this is only stuff like Ws::InvalidSessionKey and - // Ws::InvalidApiKey - qWarning() << e; - } -}; - - -int main( int argc, char** argv ) -{ - MyCoreApp app( argc, argv ); - // this is used to generate the UserAgent for webservice requests - // please set it to something sensible in your application - app.setApplicationName( "liblastfm" ); - -////// you'll need to fill these in for this demo to work - lastfm::ws::Username = - lastfm::ws::ApiKey = - lastfm::ws::SharedSecret = - QString password = - -////// Usually you never have to construct an Last.fm WS API call manually - // eg. Track.getTopTags() just returns a QNetworkReply* but authentication is - // different. - // We're using getMobileSession here as we're a console app, but you - // should use getToken if you can as the user will be presented with a - // route that feels my trustworthy to them than entering their password - // into some random app they just downloaded... ;) - QMap params; - params["method"] = "auth.getMobileSession"; - params["username"] = lastfm::ws::Username; - params["authToken"] = lastfm::md5( (lastfm::ws::Username + lastfm::md5( password.toUtf8() )).toUtf8() ); - QNetworkReply* reply = lastfm::ws::post( params ); - - // never do this when an event loop is running it's a real HACK - QEventLoop loop; - loop.connect( reply, SIGNAL(finished()), SLOT(quit()) ); - loop.exec(); - - try - { - ////// Usually there is a convenience function to decode the output from - // ws calls too, but again, authentication is different. We think you - // need to handle it yourselves :P Also conveniently it means you - // can learn more about what our webservices return, eg. this service - // will return an XML document like this: - // - // - // - // mxcl - // d580d57f32848f5dcf574d1ce18d78b2 - // 1 - // - // - // - // If status is not "ok" then this function throws - lastfm::XmlQuery const lfm = lastfm::ws::parse( reply ); - - // replace username; because eg. perhaps the user typed their - // username with the wrong case - lastfm::ws::Username = lfm["session"]["name"].text(); - - // we now have a session key, you should save this, forever! Really. - // DO NOT AUTHENTICATE EVERY TIME THE APP STARTS! You only have to do - // this once. Or again if the user deletes your key on the site. If - // that happens you'll get notification to your onWsError() function, - // see above. - lastfm::ws::SessionKey = lfm["session"]["key"].text(); - - qDebug() << "sk:" << lastfm::ws::SessionKey; - - ////// because the SessionKey is now set, the AuthenticatedUser class will - // work. And we can call authenticated calls - QNetworkReply* reply = lastfm::AuthenticatedUser().getRecommendedArtists(); - - // again, you shouldn't do this.. ;) - QEventLoop loop; - loop.connect( reply, SIGNAL(finished()), SLOT(quit()) ); - loop.exec(); - - // yay, a list rec'd artists to stderr :) - qDebug() << lastfm::Artist::list( reply ); - } - catch (std::runtime_error& e) - { - // lastfm::ws::parse() can throw lastfm::ws::ParseError, this - // exception derives std::runtime_error - qWarning() << e.what(); - return 1; - } -} - - -#include "demo2.moc" diff --git a/thirdparty/liblastfm2/demos/demo3.cpp b/thirdparty/liblastfm2/demos/demo3.cpp deleted file mode 100644 index 2bf3c1db3..000000000 --- a/thirdparty/liblastfm2/demos/demo3.cpp +++ /dev/null @@ -1,63 +0,0 @@ -/* - This software is in the public domain, furnished "as is", without technical - support, and with no warranty, express or implied, as to its usefulness for - any purpose. -*/ -#include -#include -#include -#include "src/_version.h" - - -struct MyCoreApp : QCoreApplication -{ - Q_OBJECT - -public: - MyCoreApp( int& argc, char** argv ) : QCoreApplication( argc, argv ) - {} - -public slots: - void onStatus( int status ) - { - qDebug() << lastfm::Audioscrobbler::Status(status); - } -}; - - -int main( int argc, char** argv ) -{ - // all 6 of these lines are REQUIRED in order to scrobble - // this demo requires you to fill in the blanks as well... - lastfm::ws::Username = - lastfm::ws::ApiKey = - lastfm::ws::SharedSecret = - lastfm::ws::SessionKey = // you need to auth to get this... try demo2 - QCoreApplication::setApplicationName( "liblastfm" ); - QCoreApplication::setApplicationVersion( VERSION ); - - MyCoreApp app( argc, argv ); - - lastfm::MutableTrack t; - t.setArtist( "Max Howell" ); - t.setTitle( "I Told You Not To Trust Me With Your Daughter" ); - t.setDuration( 30 ); - t.stamp(); //sets track start time - - lastfm::Audioscrobbler as( "ass" ); - as.nowPlaying( t ); - // Audioscrobbler will submit whatever is in the cache when you call submit. - // And the cache is persistent between sessions. So you should cache at the - // scrobble point usually, not before - as.cache( t ); - - //FIXME I don't get it, but the timer never triggers! pls fork and fix! - QTimer::singleShot( 31*1000, &as, SLOT(submit()) ); - - app.connect( &as, SIGNAL(status(int)), SLOT(onStatus(int)) ); - - return app.exec(); -} - - -#include "demo3.moc" diff --git a/thirdparty/liblastfm2/demos/demos.pro b/thirdparty/liblastfm2/demos/demos.pro deleted file mode 100644 index 356edff74..000000000 --- a/thirdparty/liblastfm2/demos/demos.pro +++ /dev/null @@ -1,3 +0,0 @@ -QT = core gui network xml -LIBS += -llastfm -L$$DESTDIR -SOURCES = demo1.cpp # change to demo2.cpp (etc.) to compile that demo diff --git a/thirdparty/liblastfm2/lastfm.pro b/thirdparty/liblastfm2/lastfm.pro deleted file mode 100644 index 32839418e..000000000 --- a/thirdparty/liblastfm2/lastfm.pro +++ /dev/null @@ -1,142 +0,0 @@ -TEMPLATE = lib -CONFIG += dll -QT = core network xml - -ROOT_DIR = . - -BUILD_DIR = _build -DESTDIR = $$ROOT_DIR/_bin - -OBJECTS_DIR = $$BUILD_DIR -MOC_DIR = $$BUILD_DIR -UI_DIR = $$BUILD_DIR -RCC_DIR = $$BUILD_DIR -INCLUDEPATH += $$ROOT_DIR/_include - -win32:DEFINES += _CRT_SECURE_NO_WARNINGS WIN32_LEAN_AND_MEAN - -mac { - QMAKE_PKGINFO_TYPEINFO = last - QMAKE_MACOSX_DEPLOYMENT_TARGET = 10.4 -} - -*g++* { - # allow use of 'and', 'or', etc. as symbols - QMAKE_CXXFLAGS += -fno-operator-names - QMAKE_CXXFLAGS_RELEASE += -fvisibility-inlines-hidden -fvisibility=hidden -} - -# used to determine if we should statically link the fingerprint library -# used by lastfm-desktop and other projects -CONFIG -= app_bundle - -win32{ -INSTALLS = headers -headers.path = _include/lastfm -headers.files = src/*.h -} -else{ - isEmpty( PREFIX ) { - PREFIX=/usr/local - } -INSTALLS = target headers -target.path = $${PREFIX}/lib -headers.path = $${PREFIX}/include/lastfm -headers.files = src/*.h -} - -INCLUDEPATH += src - -win32{ - DEFINES += LASTFM_LIB _ATL_DLL - LIBS += winhttp.lib wbemuuid.lib # ws configuration -} -mac{ - LIBS += -framework SystemConfiguration # ws configuration - #TODO we should only use these with the carbon version of Qt! - LIBS += -framework CoreFoundation # various -} - -unix:!mac{ - QT += dbus -} - -SOURCES += \ - src/ws.cpp \ - src/NetworkConnectionMonitor.cpp \ - src/NetworkAccessManager.cpp \ - src/InternetConnectionMonitor.cpp \ - src/Xspf.cpp \ - src/User.cpp \ - src/Track.cpp \ - src/Tasteometer.cpp \ - src/Tag.cpp \ - src/Playlist.cpp \ - src/Mbid.cpp \ - src/FingerprintId.cpp \ - src/Artist.cpp \ - src/Album.cpp \ - src/ScrobbleCache.cpp \ - src/ScrobblePoint.cpp \ - src/Audioscrobbler.cpp \ - src/RadioTuner.cpp \ - src/RadioStation.cpp \ - src/XmlQuery.cpp \ - src/UrlBuilder.cpp \ - src/misc.cpp \ - src/Chart.cpp \ - src/Auth.cpp \ - src/Library.cpp - -HEADERS += \ - src/ws.h \ - src/NetworkConnectionMonitor.h \ - src/NetworkAccessManager.h \ - src/InternetConnectionMonitor.h \ - src/Xspf.h \ - src/User.h \ - src/Track.h \ - src/Tasteometer.h \ - src/Tag.h \ - src/Playlist.h \ - src/Mbid.h \ - src/FingerprintId.h \ - src/Artist.h \ - src/Album.h \ - src/AbstractType.h \ - src/ScrobblePoint.h \ - src/ScrobbleCache.h \ - src/Audioscrobbler.h \ - src/RadioTuner.h \ - src/RadioStation.h \ - src/global.h \ - src/XmlQuery.h \ - src/UrlBuilder.h \ - src/misc.h \ - src/Chart.h \ - src/Auth.h \ - src/Library.h - -win32:SOURCES += src/win/WNetworkConnectionMonitor_win.cpp \ - src/win/WmiSink.cpp \ - src/win/Pac.cpp \ - src/win/NdisEvents.cpp - -win32:HEADERS += src/win/WNetworkConnectionMonitor.h \ - src/win/WmiSink.h \ - src/win/Pac.h \ - src/win/NdisEvents.h \ - src/win/IeSettings.h \ - src/win/ComSetup.h - -mac:SOURCES += src/mac/MNetworkConnectionMonitor_mac.cpp - -mac:HEADERS += src/mac/ProxyDict.h \ - src/mac/MNetworkConnectionMonitor.h - -unix:!mac:SOURCES += src/linux/LNetworkConnectionMonitor_linux.cpp -unix:!mac:HEADERS += src/linux/LNetworkConnectionMonitor.h - -!win32:VERSION = 1.0.0 - - diff --git a/thirdparty/liblastfm2/src/CMakeLists.txt b/thirdparty/liblastfm2/src/CMakeLists.txt deleted file mode 100644 index 56c203c14..000000000 --- a/thirdparty/liblastfm2/src/CMakeLists.txt +++ /dev/null @@ -1,125 +0,0 @@ -cmake_minimum_required(VERSION 2.6) - -# Macro to copy and rename headers -macro(copy_header from to) - configure_file( - ${CMAKE_CURRENT_SOURCE_DIR}/${from} - ${CMAKE_CURRENT_BINARY_DIR}/lastfm/${to} - COPY_ONLY - ) -endmacro(copy_header) - -# Copy headers -copy_header(core/misc.h misc.h) -copy_header(core/XmlQuery.h XmlQuery) -copy_header(core/UrlBuilder.h UrlBuilder) -copy_header(global.h global.h) -copy_header(radio/RadioTuner.h RadioTuner) -copy_header(radio/RadioStation.h RadioStation) -copy_header(scrobble/Audioscrobbler.h Audioscrobbler) -copy_header(scrobble/ScrobbleCache.h ScrobbleCache) -copy_header(scrobble/ScrobblePoint.h ScrobblePoint) -copy_header(types/AbstractType.h AbstractType) -copy_header(types/Album.h Album) -copy_header(types/Artist.h Artist) -copy_header(types/FingerprintId.h FingerprintId) -copy_header(types/Mbid.h Mbid) -copy_header(types/Playlist.h Playlist) -copy_header(types/Tag.h Tag) -copy_header(types/Track.h Track) -copy_header(types/User.h User) -copy_header(types/User.h UserList) -copy_header(types/Xspf.h Xspf) -copy_header(ws/ws.h ws.h) -copy_header(ws/InternetConnectionMonitor.h InternetConnectionMonitor) -copy_header(ws/NetworkAccessManager.h NetworkAccessManager) - -include_directories(${QT_INCLUDES} ${CMAKE_CURRENT_BINARY_DIR}) - -set(SOURCES - scrobble/ScrobbleCache.cpp - scrobble/Audioscrobbler.cpp - types/FingerprintId.cpp - types/Artist.cpp - types/Tag.cpp - types/Track.cpp - types/User.cpp - types/Xspf.cpp - types/Album.cpp - types/Playlist.cpp - types/Mbid.cpp - radio/RadioTuner.cpp - radio/RadioStation.cpp - core/UrlBuilder.cpp - core/misc.cpp - core/XmlQuery.cpp - ws/NetworkAccessManager.cpp - ws/ws.cpp - ws/InternetConnectionMonitor.cpp - ws/NetworkConnectionMonitor.cpp -) - -set(MOC_HEADERS - scrobble/Audioscrobbler.h - types/Track.h - types/Xspf.h - radio/RadioTuner.h - ws/NetworkConnectionMonitor.h - ws/InternetConnectionMonitor.h - ws/NetworkAccessManager.h -) - -if(UNIX) - if(APPLE) - set(SOURCES ${SOURCES} ws/mac/MNetworkConnectionMonitor_mac.cpp) - set(MOC_HEADERS ${MOC_HEADERS} ws/mac/MNetworkConnectionMonitor.h) - else(APPLE) - set(SOURCES ${SOURCES} ws/linux/LNetworkConnectionMonitor_linux.cpp) - set(MOC_HEADERS ${MOC_HEADERS} ws/linux/LNetworkConnectionMonitor.h) - endif(APPLE) -endif(UNIX) -if(WIN32) - set(SOURCES ${SOURCES} ws/win/WNetworkConnectionMonitor_win.cpp ws/win/Pac.cpp ws/win/NdisEvents.cpp ) - set(MOC_HEADERS ${MOC_HEADERS} ws/win/WNetworkConnectionMonitor.h) - include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../../winhttp) -endif(WIN32) - -qt4_wrap_cpp(MOC_SOURCES ${MOC_HEADERS}) - -IF( WIN32 ) - add_definitions( -DLASTFM_LIB ) - add_library(tomahawk_lastfm2 SHARED - ${SOURCES} - ${MOC_SOURCES} - ) -ELSE() - add_definitions(-fPIC) - add_library(tomahawk_lastfm2 STATIC - ${SOURCES} - ${MOC_SOURCES} - ) -ENDIF() - -target_link_libraries(tomahawk_lastfm2 - ${QT_LIBRARIES} - ${QT_QTDBUS_LIBRARY} - -) - -set_target_properties(tomahawk_lastfm2 PROPERTIES COMPILE_FLAGS "-DLASTFM_OHAI_QMAKE" ) - -if(APPLE) - target_link_libraries(tomahawk_lastfm2 - /System/Library/Frameworks/CoreFoundation.framework - /System/Library/Frameworks/SystemConfiguration.framework - ) -endif(APPLE) - - -IF( WIN32 ) - install(TARGETS tomahawk_lastfm2 - RUNTIME DESTINATION bin - LIBRARY DESTINATION lib${LIB_SUFFIX} - ARCHIVE DESTINATION lib${LIB_SUFFIX} - ) -ENDIF() diff --git a/thirdparty/liblastfm2/src/core/README b/thirdparty/liblastfm2/src/core/README deleted file mode 100644 index b725eac20..000000000 --- a/thirdparty/liblastfm2/src/core/README +++ /dev/null @@ -1,8 +0,0 @@ -Files in lastfm-core are basically extensions to fundamental Qt classes. -They may be useful to you, but mainly they are here because they are useful to -liblastfm in general. - -A lot of the time they are convenience functions that hopefully at some point -Qt will make obsolete. - - diff --git a/thirdparty/liblastfm2/src/core/UrlBuilder.cpp b/thirdparty/liblastfm2/src/core/UrlBuilder.cpp deleted file mode 100644 index 1e0171aa1..000000000 --- a/thirdparty/liblastfm2/src/core/UrlBuilder.cpp +++ /dev/null @@ -1,83 +0,0 @@ -/* - Copyright 2009 Last.fm Ltd. - - Primarily authored by Max Howell, Jono Cole and Doug Mansell - - This file is part of liblastfm. - - liblastfm is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - liblastfm is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with liblastfm. If not, see . -*/ -#include "UrlBuilder.h" -#include -#include - - -QUrl -lastfm::UrlBuilder::url() const -{ - QUrl url; - url.setScheme( "http" ); - url.setHost( host() ); - url.setEncodedPath( path ); - return url; -} - - -QByteArray //static -lastfm::UrlBuilder::encode( QString s ) -{ - foreach (QChar c, QList() << '%' << '&' << '/' << ';' << '+' << '#' << '"') - if (s.contains( c )) - // the middle step may seem odd but this is what the site does - // eg. search for the exact string "Radiohead 2 + 2 = 5" - return QUrl::toPercentEncoding( s ).replace( "%20", "+" ).toPercentEncoding( "", "+" );; - - return QUrl::toPercentEncoding( s.replace( ' ', '+' ), "+" ); -} - - -QString //static -lastfm::UrlBuilder::host( const QLocale& locale ) -{ - switch (locale.language()) - { - case QLocale::Portuguese: return "www.lastfm.com.br"; - case QLocale::Turkish: return "www.lastfm.com.tr"; - case QLocale::French: return "www.lastfm.fr"; - case QLocale::Italian: return "www.lastfm.it"; - case QLocale::German: return "www.lastfm.de"; - case QLocale::Spanish: return "www.lastfm.es"; - case QLocale::Polish: return "www.lastfm.pl"; - case QLocale::Russian: return "www.lastfm.ru"; - case QLocale::Japanese: return "www.lastfm.jp"; - case QLocale::Swedish: return "www.lastfm.se"; - case QLocale::Chinese: return "cn.last.fm"; - default: return "www.last.fm"; - } -} - - -QUrl //static -lastfm::UrlBuilder::localize( QUrl url) -{ - url.setHost( url.host().replace( QRegExp("^(www.)?last.fm"), host() ) ); - return url; -} - - -QUrl //static -lastfm::UrlBuilder::mobilize( QUrl url ) -{ - url.setHost( url.host().replace( QRegExp("^(www.)?last"), "m.last" ) ); - return url; -} diff --git a/thirdparty/liblastfm2/src/core/UrlBuilder.h b/thirdparty/liblastfm2/src/core/UrlBuilder.h deleted file mode 100644 index 42014537c..000000000 --- a/thirdparty/liblastfm2/src/core/UrlBuilder.h +++ /dev/null @@ -1,69 +0,0 @@ -/* - Copyright 2009 Last.fm Ltd. - - Primarily authored by Max Howell, Jono Cole and Doug Mansell - - This file is part of liblastfm. - - liblastfm is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - liblastfm is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with liblastfm. If not, see . -*/ -#ifndef LASTFM_URL_BUILDER_H -#define LASTFM_URL_BUILDER_H - -#include -#include -#include -#include - - -namespace lastfm -{ - /** For building www.last.fm urls. We have special rules for encoding and that */ - class LASTFM_DLLEXPORT UrlBuilder - { - QByteArray path; - - public: - /** Careful, the base is not encoded at all, we assume it is ASCII! - * If you need it encoded at all you must use the slash function. - * eg. UrlBuilder( "user" ).slash( "mxcl" ) ==> http://last.fm/user/mxcl - */ - UrlBuilder( const QString& base ) : path( '/' + base.toAscii() ) - {} - - UrlBuilder& slash( const QString& path ) { this->path += '/' + encode( path ); return *this; } - - QUrl url() const; - - /** www.last.fm becomes the local version, eg www.lastfm.de */ - static QUrl localize( QUrl ); - /** www.last.fm becomes m.last.fm, localisation is preserved */ - static QUrl mobilize( QUrl ); - - /** Use this to URL encode any database item (artist, track, album). It - * internally calls UrlEncodeSpecialChars to double encode some special - * symbols according to the same pattern as that used on the website. - * - * &, /, ;, +, # - * - * Use for any urls that go to www.last.fm - * Do not use for ws.audioscrobbler.com - */ - static QByteArray encode( QString ); - - /** returns eg. www.lastfm.de */ - static QString host( const QLocale& = QLocale() ); - }; -} - -#endif diff --git a/thirdparty/liblastfm2/src/core/XmlQuery.cpp b/thirdparty/liblastfm2/src/core/XmlQuery.cpp deleted file mode 100644 index b443e94b7..000000000 --- a/thirdparty/liblastfm2/src/core/XmlQuery.cpp +++ /dev/null @@ -1,105 +0,0 @@ -/* - Copyright 2009 Last.fm Ltd. - - Primarily authored by Max Howell, Jono Cole and Doug Mansell - - This file is part of liblastfm. - - liblastfm is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - liblastfm is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with liblastfm. If not, see . -*/ -#include "XmlQuery.h" - -#include -#include - -using lastfm::XmlQuery; - - -XmlQuery::XmlQuery( const QByteArray& bytes ) throw( lastfm::ws::ParseError ) -{ - try - { - if ( !bytes.size() ) - throw lastfm::ws::ParseError( lastfm::ws::MalformedResponse, "No data" ); - - if( !domdoc.setContent( bytes ) ) - throw lastfm::ws::ParseError( lastfm::ws::MalformedResponse, "Invalid XML" ); - - e = domdoc.documentElement(); - - if (e.isNull()) - throw lastfm::ws::ParseError( lastfm::ws::MalformedResponse, "Lfm is null" ); - - QString const status = e.attribute( "status" ); - QDomElement error = e.firstChildElement( "error" ); - uint const n = e.childNodes().count(); - - // no elements beyond the lfm is perfectably acceptable <-- wtf? - // if (n == 0) // nothing useful in the response - if (status == "failed" || (n == 1 && !error.isNull()) ) - throw error.isNull() - ? lastfm::ws::ParseError( lastfm::ws::MalformedResponse, "" ) - : lastfm::ws::ParseError( lastfm::ws::Error( error.attribute( "code" ).toUInt() ), error.text() ); - - } - catch ( lastfm::ws::ParseError e ) - { - switch ( e.enumValue() ) - { - case lastfm::ws::OperationFailed: - case lastfm::ws::InvalidApiKey: - case lastfm::ws::InvalidSessionKey: - // NOTE will never be received during the LoginDialog stage - // since that happens before this slot is registered with - // QMetaObject in App::App(). Neat :) - QMetaObject::invokeMethod( qApp, "onWsError", Q_ARG( lastfm::ws::Error, e.enumValue() ) ); - default: - throw e; - } - } -} - - -XmlQuery -XmlQuery::operator[]( const QString& name ) const -{ - QStringList parts = name.split( ' ' ); - if (parts.size() >= 2) - { - QString tagName = parts[0]; - parts = parts[1].split( '=' ); - QString attributeName = parts.value( 0 ); - QString attributeValue = parts.value( 1 ); - - foreach (XmlQuery e, children( tagName )) - if (e.e.attribute( attributeName ) == attributeValue) - return e; - } - XmlQuery xq( e.firstChildElement( name ), name.toUtf8().data() ); - xq.domdoc = this->domdoc; - return xq; -} - - -QList -XmlQuery::children( const QString& named ) const -{ - QList elements; - QDomNodeList nodes = e.elementsByTagName( named ); - for (int x = 0; x < nodes.count(); ++x) { - XmlQuery xq( nodes.at( x ).toElement() ); - xq.domdoc = this->domdoc; - elements += xq; - } - return elements; -} diff --git a/thirdparty/liblastfm2/src/core/XmlQuery.h b/thirdparty/liblastfm2/src/core/XmlQuery.h deleted file mode 100644 index 564e0fb38..000000000 --- a/thirdparty/liblastfm2/src/core/XmlQuery.h +++ /dev/null @@ -1,78 +0,0 @@ -/* - Copyright 2009 Last.fm Ltd. - - Primarily authored by Max Howell, Jono Cole and Doug Mansell - - This file is part of liblastfm. - - liblastfm is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - liblastfm is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with liblastfm. If not, see . -*/ -#ifndef LASTFM_XMLQUERY_H -#define LASTFM_XMLQUERY_H - -#include -#include -#include -#include - -namespace lastfm -{ - /** Qt's XmlQuery implementation is totally unimpressive, so this is a - * hack that feels like jQuery */ - class LASTFM_DLLEXPORT XmlQuery - { - QDomDocument domdoc; - QDomElement e; - - public: - /** we assume the bytearray is an XML document, this object will then - * represent the documentElement of that document, eg. if this is a - * Last.fm webservice response: - * - * XmlQuery xq = lastfm::ws::parse(response); - * qDebug() << xq["artist"].text() - * - * Notice the lfm node is not referenced, that is because it is the - * document-element of the XML document. - */ - XmlQuery( const QByteArray& ) throw( lastfm::ws::ParseError ); - - XmlQuery( const QDomElement& e, const char* name = "" ) : e( e ) - { - if (e.isNull()) qWarning() << "Expected node absent:" << name; - } - - /** Selects a DIRECT child element, you can specify attributes like so: - * - * e["element"]["element attribute=value"].text(); - */ - XmlQuery operator[]( const QString& name ) const; - QString text() const { return e.text(); } - QString attribute( const QString& name ) const{ return e.attribute( name ); } - - /** selects all children with specified name, recursively */ - QList children( const QString& named ) const; - - operator QDomElement() const { return e; } - }; -} - -inline QDebug operator<<( QDebug d, const lastfm::XmlQuery& xq ) -{ - QString s; - QTextStream t( &s, QIODevice::WriteOnly ); - QDomElement(xq).save( t, 2 ); - return d << s; -} - -#endif diff --git a/thirdparty/liblastfm2/src/core/misc.cpp b/thirdparty/liblastfm2/src/core/misc.cpp deleted file mode 100644 index 2f4a28424..000000000 --- a/thirdparty/liblastfm2/src/core/misc.cpp +++ /dev/null @@ -1,175 +0,0 @@ -/* - Copyright 2009 Last.fm Ltd. - - Primarily authored by Max Howell, Jono Cole and Doug Mansell - - This file is part of liblastfm. - - liblastfm is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - liblastfm is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with liblastfm. If not, see . -*/ -#include "misc.h" -#include -#ifdef WIN32 - #include -#endif -#ifdef Q_WS_MAC - #include -#endif - - -#ifdef Q_WS_MAC -QDir -lastfm::dir::bundle() -{ - // Trolltech provided example - CFURLRef appUrlRef = CFBundleCopyBundleURL( CFBundleGetMainBundle() ); - CFStringRef macPath = CFURLCopyFileSystemPath( appUrlRef, kCFURLPOSIXPathStyle ); - QString path = CFStringToQString( macPath ); - CFRelease(appUrlRef); - CFRelease(macPath); - return QDir( path ); -} -#endif - - -static QDir dataDotDot() -{ -#ifdef WIN32 - if ((QSysInfo::WindowsVersion & QSysInfo::WV_DOS_based) == 0) - { - // Use this for non-DOS-based Windowses - char path[MAX_PATH]; - HRESULT h = SHGetFolderPathA( NULL, - CSIDL_LOCAL_APPDATA | CSIDL_FLAG_CREATE, - NULL, - 0, - path ); - if (h == S_OK) - return QString::fromLocal8Bit( path ); - } - return QDir::home(); - -#elif defined(Q_WS_MAC) - return QDir::home().filePath( "Library/Application Support" ); - -#elif defined(Q_WS_X11) - return QDir::home().filePath( ".local/share" ); - -#else - return QDir::home(); -#endif -} - - -QDir -lastfm::dir::runtimeData() -{ - return dataDotDot().filePath( "Last.fm" ); -} - - -QDir -lastfm::dir::logs() -{ -#ifdef Q_WS_MAC - return QDir::home().filePath( "Library/Logs/Last.fm" ); -#else - return runtimeData(); -#endif -} - - -QDir -lastfm::dir::cache() -{ -#ifdef Q_WS_MAC - return QDir::home().filePath( "Library/Caches/Last.fm" ); -#else - return runtimeData().filePath( "cache" ); -#endif -} - - -#ifdef WIN32 -QDir -lastfm::dir::programFiles() -{ - char path[MAX_PATH]; - - // TODO: this call is dependant on a specific version of shell32.dll. - // Need to degrade gracefully. Need to bundle SHFolder.exe with installer - // and execute it on install for this to work on Win98. - HRESULT h = SHGetFolderPathA( NULL, - CSIDL_PROGRAM_FILES, - NULL, - 0, // current path - path ); - - if (h != S_OK) - { - qCritical() << "Couldn't get Program Files dir. Possibly Win9x?"; - return QDir(); - } - - return QString::fromLocal8Bit( path ); -} -#endif - -#ifdef Q_WS_MAC -CFStringRef -lastfm::QStringToCFString( const QString &s ) -{ - return CFStringCreateWithCharacters( 0, (UniChar*)s.unicode(), s.length() ); -} - -QByteArray -lastfm::CFStringToUtf8( CFStringRef s ) -{ - QByteArray result; - - if (s != NULL) - { - CFIndex length; - length = CFStringGetLength( s ); - length = CFStringGetMaximumSizeForEncoding( length, kCFStringEncodingUTF8 ) + 1; - char* buffer = new char[length]; - - if (CFStringGetCString( s, buffer, length, kCFStringEncodingUTF8 )) - result = QByteArray( buffer ); - else - qWarning() << "CFString conversion failed."; - - delete[] buffer; - } - - return result; -} -#endif - -#if 0 -// this is a Qt implementation I found -QString cfstring2qstring(CFStringRef str) -{ - if(!str) - return QString(); - - CFIndex length = CFStringGetLength(str); - if(const UniChar *chars = CFStringGetCharactersPtr(str)) - return QString((QChar *)chars, length); - UniChar *buffer = (UniChar*)malloc(length * sizeof(UniChar)); - CFStringGetCharacters(str, CFRangeMake(0, length), buffer); - QString ret((QChar *)buffer, length); - free(buffer); - return ret; -} -#endif diff --git a/thirdparty/liblastfm2/src/core/misc.h b/thirdparty/liblastfm2/src/core/misc.h deleted file mode 100644 index 3f41ec534..000000000 --- a/thirdparty/liblastfm2/src/core/misc.h +++ /dev/null @@ -1,111 +0,0 @@ -/* - Copyright 2009 Last.fm Ltd. - - Primarily authored by Max Howell, Jono Cole and Doug Mansell - - This file is part of liblastfm. - - liblastfm is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - liblastfm is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with liblastfm. If not, see . -*/ -#ifndef LASTFM_MISC_H -#define LASTFM_MISC_H - -#include -#include -#include -#include - -#ifdef Q_WS_MAC -typedef const struct __CFString* CFStringRef; -#endif - -namespace lastfm -{ - namespace dir - { - #ifdef Q_WS_WIN - LASTFM_DLLEXPORT QDir programFiles(); - #endif - #ifdef Q_WS_MAC - LASTFM_DLLEXPORT QDir bundle(); - #endif - LASTFM_DLLEXPORT QDir runtimeData(); - LASTFM_DLLEXPORT QDir cache(); - LASTFM_DLLEXPORT QDir logs(); - } - -#ifdef Q_WS_MAC - LASTFM_DLLEXPORT QByteArray CFStringToUtf8( CFStringRef ); - LASTFM_DLLEXPORT CFStringRef QStringToCFString( const QString& ); - inline QString CFStringToQString( CFStringRef s ); -#endif - - inline const char* platform() - { - #ifdef Q_WS_WIN - switch (QSysInfo::WindowsVersion) - { - case QSysInfo::WV_32s: return "Windows 3.1 with Win32s"; - case QSysInfo::WV_95: return "Windows 95"; - case QSysInfo::WV_98: return "Windows 98"; - case QSysInfo::WV_Me: return "Windows Me"; - case QSysInfo::WV_DOS_based: return "MS-DOS-based Windows"; - - case QSysInfo::WV_NT: return "Windows NT"; - case QSysInfo::WV_2000: return "Windows 2000"; - case QSysInfo::WV_XP: return "Windows XP"; - case QSysInfo::WV_2003: return "Windows Server 2003"; - case QSysInfo::WV_VISTA: return "Windows Vista"; - case QSysInfo::WV_NT_based: return "NT-based Windows"; - - case QSysInfo::WV_CE: return "Windows CE"; - case QSysInfo::WV_CENET: return "Windows CE.NET"; - case QSysInfo::WV_CE_based: return "CE-based Windows"; - - default: return "Unknown"; - } - #elif defined Q_WS_MAC - switch (QSysInfo::MacintoshVersion) - { - case QSysInfo::MV_Unknown: return "Unknown Mac"; - case QSysInfo::MV_9: return "Mac OS 9"; - case QSysInfo::MV_10_0: return "Mac OS X 10.0"; - case QSysInfo::MV_10_1: return "Mac OS X 10.1"; - case QSysInfo::MV_10_2: return "Mac OS X 10.2"; - case QSysInfo::MV_10_3: return "Mac OS X 10.3"; - case QSysInfo::MV_10_4: return "Mac OS X 10.4"; - case QSysInfo::MV_10_5: return "Mac OS X 10.5"; - - default: return "Unknown"; - } - #elif defined Q_WS_X11 - return "UNIX X11"; - #else - return "Unknown"; - #endif - } - - inline QString md5( const QByteArray& src ) - { - QByteArray const digest = QCryptographicHash::hash( src, QCryptographicHash::Md5 ); - return QString::fromLatin1( digest.toHex() ).rightJustified( 32, '0' ).toLower(); - } -} - -#ifdef Q_WS_MAC -inline QString lastfm::CFStringToQString( CFStringRef s ) -{ - return QString::fromUtf8( CFStringToUtf8( s ) ); -} -#endif -#endif //LASTFM_MISC_H diff --git a/thirdparty/liblastfm2/src/fingerprint/CMakeLists.txt b/thirdparty/liblastfm2/src/fingerprint/CMakeLists.txt deleted file mode 100644 index eae8397a8..000000000 --- a/thirdparty/liblastfm2/src/fingerprint/CMakeLists.txt +++ /dev/null @@ -1,32 +0,0 @@ -cmake_minimum_required(VERSION 2.6) - -include_directories(${LIBFFTW3_INCLUDE_DIRS}) -include_directories(${LIBSAMPLERATE_INCLUDE_DIRS}) -include_directories(${QT_INCLUDES}) -include_directories(${CMAKE_CURRENT_BINARY_DIR}/..) - -link_directories(${LIBFFTW3_LIBRARY_DIRS}) -link_directories(${LIBSAMPLERATE_LIBRARY_DIRS}) - -set(SOURCES - Collection.cpp - Fingerprint.cpp - Sha256.cpp - fplib/Filter.cpp - fplib/FingerprintExtractor.cpp - fplib/OptFFT.cpp -) - -add_library(tomahawk_lastfm2_fingerprint SHARED - ${SOURCES} -) - -target_link_libraries(tomahawk_lastfm2_fingerprint - ${QT_LIBRARIES} - ${QT_QTSQL_LIBRARY} - ${LIBFFTW3_LIBRARY} - ${LIBSAMPLERATE_LIBRARY} - tomahawk_lastfm2 -) - -set_target_properties(tomahawk_lastfm2_fingerprint PROPERTIES COMPILE_FLAGS "-DLASTFM_FINGERPRINT_OHAI_QMAKE" ) diff --git a/thirdparty/liblastfm2/src/fingerprint/Collection.cpp b/thirdparty/liblastfm2/src/fingerprint/Collection.cpp deleted file mode 100644 index 214e264e2..000000000 --- a/thirdparty/liblastfm2/src/fingerprint/Collection.cpp +++ /dev/null @@ -1,267 +0,0 @@ -/* - Copyright 2009 Last.fm Ltd. - - Primarily authored by Max Howell, Jono Cole and Doug Mansell - - This file is part of liblastfm. - - liblastfm is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - liblastfm is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with liblastfm. If not, see . -*/ - -#include "Collection.h" -#include "../core/misc.h" -#include -#include -#include -#include -#include -#include -#include - -static const int k_collectionDbVersion = 1; - -// Singleton instance needs to be initialised -Collection* Collection::s_instance = NULL; - - -Collection::Collection() -{ - m_db = QSqlDatabase::addDatabase( "QSQLITE", "collection" ); - m_db.setDatabaseName( lastfm::dir::runtimeData().filePath( "collection.db" ) ); - - if (!m_db.open()) { - qDebug() << m_db.lastError(); - return; - } - - if (!m_db.isValid()) { - qWarning() << "collection.db connection is not valid"; - return; - } - - if (!m_db.tables().contains( "files" )) - { - qDebug() << "Creating Collection database"; - - query( "CREATE TABLE artists (" - "id INTEGER PRIMARY KEY AUTOINCREMENT," - "serverUid INTEGER," - "lcName TEXT NOT NULL," - "displayName TEXT NOT NULL );" ); - - query( "CREATE TABLE albums (" - "id INTEGER PRIMARY KEY AUTOINCREMENT," - "serverUid INTEGER," - "lcName TEXT NOT NULL," - "displayName TEXT NOT NULL," - "primaryArtist INTEGER NOT NULL );" ); - - query( "CREATE UNIQUE INDEX album_names_idx ON albums ( primaryArtist, lcName );" ); - - query( "CREATE TABLE tracks (" - "id INTEGER PRIMARY KEY AUTOINCREMENT," - "lcName TEXT NOT NULL," - "displayName TEXT NOT NULL," - "primaryArtist INTEGER NOT NULL," - "primaryAlbum INTEGER );" ); - - query( "CREATE UNIQUE INDEX track_names_idx ON tracks ( primaryArtist, lcName );" ); - - query( "CREATE TABLE files (" - "id INTEGER PRIMARY KEY AUTOINCREMENT," - "uri TEXT NOT NULL," - "track INTEGER NOT NULL," - "bitrate INTEGER," - "samplerate INTEGER," - "duration INTEGER," - "filesize INTEGER," - "source INTEGER," - "modificationDate INTEGER," - "lastPlayDate INTEGER," - "playCounter INTEGER," - "mbId VARCHAR( 36 )," - "fpId INTEGER );" ); - - query( "CREATE UNIQUE INDEX files_uri_idx ON files ( uri );" ); - query( "CREATE INDEX files_track_idx ON files ( track );" ); - query( "CREATE INDEX files_fpId_idx ON files ( fpId );" ); - query( "CREATE INDEX files_source_idx ON files ( source );" ); - - query( "CREATE TABLE sources (" - "id INTEGER PRIMARY KEY AUTOINCREMENT," - "name TEXT UNIQUE," - "available INTEGER," - "host TEXT," - "cost INTEGER );" ); - - query( "CREATE TABLE genres (" - "id INTEGER PRIMARY KEY AUTOINCREMENT," - "name TEXT UNIQUE );" ); - - query( "CREATE TABLE labels (" - "id INTEGER PRIMARY KEY AUTOINCREMENT," - "serverUid INTEGER UNIQUE," - "name TEXT );" ); - } - - int const v = version(); - if ( v < k_collectionDbVersion ) - { - qDebug() << "Upgrading Collection::db from" << v << "to" << k_collectionDbVersion; - - /********************************************** - * README!!!!!!! * - * Ensure you use v < x * - * Ensure you do upgrades in ascending order! * - **********************************************/ - - if ( v < 1 ) - { - // Norman discovered that he stored some fpId's wrong prior to 17th December 2007 - // So we have to wipe the fpIds for databases without the metadata table - // we didn't store version information before that, which was a bad decision wasn't it? - - // this will trigger refingerprinting of every track - query( "UPDATE files SET fpId = NULL;" ); - - query( "CREATE TABLE metadata (" - "key TEXT UNIQUE NOT NULL," - "value TEXT );" ); - - query( "INSERT INTO metadata (key, value) VALUES ('version', '1');" ); - } - - - // do last, update DB version number - query( "UPDATE metadata set key='version', value='" - + QString::number( k_collectionDbVersion ) + "';" ); - } -} - - -Collection& //static -Collection::instance() -{ - static QMutex mutex; - QMutexLocker locker( &mutex ); - - if ( !s_instance ) - { - s_instance = new Collection; - qAddPostRoutine(destroy); - } - - return *s_instance; -} - - -void //static -Collection::destroy() -{ - delete s_instance; - QSqlDatabase::removeDatabase( "collection" ); -} - - -int -Collection::version() const -{ - QSqlQuery sql( m_db ); - sql.exec( "SELECT value FROM metadata WHERE key='version';" ); - - if ( sql.next() ) - { - return sql.value( 0 ).toInt(); - } - - return 0; -} - - -bool -Collection::query( const QString& queryToken ) -{ - QSqlQuery query( m_db ); - query.exec( queryToken ); - - if ( query.lastError().isValid() ) - { - qDebug() << "SQL query failed:" << query.lastQuery() << endl - << "SQL error was:" << query.lastError().databaseText() << endl - << "SQL error type:" << query.lastError().type(); - - return false; - } - - return true; -} - - -QString -Collection::fileURI( const QString& filePath ) -{ - QString prefix( "file:/" ); - -#ifdef WIN32 - prefix = "file://"; -#endif - - return prefix + QFileInfo( filePath ).absoluteFilePath(); -} - - -QString -Collection::getFingerprintId( const QString& filePath ) -{ - QSqlQuery query( m_db ); - query.prepare( "SELECT fpId FROM files WHERE uri = :uri" ); - query.bindValue( ":uri", fileURI( filePath ) ); - - query.exec(); - if ( query.lastError().isValid() ) - { - qDebug() << "SQL query failed:" << query.lastQuery() << endl - << "SQL error was:" << query.lastError().databaseText() << endl - << "SQL error type:" << query.lastError().type(); - } - else if (query.next()) - return query.value( 0 ).toString(); - - return ""; -} - - -bool -Collection::setFingerprintId( const QString& filePath, QString fpId ) -{ - bool isNumeric; - int intFpId = fpId.toInt( &isNumeric ); - Q_ASSERT( isNumeric ); - - QSqlQuery query( m_db ); - query.prepare( "REPLACE INTO files ( uri, track, fpId ) VALUES ( :uri, 0, :fpId )" ); - query.bindValue( ":uri", fileURI( filePath ) ); - query.bindValue( ":fpId", intFpId ); - query.exec(); - - if ( query.lastError().isValid() ) - { - qDebug() << "SQL query failed:" << query.lastQuery() << endl - << "SQL error was:" << query.lastError().databaseText() << endl - << "SQL error type:" << query.lastError().type(); - - return false; - } - - return true; -} diff --git a/thirdparty/liblastfm2/src/fingerprint/Collection.h b/thirdparty/liblastfm2/src/fingerprint/Collection.h deleted file mode 100644 index 9a1f3bd17..000000000 --- a/thirdparty/liblastfm2/src/fingerprint/Collection.h +++ /dev/null @@ -1,59 +0,0 @@ -/* - Copyright 2009 Last.fm Ltd. - - Primarily authored by Max Howell, Jono Cole and Doug Mansell - - This file is part of liblastfm. - - liblastfm is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - liblastfm is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with liblastfm. If not, see . -*/ - -/** Class that we use to store fingerprints, basically - */ - -#ifndef COLLECTION_H -#define COLLECTION_H - -#include -#include - - -/** @author: */ -class Collection -{ -public: - static Collection& instance(); - - /** \brief Temp method: Gets a fingerprint id. Returns "" if none found. */ - QString getFingerprintId( const QString& filePath ); - - /** \brief Temp method: Sets a fingerprint id. */ - bool setFingerprintId( const QString& filePath, QString fpId ); - -private: - Collection(); - - /** the database version - * version 0: up until 1.4.1 - * version 1: from 1.4.2 */ - int version() const; - bool query( const QString& queryToken ); - QString fileURI( const QString& filePath ); - - static void destroy(); - - static Collection* s_instance; - QSqlDatabase m_db; -}; - -#endif // COLLECTION_H diff --git a/thirdparty/liblastfm2/src/fingerprint/EXAMPLE.cpp b/thirdparty/liblastfm2/src/fingerprint/EXAMPLE.cpp deleted file mode 100644 index f86d4bbaf..000000000 --- a/thirdparty/liblastfm2/src/fingerprint/EXAMPLE.cpp +++ /dev/null @@ -1,76 +0,0 @@ -/* - Copyright 2009 Last.fm Ltd. - - Primarily authored by Max Howell, Jono Cole and Doug Mansell - - This file is part of liblastfm. - - liblastfm is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - liblastfm is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with liblastfm. If not, see . -*/ -#include -#include -#include -#include - -using namespace lastfm; - - -static void finish( QNetworkReply* reply ) -{ - QEventLoop loop; - loop.connect( reply, SIGNAL(finished()), SLOT(quit()) ); - loop.exec(); -} - - -int main( int argc, char** argv ) -{ - QCoreApplication app( argc, argv ); - - // these fields are required - MutableTrack t; - t.setArtist( "Air" ); - t.setTitle( "Redhead Girl" ); - t.setAlbum( "Pocket Symphony" ); - t.setUrl( QUrl::fromLocalFile( "/Users/mxcl/Music/iTunes/iTunes Music/Air/Pocket Symphony/1-11 Redhead Girl.mp3") ); - - try - { - Fingerprint fp( t ); - - // we cache FingerprintIds in an sqlite3 db, as the generate() function - // is expensive - if (fp.id().isNull()) - { - // this generates the full fingerprint hash, which is about 20kB - fp.generate(); - - // this asks Last.fm for a FingerprintId - // the finish function is a Qt hack to allow syncronous HTTP - finish( fp.submit() ); - - // the decode step sets the FingerprintId - // the FingerprintId is required to obtain suggestions - // id will now be valid, or this function throws - fp.decode( reply ); - } - - finish( fp.id().getSuggestions() ); - - qDebug() << FingerprintId::getSuggestions( reply ); - } - catch (Fingerprint::Error e) - { - qWarning() << e; //TODO enum debug thing - } -} diff --git a/thirdparty/liblastfm2/src/fingerprint/Fingerprint.cpp b/thirdparty/liblastfm2/src/fingerprint/Fingerprint.cpp deleted file mode 100644 index b23805c7d..000000000 --- a/thirdparty/liblastfm2/src/fingerprint/Fingerprint.cpp +++ /dev/null @@ -1,300 +0,0 @@ -/* - Copyright 2009 Last.fm Ltd. - - Primarily authored by Max Howell, Jono Cole and Doug Mansell - - This file is part of liblastfm. - - liblastfm is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - liblastfm is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with liblastfm. If not, see . -*/ - -#include "Fingerprint.h" -#include "FingerprintableSource.h" -#include "Collection.h" -#include "Sha256.h" -#include "fplib/FingerprintExtractor.h" -#include "../ws/ws.h" -#include -#include -#include -#include -#include -#include - -using lastfm::Track; - -static const uint k_bufferSize = 1024 * 8; -static const int k_minTrackDuration = 30; - - -lastfm::Fingerprint::Fingerprint( const Track& t ) - : m_track( t ) - , m_id( -1 ), m_duration( 0 ) - , m_complete( false ) -{ - QString id = Collection::instance().getFingerprintId( t.url().toLocalFile() ); - if (id.size()) { - bool b; - m_id = id.toInt( &b ); - if (!b) m_id = -1; - } -} - - -void -lastfm::Fingerprint::generate( FingerprintableSource* ms ) throw( Error ) -{ - //TODO throw if we can't get required metadata from the track object - -//TODO if (!QFileInfo( path ).isReadable()) -//TODO throw ReadError; - - int sampleRate, bitrate, numChannels; - - if ( !ms ) - throw ReadError; - - try - { - ms->init( m_track.url().toLocalFile() ); - ms->getInfo( m_duration, sampleRate, bitrate, numChannels ); - } - catch (std::exception& e) - { - qWarning() << e.what(); - throw HeadersError; - } - - - if (m_duration < k_minTrackDuration) - throw TrackTooShortError; - - ms->skipSilence(); - - bool fpDone = false; - fingerprint::FingerprintExtractor* extractor; - try - { - extractor = new fingerprint::FingerprintExtractor; - - if (m_complete) - { - extractor->initForFullSubmit( sampleRate, numChannels ); - } - else - { - extractor->initForQuery( sampleRate, numChannels, m_duration ); - - // Skippety skip for as long as the skipper sez (optimisation) - ms->skip( extractor->getToSkipMs() ); - float secsToSkip = extractor->getToSkipMs() / 1000.0f; - fpDone = extractor->process( 0, - (size_t) sampleRate * numChannels * secsToSkip, - false ); - } - } - catch (std::exception& e) - { - qWarning() << e.what(); - throw DecodeError; - } - - const size_t PCMBufSize = 131072; - short* pPCMBuffer = new short[PCMBufSize]; - - while (!fpDone) - { - size_t readData = ms->updateBuffer( pPCMBuffer, PCMBufSize ); - if (readData == 0) - break; - - try - { - fpDone = extractor->process( pPCMBuffer, readData, ms->eof() ); - } - catch ( const std::exception& e ) - { - qWarning() << e.what(); - delete ms; - delete[] pPCMBuffer; - throw InternalError; - } - } - - delete[] pPCMBuffer; - - if (!fpDone) - throw InternalError; - - // We succeeded - std::pair fpData = extractor->getFingerprint(); - - if (fpData.first == NULL || fpData.second == 0) - throw InternalError; - - // Make a deep copy before extractor gets deleted - m_data = QByteArray( fpData.first, fpData.second ); - delete extractor; -} - - -static QString sha256( const QString& path ) -{ - // no clue why this is static, there was no comment when I refactored it - // initially --mxcl - static uint8_t pBuffer[SHA_BUFFER_SIZE+7]; - - unsigned char hash[SHA256_HASH_SIZE]; - - { - QByteArray path8 = QFile::encodeName( path ); - std::ifstream inFile( path8.data(), std::ios::binary); - - SHA256Context sha256; - SHA256Init( &sha256 ); - - uint8_t* pMovableBuffer = pBuffer; - - // Ensure it is on a 64-bit boundary. - INTPTR offs; - if ((offs = reinterpret_cast(pBuffer) & 7L)) - pMovableBuffer += 8 - offs; - - unsigned int len; - - for (;;) - { - inFile.read( reinterpret_cast(pMovableBuffer), SHA_BUFFER_SIZE ); - len = inFile.gcount(); - - if (len == 0) - break; - - SHA256Update( &sha256, pMovableBuffer, len ); - } - - SHA256Final( &sha256, hash ); - } - - QString sha; - for (int i = 0; i < SHA256_HASH_SIZE; ++i) - { - QString hex = QString("%1").arg(uchar(hash[i]), 2, 16, - QChar('0')); - sha.append(hex); - } - - return sha; -} - - -static QByteArray number( uint n ) -{ - return n ? QByteArray::number( n ) : ""; -} - -QNetworkReply* -lastfm::Fingerprint::submit() const -{ - if (m_data.isEmpty()) - return 0; - - //Parameters understood by the server according to the MIR team: - //{ "trackid", "recordingid", "artist", "album", "track", "duration", - // "tracknum", "username", "sha256", "ip", "fpversion", "mbid", - // "filename", "genre", "year", "samplerate", "noupdate", "fulldump" } - - Track const t = m_track; - QString const path = t.url().toLocalFile(); - QFileInfo const fi( path ); - - #define e( x ) QUrl::toPercentEncoding( x ) - QUrl url( "http://www.last.fm/fingerprint/query/" ); - url.addEncodedQueryItem( "artist", e(t.artist()) ); - url.addEncodedQueryItem( "album", e(t.album()) ); - url.addEncodedQueryItem( "track", e(t.title()) ); - url.addEncodedQueryItem( "duration", number( m_duration > 0 ? m_duration : t.duration() ) ); - url.addEncodedQueryItem( "mbid", e(t.mbid()) ); - url.addEncodedQueryItem( "filename", e(fi.completeBaseName()) ); - url.addEncodedQueryItem( "fileextension", e(fi.completeSuffix()) ); - url.addEncodedQueryItem( "tracknum", number( t.trackNumber() ) ); - url.addEncodedQueryItem( "sha256", sha256( path ).toAscii() ); - url.addEncodedQueryItem( "time", number(QDateTime::currentDateTime().toTime_t()) ); - url.addEncodedQueryItem( "fpversion", QByteArray::number((int)fingerprint::FingerprintExtractor::getVersion()) ); - url.addEncodedQueryItem( "fulldump", m_complete ? "true" : "false" ); - url.addEncodedQueryItem( "noupdate", "false" ); - #undef e - - //FIXME: talk to mir about submitting fplibversion - - QNetworkRequest request( url ); - request.setHeader( QNetworkRequest::ContentTypeHeader, "multipart/form-data; boundary=----------------------------8e61d618ca16" ); - - QByteArray bytes; - bytes += "------------------------------8e61d618ca16\r\n"; - bytes += "Content-Disposition: "; - bytes += "form-data; name=\"fpdata\""; - bytes += "\r\n\r\n"; - bytes += m_data; - bytes += "\r\n"; - bytes += "------------------------------8e61d618ca16--\r\n"; - - qDebug() << url; - qDebug() << "Fingerprint size:" << bytes.size() << "bytes"; - - return lastfm::nam()->post( request, bytes ); -} - - -void -lastfm::Fingerprint::decode( QNetworkReply* reply, bool* complete_fingerprint_requested ) throw( Error ) -{ - // The response data will consist of a number and a string. - // The number is the fpid and the string is either FOUND or NEW - // (or NOT FOUND when noupdate was used). NEW means we should - // schedule a full fingerprint. - // - // In the case of an error, there will be no initial number, just - // an error string. - - QString const response( reply->readAll() ); - QStringList const list = response.split( ' ' ); - - QString const fpid = list.value( 0 ); - QString const status = list.value( 1 ); - - if (response.isEmpty() || list.count() < 2 || response == "No response to client error") - goto bad_response; - if (list.count() != 2) - qWarning() << "Response looks bad but continuing anyway:" << response; - - { - // so variables go out of scope before jump to label - // otherwise compiler error on GCC 4.2 - bool b; - uint fpid_as_uint = fpid.toUInt( &b ); - if (!b) goto bad_response; - - Collection::instance().setFingerprintId( m_track.url().toLocalFile(), fpid ); - - if (complete_fingerprint_requested) - *complete_fingerprint_requested = (status == "NEW"); - - m_id = (int)fpid_as_uint; - return; - } - -bad_response: - qWarning() << "Response is bad:" << response; - throw BadResponseError; -} diff --git a/thirdparty/liblastfm2/src/fingerprint/Fingerprint.h b/thirdparty/liblastfm2/src/fingerprint/Fingerprint.h deleted file mode 100644 index b793c4bb9..000000000 --- a/thirdparty/liblastfm2/src/fingerprint/Fingerprint.h +++ /dev/null @@ -1,116 +0,0 @@ -/* - Copyright 2009 Last.fm Ltd. - - Primarily authored by Max Howell, Jono Cole and Doug Mansell - - This file is part of liblastfm. - - liblastfm is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - liblastfm is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with liblastfm. If not, see . -*/ -#ifndef LASTFM_FINGERPRINT_H -#define LASTFM_FINGERPRINT_H - -#include -#include - - -namespace lastfm -{ - class LASTFM_FINGERPRINT_DLLEXPORT Fingerprint - { - lastfm::Track m_track; - QByteArray m_data; - int m_id; - int m_duration; - - protected: - bool m_complete; - - public: - /** represents a partial fingerprint of 20 seconds of music, this is - * considered 99.9999...9999% unique and so we use it for most stuff as - * it is much quicker than a complete fingerprint, still though, you - * should do the generate step in a thread. */ - Fingerprint( const lastfm::Track& ); - - /** if the id isNull(), then you'll need to do generate, submit and decode */ - FingerprintId id() const { return m_id; } - - /** The actual data that is the fingerprint, this is about 70kB or so, - * there isn't anything in it until you call generate. */ - QByteArray data() const { return m_data; } - - enum Error - { - ReadError = 0, - - /** failed to extract samplerate, bitrate, channels, duration etc */ - HeadersError, - - DecodeError, - - /** there is a minimum track duration for fingerprinting */ - TrackTooShortError, - - /** the fingerprint service went wrong, or we submitted bad data, - * or myabe the request failed, whatever, we couldn't parse the - * result */ - BadResponseError, - - /** sorry, liblastfm sucks, report bug with log! */ - InternalError - }; - - /** This is CPU intensive, do it in a thread in your GUI application */ - void generate( FingerprintableSource* ) throw( Error ); - - /** Submits the fingerprint data to Last.fm in order to get a FingerprintId - * back. You need to wait for the QNetworkReply to finish before you can - * pass it to decode clearly. */ - QNetworkReply* submit() const; - - /** Pass a finished reply from submit(), if the response is sound, id() - * will be valid. Otherwise we will throw. You always get a valid id - * or a throw. - */ - void decode( QNetworkReply*, bool* lastfm_needs_a_complete_fingerprint = 0 ) throw( Error ); - }; - - - class CompleteFingerprint : public Fingerprint - { - public: - CompleteFingerprint( const lastfm::Track& t ) : Fingerprint( t ) - { - m_complete = true; - } - }; -} - - -inline QDebug operator<<( QDebug d, lastfm::Fingerprint::Error e ) -{ - #define CASE(x) case lastfm::Fingerprint::x: return d << #x; - switch (e) - { - CASE(ReadError) - CASE(HeadersError) - CASE(DecodeError) - CASE(TrackTooShortError) - CASE(BadResponseError) - CASE(InternalError) - } - #undef CASE -} - -#endif diff --git a/thirdparty/liblastfm2/src/fingerprint/FingerprintableSource.h b/thirdparty/liblastfm2/src/fingerprint/FingerprintableSource.h deleted file mode 100644 index 9954fd368..000000000 --- a/thirdparty/liblastfm2/src/fingerprint/FingerprintableSource.h +++ /dev/null @@ -1,48 +0,0 @@ -/* - Copyright 2009 Last.fm Ltd. - Copyright 2009 John Stamp - - This file is part of liblastfm. - - liblastfm is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - liblastfm is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with liblastfm. If not, see . -*/ - -#ifndef LASTFM_FINGERPRINTABLE_SOURCE_H -#define LASTFM_FINGERPRINTABLE_SOURCE_H - -#include -#include - -namespace lastfm -{ - class LASTFM_FINGERPRINT_DLLEXPORT FingerprintableSource - { - public: - /** do all initialisation here and throw if there is problems */ - virtual void init( const QString& path ) = 0; - - virtual void getInfo( int& lengthSecs, int& samplerate, int& bitrate, int& nchannels ) = 0; - - /** put a chunk of PCM data in pBuffer, don't exceed size, return the - * number of bytes you put in the buffer */ - virtual int updateBuffer( signed short* buffer, size_t bufferSize ) = 0; - - virtual void skip( const int mSecs ) = 0; - virtual void skipSilence( double silenceThreshold = 0.0001 ) = 0; - - virtual bool eof() const = 0; - }; -} - -#endif diff --git a/thirdparty/liblastfm2/src/fingerprint/Sha256.cpp b/thirdparty/liblastfm2/src/fingerprint/Sha256.cpp deleted file mode 100644 index 9be3c18ac..000000000 --- a/thirdparty/liblastfm2/src/fingerprint/Sha256.cpp +++ /dev/null @@ -1,480 +0,0 @@ -/*- - * Copyright (c) 2001-2003 Allan Saddi - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY ALLAN SADDI AND HIS CONTRIBUTORS ``AS IS'' - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL ALLAN SADDI OR HIS CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * $Id: sha256.c 680 2003-07-25 21:57:49Z asaddi $ - */ - -/* - * Define WORDS_BIGENDIAN if compiling on a big-endian architecture. - * - * Define SHA256_TEST to test the implementation using the NIST's - * sample messages. The output should be: - * - * ba7816bf 8f01cfea 414140de 5dae2223 b00361a3 96177a9c b410ff61 f20015ad - * 248d6a61 d20638b8 e5c02693 0c3e6039 a33ce459 64ff2167 f6ecedd4 19db06c1 - * cdc76e5c 9914fb92 81a1c7e2 84d73e67 f1809a48 a497200e 046d39cc c7112cd0 - */ - -#ifdef HAVE_CONFIG_H -#include -#endif /* HAVE_CONFIG_H */ - -#if HAVE_INTTYPES_H -# include -#else -# if HAVE_STDINT_H -# include -# endif -#endif - -#include - -#include "Sha256.h" - -#ifndef lint -static const char rcsid[] = - "$Id: sha256.c 680 2003-07-25 21:57:49Z asaddi $"; -#endif /* !lint */ - -#define ROTL(x, n) (((x) << (n)) | ((x) >> (32 - (n)))) -#define ROTR(x, n) (((x) >> (n)) | ((x) << (32 - (n)))) - -#define Ch(x, y, z) ((z) ^ ((x) & ((y) ^ (z)))) -#define Maj(x, y, z) (((x) & ((y) | (z))) | ((y) & (z))) -#define SIGMA0(x) (ROTR((x), 2) ^ ROTR((x), 13) ^ ROTR((x), 22)) -#define SIGMA1(x) (ROTR((x), 6) ^ ROTR((x), 11) ^ ROTR((x), 25)) -#define sigma0(x) (ROTR((x), 7) ^ ROTR((x), 18) ^ ((x) >> 3)) -#define sigma1(x) (ROTR((x), 17) ^ ROTR((x), 19) ^ ((x) >> 10)) - -#define DO_ROUND() { \ - t1 = h + SIGMA1(e) + Ch(e, f, g) + *(Kp++) + *(W++); \ - t2 = SIGMA0(a) + Maj(a, b, c); \ - h = g; \ - g = f; \ - f = e; \ - e = d + t1; \ - d = c; \ - c = b; \ - b = a; \ - a = t1 + t2; \ -} - -static const uint32_t K[64] = { - 0x428a2f98L, 0x71374491L, 0xb5c0fbcfL, 0xe9b5dba5L, - 0x3956c25bL, 0x59f111f1L, 0x923f82a4L, 0xab1c5ed5L, - 0xd807aa98L, 0x12835b01L, 0x243185beL, 0x550c7dc3L, - 0x72be5d74L, 0x80deb1feL, 0x9bdc06a7L, 0xc19bf174L, - 0xe49b69c1L, 0xefbe4786L, 0x0fc19dc6L, 0x240ca1ccL, - 0x2de92c6fL, 0x4a7484aaL, 0x5cb0a9dcL, 0x76f988daL, - 0x983e5152L, 0xa831c66dL, 0xb00327c8L, 0xbf597fc7L, - 0xc6e00bf3L, 0xd5a79147L, 0x06ca6351L, 0x14292967L, - 0x27b70a85L, 0x2e1b2138L, 0x4d2c6dfcL, 0x53380d13L, - 0x650a7354L, 0x766a0abbL, 0x81c2c92eL, 0x92722c85L, - 0xa2bfe8a1L, 0xa81a664bL, 0xc24b8b70L, 0xc76c51a3L, - 0xd192e819L, 0xd6990624L, 0xf40e3585L, 0x106aa070L, - 0x19a4c116L, 0x1e376c08L, 0x2748774cL, 0x34b0bcb5L, - 0x391c0cb3L, 0x4ed8aa4aL, 0x5b9cca4fL, 0x682e6ff3L, - 0x748f82eeL, 0x78a5636fL, 0x84c87814L, 0x8cc70208L, - 0x90befffaL, 0xa4506cebL, 0xbef9a3f7L, 0xc67178f2L -}; - -#ifndef RUNTIME_ENDIAN - -#ifdef WORDS_BIGENDIAN - -#define BYTESWAP(x) (x) -#define BYTESWAP64(x) (x) - -#else /* WORDS_BIGENDIAN */ - -#define BYTESWAP(x) ((ROTR((x), 8) & 0xff00ff00L) | \ - (ROTL((x), 8) & 0x00ff00ffL)) -#define BYTESWAP64(x) _byteswap64(x) - -static inline uint64_t _byteswap64(uint64_t x) -{ - uint32_t a = x >> 32; - uint32_t b = (uint32_t) x; - return ((uint64_t) BYTESWAP(b) << 32) | (uint64_t) BYTESWAP(a); -} - -#endif /* WORDS_BIGENDIAN */ - -#else /* !RUNTIME_ENDIAN */ - -#define BYTESWAP(x) _byteswap(sc->littleEndian, x) -#define BYTESWAP64(x) _byteswap64(sc->littleEndian, x) - -#define _BYTESWAP(x) ((ROTR((x), 8) & 0xff00ff00L) | \ - (ROTL((x), 8) & 0x00ff00ffL)) -#define _BYTESWAP64(x) __byteswap64(x) - -static inline uint64_t __byteswap64(uint64_t x) -{ - uint32_t a = x >> 32; - uint32_t b = (uint32_t) x; - return ((uint64_t) _BYTESWAP(b) << 32) | (uint64_t) _BYTESWAP(a); -} - -static inline uint32_t _byteswap(int littleEndian, uint32_t x) -{ - if (!littleEndian) - return x; - else - return _BYTESWAP(x); -} - -static inline uint64_t _byteswap64(int littleEndian, uint64_t x) -{ - if (!littleEndian) - return x; - else - return _BYTESWAP64(x); -} - -static inline void setEndian(int *littleEndianp) -{ - union { - uint32_t w; - uint8_t b[4]; - } endian; - - endian.w = 1L; - *littleEndianp = endian.b[0] != 0; -} - -#endif /* !RUNTIME_ENDIAN */ - -static const uint8_t padding[64] = { - 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 -}; - -void -SHA256Init (SHA256Context *sc) -{ -#ifdef RUNTIME_ENDIAN - setEndian (&sc->littleEndian); -#endif /* RUNTIME_ENDIAN */ - - sc->totalLength = 0LL; - sc->hash[0] = 0x6a09e667L; - sc->hash[1] = 0xbb67ae85L; - sc->hash[2] = 0x3c6ef372L; - sc->hash[3] = 0xa54ff53aL; - sc->hash[4] = 0x510e527fL; - sc->hash[5] = 0x9b05688cL; - sc->hash[6] = 0x1f83d9abL; - sc->hash[7] = 0x5be0cd19L; - sc->bufferLength = 0L; -} - -static void -burnStack (int size) -{ - char buf[128]; - - memset (buf, 0, sizeof (buf)); - size -= sizeof (buf); - if (size > 0) - burnStack (size); -} - -static void -SHA256Guts (SHA256Context *sc, const uint32_t *cbuf) -{ - uint32_t buf[64]; - uint32_t *W, *W2, *W7, *W15, *W16; - uint32_t a, b, c, d, e, f, g, h; - uint32_t t1, t2; - const uint32_t *Kp; - int i; - - W = buf; - - for (i = 15; i >= 0; i--) { - *(W++) = BYTESWAP(*cbuf); - cbuf++; - } - - W16 = &buf[0]; - W15 = &buf[1]; - W7 = &buf[9]; - W2 = &buf[14]; - - for (i = 47; i >= 0; i--) { - *(W++) = sigma1(*W2) + *(W7++) + sigma0(*W15) + *(W16++); - W2++; - W15++; - } - - a = sc->hash[0]; - b = sc->hash[1]; - c = sc->hash[2]; - d = sc->hash[3]; - e = sc->hash[4]; - f = sc->hash[5]; - g = sc->hash[6]; - h = sc->hash[7]; - - Kp = K; - W = buf; - -#ifndef SHA256_UNROLL -#define SHA256_UNROLL 1 -#endif /* !SHA256_UNROLL */ - -#if SHA256_UNROLL == 1 - for (i = 63; i >= 0; i--) - DO_ROUND(); -#elif SHA256_UNROLL == 2 - for (i = 31; i >= 0; i--) { - DO_ROUND(); DO_ROUND(); - } -#elif SHA256_UNROLL == 4 - for (i = 15; i >= 0; i--) { - DO_ROUND(); DO_ROUND(); DO_ROUND(); DO_ROUND(); - } -#elif SHA256_UNROLL == 8 - for (i = 7; i >= 0; i--) { - DO_ROUND(); DO_ROUND(); DO_ROUND(); DO_ROUND(); - DO_ROUND(); DO_ROUND(); DO_ROUND(); DO_ROUND(); - } -#elif SHA256_UNROLL == 16 - for (i = 3; i >= 0; i--) { - DO_ROUND(); DO_ROUND(); DO_ROUND(); DO_ROUND(); - DO_ROUND(); DO_ROUND(); DO_ROUND(); DO_ROUND(); - DO_ROUND(); DO_ROUND(); DO_ROUND(); DO_ROUND(); - DO_ROUND(); DO_ROUND(); DO_ROUND(); DO_ROUND(); - } -#elif SHA256_UNROLL == 32 - for (i = 1; i >= 0; i--) { - DO_ROUND(); DO_ROUND(); DO_ROUND(); DO_ROUND(); - DO_ROUND(); DO_ROUND(); DO_ROUND(); DO_ROUND(); - DO_ROUND(); DO_ROUND(); DO_ROUND(); DO_ROUND(); - DO_ROUND(); DO_ROUND(); DO_ROUND(); DO_ROUND(); - DO_ROUND(); DO_ROUND(); DO_ROUND(); DO_ROUND(); - DO_ROUND(); DO_ROUND(); DO_ROUND(); DO_ROUND(); - DO_ROUND(); DO_ROUND(); DO_ROUND(); DO_ROUND(); - DO_ROUND(); DO_ROUND(); DO_ROUND(); DO_ROUND(); - } -#elif SHA256_UNROLL == 64 - DO_ROUND(); DO_ROUND(); DO_ROUND(); DO_ROUND(); - DO_ROUND(); DO_ROUND(); DO_ROUND(); DO_ROUND(); - DO_ROUND(); DO_ROUND(); DO_ROUND(); DO_ROUND(); - DO_ROUND(); DO_ROUND(); DO_ROUND(); DO_ROUND(); - DO_ROUND(); DO_ROUND(); DO_ROUND(); DO_ROUND(); - DO_ROUND(); DO_ROUND(); DO_ROUND(); DO_ROUND(); - DO_ROUND(); DO_ROUND(); DO_ROUND(); DO_ROUND(); - DO_ROUND(); DO_ROUND(); DO_ROUND(); DO_ROUND(); - DO_ROUND(); DO_ROUND(); DO_ROUND(); DO_ROUND(); - DO_ROUND(); DO_ROUND(); DO_ROUND(); DO_ROUND(); - DO_ROUND(); DO_ROUND(); DO_ROUND(); DO_ROUND(); - DO_ROUND(); DO_ROUND(); DO_ROUND(); DO_ROUND(); - DO_ROUND(); DO_ROUND(); DO_ROUND(); DO_ROUND(); - DO_ROUND(); DO_ROUND(); DO_ROUND(); DO_ROUND(); - DO_ROUND(); DO_ROUND(); DO_ROUND(); DO_ROUND(); - DO_ROUND(); DO_ROUND(); DO_ROUND(); DO_ROUND(); -#else -#error "SHA256_UNROLL must be 1, 2, 4, 8, 16, 32, or 64!" -#endif - - sc->hash[0] += a; - sc->hash[1] += b; - sc->hash[2] += c; - sc->hash[3] += d; - sc->hash[4] += e; - sc->hash[5] += f; - sc->hash[6] += g; - sc->hash[7] += h; -} - -void -SHA256Update (SHA256Context *sc, const void *vdata, uint32_t len) -{ - const uint8_t *data = (const uint8_t*)vdata; - uint32_t bufferBytesLeft; - uint32_t bytesToCopy; - int needBurn = 0; - -#ifdef SHA256_FAST_COPY - if (sc->bufferLength) { - bufferBytesLeft = 64L - sc->bufferLength; - - bytesToCopy = bufferBytesLeft; - if (bytesToCopy > len) - bytesToCopy = len; - - memcpy (&sc->buffer.bytes[sc->bufferLength], data, bytesToCopy); - - sc->totalLength += bytesToCopy * 8L; - - sc->bufferLength += bytesToCopy; - data += bytesToCopy; - len -= bytesToCopy; - - if (sc->bufferLength == 64L) { - SHA256Guts (sc, sc->buffer.words); - needBurn = 1; - sc->bufferLength = 0L; - } - } - - while (len > 63L) { - sc->totalLength += 512L; - - SHA256Guts (sc, data); - needBurn = 1; - - data += 64L; - len -= 64L; - } - - if (len) { - memcpy (&sc->buffer.bytes[sc->bufferLength], data, len); - - sc->totalLength += len * 8L; - - sc->bufferLength += len; - } -#else /* SHA256_FAST_COPY */ - while (len) { - bufferBytesLeft = 64L - sc->bufferLength; - - bytesToCopy = bufferBytesLeft; - if (bytesToCopy > len) - bytesToCopy = len; - - memcpy (&sc->buffer.bytes[sc->bufferLength], data, bytesToCopy); - - sc->totalLength += bytesToCopy * 8L; - - sc->bufferLength += bytesToCopy; - data += bytesToCopy; - len -= bytesToCopy; - - if (sc->bufferLength == 64L) { - SHA256Guts (sc, sc->buffer.words); - needBurn = 1; - sc->bufferLength = 0L; - } - } -#endif /* SHA256_FAST_COPY */ - - if (needBurn) - burnStack (sizeof (uint32_t[74]) + sizeof (uint32_t *[6]) + sizeof (int)); -} - -void -SHA256Final (SHA256Context *sc, uint8_t hash[SHA256_HASH_SIZE]) -{ - uint32_t bytesToPad; - uint64_t lengthPad; - int i; - - bytesToPad = 120L - sc->bufferLength; - if (bytesToPad > 64L) - bytesToPad -= 64L; - - lengthPad = BYTESWAP64(sc->totalLength); - - SHA256Update (sc, padding, bytesToPad); - SHA256Update (sc, &lengthPad, 8L); - - if (hash) { - for (i = 0; i < SHA256_HASH_WORDS; i++) { -#ifdef SHA256_FAST_COPY - *((uint32_t *) hash) = BYTESWAP(sc->hash[i]); -#else /* SHA256_FAST_COPY */ - hash[0] = (uint8_t) (sc->hash[i] >> 24); - hash[1] = (uint8_t) (sc->hash[i] >> 16); - hash[2] = (uint8_t) (sc->hash[i] >> 8); - hash[3] = (uint8_t) sc->hash[i]; -#endif /* SHA256_FAST_COPY */ - hash += 4; - } - } -} - -#ifdef SHA256_TEST - -#include -#include - -int -main (int argc, char *argv[]) -{ - SHA256Context foo; - uint8_t hash[SHA256_HASH_SIZE]; - char buf[1000]; - int i; - - SHA256Init (&foo); - SHA256Update (&foo, "abc", 3); - SHA256Final (&foo, hash); - - for (i = 0; i < SHA256_HASH_SIZE;) { - printf ("%02x", hash[i++]); - if (!(i % 4)) - printf (" "); - } - printf ("\n"); - - SHA256Init (&foo); - SHA256Update (&foo, - "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq", - 56); - SHA256Final (&foo, hash); - - for (i = 0; i < SHA256_HASH_SIZE;) { - printf ("%02x", hash[i++]); - if (!(i % 4)) - printf (" "); - } - printf ("\n"); - - SHA256Init (&foo); - memset (buf, 'a', sizeof (buf)); - for (i = 0; i < 1000; i++) - SHA256Update (&foo, buf, sizeof (buf)); - SHA256Final (&foo, hash); - - for (i = 0; i < SHA256_HASH_SIZE;) { - printf ("%02x", hash[i++]); - if (!(i % 4)) - printf (" "); - } - printf ("\n"); - - exit (0); -} - -#endif /* SHA256_TEST */ diff --git a/thirdparty/liblastfm2/src/fingerprint/Sha256.h b/thirdparty/liblastfm2/src/fingerprint/Sha256.h deleted file mode 100644 index 433c8f9a6..000000000 --- a/thirdparty/liblastfm2/src/fingerprint/Sha256.h +++ /dev/null @@ -1,180 +0,0 @@ -/*- - * Copyright (c) 2001-2003 Allan Saddi - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY ALLAN SADDI AND HIS CONTRIBUTORS ``AS IS'' - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL ALLAN SADDI OR HIS CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * $Id: sha256.h 348 2003-02-23 22:12:06Z asaddi $ - */ -// -/////////// EXAMPLE ///////////////////////////////// -// -// SHA256Context sha256; -// SHA256Init (&sha256); -// -// uint8_t* pBuffer = new uint8_t[SHA_BUFFER_SIZE + 7]; -// // Ensure it is on a 64-bit boundary. -// INTPTR offs; -// if ((offs = reinterpret_cast(pBuffer) & 7L)) -// pBuffer += 8 - offs; -// -// unsigned int len; -// -// ifstream inFile("test.txt", ios::binary); -// -// for (;;) -// { -// inFile.read( reinterpret_cast(pBuffer), SHA_BUFFER_SIZE ); -// len = inFile.gcount(); -// -// if ( len == 0) -// break; -// -// SHA256Update (&sha256, pBuffer, len); -// } -// -// uint8_t hash[SHA256_HASH_SIZE]; -// SHA256Final (&sha256, hash); -// -// cout << "Hash: "; -// for (int i = 0; i < SHA256_HASH_SIZE; ++i) -// printf ("%02x", hash[i]); -// cout << endl; - - -#ifndef _SHA256_H -#define _SHA256_H - -// ---------------------------------------------------------------------------- -// ---------------------------------------------------------------------------- - -/* Define to 1 if you have the header file. */ -#ifndef WIN32 -#define HAVE_INTTYPES_H 1 -#endif - -/* Define to 1 if you have the header file. */ -#define HAVE_MEMORY_H 1 - -/* Define to 1 if you have the header file. */ -#ifndef WIN32 -#define HAVE_STDINT_H 1 -#endif - -/* Define to 1 if you have the header file. */ -#define HAVE_STDLIB_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_STRINGS_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_STRING_H 1 - -/* Define to 1 if you have the `strerror' function. */ -#ifndef WIN32 -#define HAVE_STRERROR 1 -#endif - -/* Define to 1 if you have the header file. */ -#define HAVE_SYS_STAT_H 1 - -/* Define to 1 if you have the header file. */ -#ifndef WIN32 -#define HAVE_SYS_TYPES_H 1 -#endif - -/* Define to 1 if you have the header file. */ -#ifndef WIN32 -#define HAVE_UNISTD_H 1 -#endif - -/* Define to 1 if you have the ANSI C header files. */ -#define STDC_HEADERS 1 - -/* Define as `__inline' if that's what the C compiler calls it, or to nothing - if it is not supported. */ -#ifdef WIN32 -#define inline __inline -#endif - -/* Define to `unsigned' if does not define. */ -/* #undef size_t */ - -#ifdef WIN32 -#define uint64_t unsigned __int64 -#define uint32_t unsigned int -#define uint8_t unsigned char -#endif // WIN32 - -#ifdef WIN32 -#define INTPTR intptr_t -#else -#define INTPTR long -#endif - -#define SHA_BUFFER_SIZE 65536 - -// ---------------------------------------------------------------------------- -// ---------------------------------------------------------------------------- - - -#if HAVE_INTTYPES_H -# include -#else -# if HAVE_STDINT_H -# include -# endif -#endif - -#define SHA256_HASH_SIZE 32 - -/* Hash size in 32-bit words */ -#define SHA256_HASH_WORDS 8 - -struct _SHA256Context { - uint64_t totalLength; - uint32_t hash[SHA256_HASH_WORDS]; - uint32_t bufferLength; - union { - uint32_t words[16]; - uint8_t bytes[64]; - } buffer; -#ifdef RUNTIME_ENDIAN - int littleEndian; -#endif /* RUNTIME_ENDIAN */ -}; - -typedef struct _SHA256Context SHA256Context; - -#ifdef __cplusplus -extern "C" { -#endif - -void SHA256Init (SHA256Context *sc); -void SHA256Update (SHA256Context *sc, const void *data, uint32_t len); -void SHA256Final (SHA256Context *sc, uint8_t hash[SHA256_HASH_SIZE]); - -#ifdef __cplusplus -} -#endif - -#endif /* !_SHA256_H */ diff --git a/thirdparty/liblastfm2/src/fingerprint/contrib/AacSource.cpp b/thirdparty/liblastfm2/src/fingerprint/contrib/AacSource.cpp deleted file mode 100644 index 77bacd343..000000000 --- a/thirdparty/liblastfm2/src/fingerprint/contrib/AacSource.cpp +++ /dev/null @@ -1,953 +0,0 @@ -/* - Copyright 2009 Last.fm Ltd. - Copyright 2009 John Stamp - Portions Copyright 2003-2005 M. Bakker, Nero AG, http://www.nero.com - - Adapted from main.c found in the FAAD2 source tarball. - - This file is part of liblastfm. - - liblastfm is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - liblastfm is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with liblastfm. If not, see . -*/ -#include "AacSource.h" -#include "AacSource_p.h" - -#include -#include -#include -#include -#include -#include -#include -#include - - -//////////////////////////////////////////////////////////////////////// -// -// AAC_File -// -//////////////////////////////////////////////////////////////////////// -AAC_File::AAC_File(const QString& fileName, int headerType) - : m_fileName(fileName) - , m_inBuf(NULL) - , m_inBufSize(0) - , m_decoder(0) - , m_overflow(static_cast(malloc( sizeof(unsigned char) * 1024 ))) - , m_overflowSize(0) - , m_header(headerType) -{ -} - - -AAC_File::~AAC_File() -{ - // common - if ( m_decoder ) - { - NeAACDecClose( m_decoder ); - m_decoder = NULL; - } - if ( m_inBuf ) - { - free( m_inBuf ); - m_inBufSize = 0; - m_inBuf = NULL; - } - if ( m_overflow ) - { - free( m_overflow ); - m_overflowSize = 0; - m_overflow = NULL; - } -} - - - -//////////////////////////////////////////////////////////////////////// -// -// AAC with ADTS or ADIF headers -// -//////////////////////////////////////////////////////////////////////// - - -#define MAX_CHANNELS 6 // Output will get mixed down to 2 channels -#define ADTS_HEADER_SIZE 8 - -static int adts_sample_rates[] = -{ - 96000, - 88200, - 64000, - 48000, - 44100, - 32000, - 24000, - 22050, - 16000, - 12000, - 11025, - 8000, - 7350, - 0, - 0, - 0 -}; - -AAC_ADTS_File::AAC_ADTS_File( const QString& fileName, int headerType ) : AAC_File(fileName, headerType) - , m_file( NULL ) - , m_adifSamplerate( 0 ) - , m_adifChannels( 0 ) -{ -} - - -AAC_ADTS_File::~AAC_ADTS_File() -{ - if ( m_file ) - { - fclose( m_file ); - } -} - - -void AAC_ADTS_File::fillBuffer( FILE*& fp, unsigned char*& buf, size_t& bufSize, const size_t bytesConsumed ) -{ - size_t bread; - - if ( bytesConsumed > 0 ) - { - if ( bufSize ) - memmove( (void*)buf, (void*)(buf + bytesConsumed), bufSize*sizeof(unsigned char) ); - - bread = fread( (void*)(buf + bufSize), 1, bytesConsumed, fp ); - bufSize += bread; - - if ( bufSize > 3 ) - { - if ( memcmp( buf, "TAG", 3 ) == 0 ) - bufSize = 0; - } - if ( bufSize > 11 ) - { - if ( memcmp( buf, "LYRICSBEGIN", 11 ) == 0 ) - bufSize = 0; - } - if ( bufSize > 8 ) - { - if ( memcmp( buf, "APETAGEX", 8 ) == 0 ) - bufSize = 0; - } - } -} - - -void AAC_ADTS_File::parse( FILE*& fp, unsigned char*& buf, size_t& bufSize, int &bitrate, double &length ) -{ - unsigned int frames, frame_length = 0; - int t_framelength = 0; - int samplerate = 0; - double frames_per_sec, bytes_per_frame; - - // Read all frames to ensure correct time and bitrate - for ( frames = 0; /* */; frames++ ) - { - fillBuffer( fp, buf, bufSize, frame_length ); - - if ( bufSize > 7 ) - { - /* check syncword */ - if ( !( (buf[0] == 0xFF) && ((buf[1] & 0xF6) == 0xF0) ) ) - break; - - if ( frames == 0 ) - samplerate = adts_sample_rates[ (buf[2] & 0x3c) >> 2 ]; - - frame_length = ( ((buf[3] & 0x3) << 11) - | ((buf[4]) << 3) - | (buf[5] >> 5) ); - - t_framelength += frame_length - ADTS_HEADER_SIZE; - - if ( frame_length > bufSize ) - break; - - bufSize -= frame_length; - } - else - { - break; - } - } - - frames_per_sec = samplerate / 1024.0; - - if ( frames != 0 ) - bytes_per_frame = t_framelength / frames; - else - bytes_per_frame = 0; - - bitrate = static_cast(8 * bytes_per_frame * frames_per_sec + 0.5); - - if ( frames_per_sec != 0 ) - length = frames / frames_per_sec; - else - length = 1; -} - - -int32_t AAC_ADTS_File::commonSetup( FILE*& fp, NeAACDecHandle& decoder, unsigned char*& buf, size_t& bufSize, uint32_t& samplerate, uint8_t& channels ) -{ - samplerate = 0; - channels = 0; - - fp = fopen(QFile::encodeName(m_fileName), "rb" ); - if( !fp ) - { - std::cerr << "ERROR: Failed to open " << strerror( errno ) << std::endl; - return -1; - } - - if ( !(buf = static_cast( malloc(FAAD_MIN_STREAMSIZE*MAX_CHANNELS)) ) ) - { - std::cerr << "Memory allocation error" << std::endl; - fclose ( fp ); - return -1; - } - - memset( buf, 0, FAAD_MIN_STREAMSIZE*MAX_CHANNELS ); - - bufSize = fread( buf, 1, FAAD_MIN_STREAMSIZE * MAX_CHANNELS, fp ); - - int tagsize = 0; - if ( !memcmp( buf, "ID3", 3 ) ) - { - /* high bit is not used */ - tagsize = (buf[6] << 21) | (buf[7] << 14) | - (buf[8] << 7) | (buf[9] << 0); - - tagsize += 10; - bufSize -= tagsize; - fillBuffer( fp, buf, bufSize, tagsize ); - } - - decoder = NeAACDecOpen(); - - /* Set configuration */ - NeAACDecConfigurationPtr config; - config = NeAACDecGetCurrentConfiguration(decoder); - config->outputFormat = FAAD_FMT_16BIT; - config->downMatrix = 1; // Turn 5.1 channels into 2 - NeAACDecSetConfiguration( decoder, config); - - int32_t initval = 0; - if ((initval = NeAACDecInit(decoder, buf, - FAAD_MIN_STREAMSIZE*MAX_CHANNELS, &samplerate, &channels)) < 0) - { - std::cerr << "Error: could not set up AAC decoder" << std::endl; - if ( buf ) - free( buf ); - buf = NULL; - NeAACDecClose( decoder ); - decoder = NULL; - fclose( fp ); - fp = NULL; - } - return initval; -} - - -bool AAC_ADTS_File::init() -{ - uint32_t initSamplerate = 0; - uint8_t initChannels = 0; - int32_t initval = commonSetup( m_file, m_decoder, m_inBuf, m_inBufSize, initSamplerate, initChannels ); - - if ( initval >= 0 ) - { - m_inBufSize -= initval; - fillBuffer( m_file, m_inBuf, m_inBufSize, initval ); - - // These two only needed for skipping AAC ADIF files - m_adifSamplerate = initSamplerate; - m_adifChannels = initChannels; - - return true; - } - - throw std::runtime_error( "ERROR: Could not initialize AAC file reader!" ); - return false; -} - - -/*QString AAC_ADTS_File::getMbid() -{ - char out[MBID_BUFFER_SIZE]; - int const r = getMP3_MBID(QFile::encodeName(m_fileName), out); - if ( r == 0 ) - return QString::fromLatin1( out ); - return QString(); -}*/ - -void AAC_ADTS_File::getInfo( int& lengthSecs, int& samplerate, int& bitrate, int& nchannels ) -{ - long fileread; - uint32_t initSamplerate; - uint8_t initChannels; - double initLength = 0; - unsigned char *tempBuf = NULL; - size_t tempBufSize; - FILE *fp = NULL; - NeAACDecHandle decoder = NULL; - commonSetup( fp, decoder, tempBuf, tempBufSize, initSamplerate, initChannels ); - - long origpos = ftell( fp ); - fseek( fp, 0, SEEK_END ); - fileread = ftell( fp ); - fseek( fp, origpos, SEEK_SET ); - - if ( (tempBuf[0] == 0xFF) && ((tempBuf[1] & 0xF6) == 0xF0) ) - { - parse( fp, tempBuf, tempBufSize, bitrate, initLength ); - } - else if (memcmp(tempBuf, "ADIF", 4) == 0) - { - int skip_size = (tempBuf[4] & 0x80) ? 9 : 0; - bitrate = ((tempBuf[4 + skip_size] & 0x0F)<<19) | - (tempBuf[5 + skip_size]<<11) | - (tempBuf[6 + skip_size]<<3) | - (tempBuf[7 + skip_size] & 0xE0); - - if ( fileread != 0) - { - initLength = static_cast(fileread) * 8 / bitrate + 0.5; - } - } - - lengthSecs = static_cast(initLength); - nchannels = initChannels; - samplerate = initSamplerate; - - if ( decoder ) - NeAACDecClose( decoder ); - if ( fp ) - fclose( fp ); - if ( tempBuf ) - free( tempBuf ); -} - - -void AAC_ADTS_File::skip( const int mSecs ) -{ - if ( m_header == AAC_ADTS ) - { - // As AAC is VBR we need to check all ADTS headers to enable seeking... - // There is no other solution - unsigned char header[8]; - unsigned int frameCount, frameLength; - double seconds = 0; - - // We need to find the ATDS syncword so rewind to the beginning - // of the unprocessed data. - if ( m_inBufSize > 0 ) - { - fseek ( m_file, -m_inBufSize, SEEK_CUR ); - m_inBufSize = 0; - } - - for( frameCount = 1; seconds * 1000 < mSecs; frameCount++ ) - { - if ( fread( header, 1, ADTS_HEADER_SIZE, m_file ) != ADTS_HEADER_SIZE ) - { - break; - } - if ( !strncmp( (char*)header, "ID3", 3 ) ) - { - // high bit is not used - unsigned char rest[2]; - fread( rest, 1, 2, m_file ); - int tagsize = (header[6] << 21) | (header[7] << 14) | - (rest[0] << 7) | (rest[1] << 0); - - fseek( m_file, tagsize, SEEK_CUR ); - fread( header, 1, ADTS_HEADER_SIZE, m_file ); - } - if ( !((header[0] == 0xFF) && ((header[1] & 0xF6) == 0xF0)) ) - { - std::cerr << "Error: Bad frame header; file may be corrupt!" << std::endl; - break; - } - - int samplerate = adts_sample_rates[ (header[2] & 0x3c) >> 2 ]; - frameLength = ( ( header[3] & 0x3 ) << 11 ) - | ( header[4] << 3 ) - | ( header[5] >> 5 ); - - if ( samplerate > 0 ) - seconds += 1024.0 / samplerate; - else - { - std::cerr << "Error: Bad frame header; file may be corrupt!" << std::endl; - break; - } - - if ( fseek( m_file, frameLength - ADTS_HEADER_SIZE, SEEK_CUR ) == -1 ) - break; - } - m_inBufSize = fread( m_inBuf, 1, FAAD_MIN_STREAMSIZE * MAX_CHANNELS, m_file ); - } - else if ( m_header == AAC_ADIF ) - { - // AAC ADIF is even worse. There's only the one header at the - // beginning of the file. If you want to skip forward, you have to - // decode block by block and check how far along you are. Lovely, eh? - - unsigned long totalSamples = 0; - void *sampleBuffer = NULL; - - do - { - NeAACDecFrameInfo frameInfo; - sampleBuffer = NeAACDecDecode(m_decoder, &frameInfo, m_inBuf, static_cast(m_inBufSize) ); - totalSamples += frameInfo.samples; - if ( frameInfo.bytesconsumed > 0 ) - { - m_inBufSize -= frameInfo.bytesconsumed; - fillBuffer( m_file, m_inBuf, m_inBufSize, frameInfo.bytesconsumed ); - } - if ( totalSamples >= ( mSecs * m_adifSamplerate * m_adifChannels / 1000 ) ) - break; - } while ( sampleBuffer != NULL ); - } -} - - -void AAC_ADTS_File::postDecode(unsigned long bytesConsumed) -{ - m_inBufSize -= bytesConsumed; - fillBuffer( m_file, m_inBuf, m_inBufSize, bytesConsumed ); -} - - -//////////////////////////////////////////////////////////////////////// -// -// AAC in an MP4 wrapper -// -//////////////////////////////////////////////////////////////////////// - - -uint32_t read_callback( void *user_data, void *buffer, uint32_t length ) -{ - return static_cast(fread( buffer, 1, length, static_cast(user_data) )); -} - - -uint32_t seek_callback( void *user_data, uint64_t position ) -{ - return fseek( static_cast(user_data), static_cast(position), SEEK_SET ); -} - -AAC_MP4_File::AAC_MP4_File( const QString& fileName, int headerType ) : AAC_File(fileName, headerType) - , m_mp4AudioTrack( -1 ) - , m_mp4SampleId( 0 ) - , m_mp4File ( NULL ) - , m_mp4cb ( NULL ) -{ -} - -int32_t AAC_MP4_File::readSample() -{ - unsigned int bsize; - int32_t rc = mp4ff_read_sample( m_mp4File, m_mp4AudioTrack, m_mp4SampleId, &m_inBuf, &bsize ); - m_inBufSize = bsize; - // Not necessarily an error. Could just mean end of file. - //if ( rc == 0 ) - // std::cerr << "Reading samples failed." << std::endl; - return rc; -} - - -int32_t AAC_MP4_File::getTrack( const mp4ff_t *f ) -{ - // find AAC track - int32_t numTracks = mp4ff_total_tracks( f ); - - for ( int32_t i = 0; i < numTracks; i++ ) - { - unsigned char *buff = NULL; - unsigned int buff_size = 0; - mp4AudioSpecificConfig mp4ASC; - - mp4ff_get_decoder_config( f, i, &buff, &buff_size ); - - if ( buff ) - { - int8_t rc = NeAACDecAudioSpecificConfig( buff, buff_size, &mp4ASC ); - free( buff ); - - if ( rc < 0 ) - continue; - return i; - } - } - - // can't decode this, probably DRM - return -1; -} - - -bool AAC_MP4_File::commonSetup( NeAACDecHandle& decoder, mp4ff_callback_t*& cb, FILE*& fp, mp4ff_t*& mp4, int32_t& audioTrack ) -{ - fp = fopen(QFile::encodeName(m_fileName), "rb"); - if ( !fp ) - { - throw std::runtime_error( "Error: failed to open AAC file!" ); - return false; - } - - decoder = NeAACDecOpen(); - - // Set configuration - NeAACDecConfigurationPtr config; - config = NeAACDecGetCurrentConfiguration( decoder ); - config->outputFormat = FAAD_FMT_16BIT; - config->downMatrix = 1; // Turn 5.1 channels into 2 - NeAACDecSetConfiguration( decoder, config ); - - // initialise the callback structure - cb = static_cast( malloc( sizeof(mp4ff_callback_t) ) ); - - cb->read = read_callback; - cb->seek = seek_callback; - cb->user_data = fp; - - mp4 = mp4ff_open_read( cb ); - - if ( !mp4 ) - { - // unable to open file - free( cb ); - cb = NULL; - NeAACDecClose( decoder ); - decoder = NULL; - fclose( fp ); - fp = NULL; - throw std::runtime_error( "Error: failed to set up AAC decoder!" ); - return false; - } - - if ( ( audioTrack = getTrack( mp4 )) < 0 ) - { - free( cb ); - cb = NULL; - NeAACDecClose( decoder ); - decoder = NULL; - fclose( fp ); - fp = NULL; - mp4ff_close( mp4 ); - mp4 = NULL; - audioTrack = 0; - throw std::runtime_error( "Error: Unable to find an audio track. Is the file DRM protected?" ); - return false; - } - return true; -} - - -/*QString AAC_MP4_File::getMbid() -{ - int j = mp4ff_meta_get_num_items( m_mp4File ); - if ( j > 0 ) - { - int k; - for ( k = 0; k < j; k++ ) - { - char *tag = NULL, *item = NULL; - if ( mp4ff_meta_get_by_index( m_mp4File, k, &item, &tag ) ) - { - if ( item != NULL && tag != NULL ) - { - QString key(item); - if ( key.toLower() == "musicbrainz track id" ) - { - QString ret(tag); - free( item ); - free( tag ); - return ret; - } - free( item ); - free( tag ); - } - } - } - } - return QString(); -}*/ - - -void AAC_MP4_File::getInfo( int& lengthSecs, int& samplerate, int& bitrate, int& nchannels ) -{ - FILE* fp = NULL; - mp4ff_callback_t *cb = NULL; - NeAACDecHandle decoder = NULL; - mp4ff_t* mp4 = NULL; - int32_t audioTrack; - - bool success = commonSetup( decoder, cb, fp, mp4, audioTrack ); - - if ( success ) - { - // get basic file info - mp4AudioSpecificConfig mp4ASC; - unsigned char* buffer = NULL; - unsigned int buffer_size = 0; - double f = 1024.0; - unsigned int framesize = 1024; - - int32_t samples = mp4ff_num_samples( mp4, audioTrack ); - - if ( buffer ) - { - if ( NeAACDecAudioSpecificConfig(buffer, buffer_size, &mp4ASC) >= 0 ) - { - if ( mp4ASC.frameLengthFlag == 1 ) - framesize = 960; - if ( mp4ASC.sbr_present_flag == 1 ) - framesize *= 2; - if ( mp4ASC.sbr_present_flag == 1 ) - f = f * 2.0; - } - free( buffer ); - } - - samplerate = mp4ff_get_sample_rate( mp4, audioTrack ); - if ( samplerate > 0 ) - lengthSecs = static_cast(samples * f / samplerate + 0.5); - bitrate = mp4ff_get_avg_bitrate( mp4, audioTrack ); - nchannels = mp4ff_get_channel_count( mp4, audioTrack ); - - mp4ff_close( mp4 ); - NeAACDecClose( decoder ); - free( cb ); - fclose( fp ); - } -} - - -bool AAC_MP4_File::init() -{ - FILE* fp = NULL; - - bool success = commonSetup( m_decoder, m_mp4cb, fp, m_mp4File, m_mp4AudioTrack ); - if ( !success ) - return false; - - unsigned char* buffer = NULL; - unsigned int buffer_size = 0; - uint32_t samplerate; - uint8_t channels; - - mp4ff_get_decoder_config( m_mp4File, m_mp4AudioTrack, &buffer, &buffer_size ); - - if( NeAACDecInit2( m_decoder, buffer, buffer_size, &samplerate, &channels) < 0 ) - { - // If some error initializing occured, skip the file - if ( fp ) - fclose( fp ); - throw std::runtime_error( "Error: unable to initialize AAC decoder library!" ); - return false; - } - - if ( buffer ) - free( buffer ); - - return true; -} - - -void AAC_MP4_File::postDecode(unsigned long) -{ - free( m_inBuf ); - m_inBuf = NULL; - m_mp4SampleId++; -} - -void AAC_MP4_File::skip( const int mSecs ) -{ - double dur = 0.0; - int f = 1; - unsigned char *buff = NULL; - unsigned int buff_size = 0; - uint32_t totalSamples = mp4ff_num_samples( m_mp4File, m_mp4AudioTrack ); - mp4AudioSpecificConfig mp4ASC; - - mp4ff_get_decoder_config( m_mp4File, m_mp4AudioTrack, &buff, &buff_size ); - - if ( buff ) - { - int8_t rc = NeAACDecAudioSpecificConfig( buff, buff_size, &mp4ASC ); - free( buff ); - if ( rc >= 0 && mp4ASC.sbr_present_flag == 1 ) - f = 2; - - // I think the f multiplier is needed here. - while ( dur * 1000.0 * f / static_cast(mp4ASC.samplingFrequency) < mSecs && m_mp4SampleId < totalSamples ) - { - dur += mp4ff_get_sample_duration( m_mp4File, m_mp4AudioTrack, m_mp4SampleId ); - m_mp4SampleId++; - } - } - else - std::cerr << "Error: could not skip " << mSecs << " milliseconds" << std::endl; -} - - -AAC_MP4_File::~AAC_MP4_File() -{ - if ( m_mp4File ) - mp4ff_close( m_mp4File ); - if ( m_mp4cb ) - { - free( m_mp4cb ); - } -} - - -//////////////////////////////////////////////////////////////////////// -// -// AacSource -// -//////////////////////////////////////////////////////////////////////// - -AacSource::AacSource() - : m_eof( false ) - , m_aacFile( NULL ) -{} - - -AacSource::~AacSource() -{ - delete m_aacFile; -} - - -int AacSource::checkHeader() -{ - FILE *fp = NULL; - unsigned char header[10]; - - // check for mp4 file - fp = fopen(QFile::encodeName(m_fileName), "rb"); - if ( !fp ) - { - std::cerr << "Error: failed to open " << strerror( errno ) << std::endl; - return AAC_File::AAC_UNKNOWN; - } - - fread( header, 1, 10, fp ); - - // MP4 headers - if ( !memcmp( &header[4], "ftyp", 4 ) ) - { - fclose( fp ); - return AAC_File::AAC_MP4; - } - - // Skip id3 tags - int tagsize = 0; - if ( !memcmp( header, "ID3", 3 ) ) - { - /* high bit is not used */ - tagsize = (header[6] << 21) | (header[7] << 14) | - (header[8] << 7) | (header[9] << 0); - - tagsize += 10; - fseek( fp, tagsize, SEEK_SET ); - fread( header, 1, 10, fp ); - } - - // Check for ADTS OR ADIF headers - if ( (header[0] == 0xFF) && ((header[1] & 0xF6) == 0xF0) ) - { - fclose( fp ); - return AAC_File::AAC_ADTS; - } - else if (memcmp(header, "ADIF", 4) == 0) - { - fclose( fp ); - return AAC_File::AAC_ADIF; - } - - fclose( fp ); - return AAC_File::AAC_UNKNOWN; -} - - -void AacSource::getInfo( int& lengthSecs, int& samplerate, int& bitrate, int& nchannels ) -{ - // get the header plus some other stuff.. - - m_aacFile->getInfo( lengthSecs, samplerate, bitrate, nchannels ); -} - - -void AacSource::init(const QString& fileName) -{ - m_fileName = fileName; - - int headerType = checkHeader(); - if ( headerType != AAC_File::AAC_UNKNOWN ) - { - if ( headerType == AAC_File::AAC_MP4 ) - m_aacFile = new AAC_MP4_File(m_fileName, headerType); - else - m_aacFile = new AAC_ADTS_File( m_fileName, headerType ); - } - - if ( m_aacFile ) - m_aacFile->init(); - else - throw std::runtime_error( "ERROR: No suitable AAC decoder found!" ); -} - - -/*QString AacSource::getMbid() -{ - QString mbid = m_aacFile->getMbid(); - return mbid; -}*/ - - -void AacSource::skip( const int mSecs ) -{ - if ( mSecs < 0 || !m_aacFile->m_decoder ) - return; - - m_aacFile->skip( mSecs ); -} - - -void AacSource::skipSilence(double silenceThreshold /* = 0.0001 */) -{ - if ( !m_aacFile->m_decoder ) - return; - - silenceThreshold *= static_cast( std::numeric_limits::max() ); - - for (;;) - { - if ( m_aacFile->m_header == AAC_File::AAC_MP4 ) - { - if ( !static_cast(m_aacFile)->readSample() ) - break; - } - NeAACDecFrameInfo frameInfo; - - void* sampleBuffer = NeAACDecDecode(m_aacFile->m_decoder, &frameInfo, m_aacFile->m_inBuf, static_cast(m_aacFile->m_inBufSize) ); - - m_aacFile->postDecode( frameInfo.bytesconsumed ); - - if ( frameInfo.error > 0 ) - { - break; - } - else if ( frameInfo.samples > 0 ) - { - double sum = 0; - int16_t *buf = static_cast(sampleBuffer); - switch ( frameInfo.channels ) - { - case 1: - for (size_t j = 0; j < frameInfo.samples; ++j) - sum += abs( buf[j] ); - break; - case 2: - for (size_t j = 0; j < frameInfo.samples; j+=2) - sum += abs( (buf[j] >> 1) + (buf[j+1] >> 1) ); - break; - } - if ( (sum >= silenceThreshold * static_cast(frameInfo.samples/frameInfo.channels) ) ) - break; - } - } -} - - -int AacSource::updateBuffer( signed short *pBuffer, size_t bufferSize ) -{ - size_t nwrit = 0; //number of samples written to the output buffer - - if ( m_aacFile->m_overflowSize > 0 ) - { - size_t samples_to_use = bufferSize < m_aacFile->m_overflowSize ? bufferSize : m_aacFile->m_overflowSize; - memcpy( pBuffer, m_aacFile->m_overflow, samples_to_use * sizeof(signed short) ); - nwrit += samples_to_use; - m_aacFile->m_overflowSize -= samples_to_use; - memmove( (void*)(m_aacFile->m_overflow), (void*)(m_aacFile->m_overflow + samples_to_use*sizeof(signed short)), samples_to_use*sizeof(signed short) ); - } - - if ( !m_aacFile->m_decoder ) - return 0; - - for (;;) - { - signed short* pBufferIt = pBuffer + nwrit; - void* sampleBuffer; - - assert( nwrit <= bufferSize ); - - if ( m_aacFile->m_header == AAC_File::AAC_MP4 ) - { - if ( !static_cast(m_aacFile)->readSample() ) - { - m_eof = true; - return static_cast(nwrit); - } - } - NeAACDecFrameInfo frameInfo; - - sampleBuffer = NeAACDecDecode(m_aacFile->m_decoder, &frameInfo, m_aacFile->m_inBuf, static_cast(m_aacFile->m_inBufSize) ); - size_t samples_to_use = (bufferSize - nwrit) < frameInfo.samples ? bufferSize-nwrit : frameInfo.samples; - - if ( samples_to_use > 0 && sampleBuffer != NULL ) - { - memcpy( pBufferIt, sampleBuffer, samples_to_use * sizeof(signed short) ); - nwrit += samples_to_use; - } - - if ( samples_to_use < frameInfo.samples ) - { - m_aacFile->m_overflow = static_cast(realloc( m_aacFile->m_overflow, (frameInfo.samples - samples_to_use) * sizeof(signed short) ) ); - memcpy( m_aacFile->m_overflow, static_cast(sampleBuffer) + samples_to_use, (frameInfo.samples - samples_to_use) * sizeof(signed short) ); - m_aacFile->m_overflowSize = frameInfo.samples - samples_to_use; - } - - m_aacFile->postDecode( frameInfo.bytesconsumed ); - - if ( sampleBuffer == NULL ) - { - m_eof = true; - break; - } - - if ( frameInfo.error > 0 ) - { - std::cerr << "Error: " << NeAACDecGetErrorMessage(frameInfo.error) << std::endl; - break; - } - - if ( nwrit == bufferSize ) - break; - } - - return static_cast(nwrit); -} diff --git a/thirdparty/liblastfm2/src/fingerprint/contrib/AacSource.h b/thirdparty/liblastfm2/src/fingerprint/contrib/AacSource.h deleted file mode 100644 index 0fff6f585..000000000 --- a/thirdparty/liblastfm2/src/fingerprint/contrib/AacSource.h +++ /dev/null @@ -1,46 +0,0 @@ -/* - Copyright 2009 Last.fm Ltd. - Copyright 2009 John Stamp - - This file is part of liblastfm. - - liblastfm is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - liblastfm is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with liblastfm. If not, see . -*/ -#ifndef __AAC_SOURCE_H__ -#define __AAC_SOURCE_H__ - -#include - -class AacSource : public lastfm::FingerprintableSource -{ -public: - AacSource(); - ~AacSource(); - - virtual void getInfo(int& lengthSecs, int& samplerate, int& bitrate, int& nchannels); - virtual void init(const QString& fileName); - virtual int updateBuffer(signed short* pBuffer, size_t bufferSize); - virtual void skip(const int mSecs); - virtual void skipSilence(double silenceThreshold = 0.0001); - virtual bool eof() const { return m_eof; } - -private: - int checkHeader(); - QString m_fileName; - bool m_eof; - class AAC_File *m_aacFile; -}; - -#endif - diff --git a/thirdparty/liblastfm2/src/fingerprint/contrib/AacSource_p.h b/thirdparty/liblastfm2/src/fingerprint/contrib/AacSource_p.h deleted file mode 100644 index 870482c1f..000000000 --- a/thirdparty/liblastfm2/src/fingerprint/contrib/AacSource_p.h +++ /dev/null @@ -1,94 +0,0 @@ -/* - Copyright 2009 Last.fm Ltd. - Copyright 2009 John Stamp - - This file is part of liblastfm. - - liblastfm is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - liblastfm is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with liblastfm. If not, see . -*/ -#include -#include - -class AAC_File -{ -public: - AAC_File(const QString&, int headerType); - virtual ~AAC_File(); - virtual void getInfo( int& lengthSecs, int& samplerate, int& bitrate, int& nchannels ) = 0; - virtual bool init() = 0; - //virtual QString getMbid() = 0; - virtual void skip( const int mSecs ) = 0; - virtual void postDecode(unsigned long) = 0; - - enum HeaderType - { - AAC_UNKNOWN = 0, - AAC_ADIF, - AAC_ADTS, - AAC_MP4 - }; - - QString m_fileName; - unsigned char *m_inBuf; - size_t m_inBufSize; - NeAACDecHandle m_decoder; - unsigned char *m_overflow; - size_t m_overflowSize; - int m_header; -}; - - -class AAC_MP4_File : public AAC_File -{ -public: - AAC_MP4_File(const QString&, int headerType = AAC_MP4 ); - ~AAC_MP4_File(); - virtual void getInfo( int& lengthSecs, int& samplerate, int& bitrate, int& nchannels ); - virtual bool init(); - //virtual QString getMbid(); - virtual void skip( const int mSecs ); - virtual void postDecode(unsigned long); - int32_t readSample(); - -private: - bool commonSetup( NeAACDecHandle& handle, mp4ff_callback_t*& cb, FILE*& fp, mp4ff_t*& mp4, int32_t& audioTrack ); - virtual int32_t getTrack( const mp4ff_t* f ); - int m_mp4AudioTrack; - uint32_t m_mp4SampleId; - mp4ff_t *m_mp4File; - mp4ff_callback_t *m_mp4cb; -}; - - -class AAC_ADTS_File : public AAC_File -{ -public: - AAC_ADTS_File( const QString& fileName, int headerType ); - ~AAC_ADTS_File(); - virtual void getInfo( int& lengthSecs, int& samplerate, int& bitrate, int& nchannels ); - virtual bool init(); - //virtual QString getMbid(); - virtual void skip( const int mSecs ); - virtual void postDecode(unsigned long bytesconsumed ); - -private: - int32_t commonSetup( FILE*& fp, NeAACDecHandle& decoder, unsigned char*& buf, size_t& bufSize, uint32_t& samplerate, uint8_t& channels ); - void parse( FILE*& fp, unsigned char*& buf, size_t& bufSize, int &bitrate, double &length ); - void fillBuffer( FILE*& fp, unsigned char*& buf, size_t& bufSize, const size_t m_bytesConsumed ); - - FILE* m_file; - // These two only needed for skipping AAC ADIF files - uint32_t m_adifSamplerate; - int m_adifChannels; -}; diff --git a/thirdparty/liblastfm2/src/fingerprint/contrib/FlacSource.cpp b/thirdparty/liblastfm2/src/fingerprint/contrib/FlacSource.cpp deleted file mode 100644 index 1e1e29900..000000000 --- a/thirdparty/liblastfm2/src/fingerprint/contrib/FlacSource.cpp +++ /dev/null @@ -1,339 +0,0 @@ -/* - Copyright 2009 Last.fm Ltd. - Copyright 2009 John Stamp - - This file is part of liblastfm. - - liblastfm is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - liblastfm is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with liblastfm. If not, see . -*/ -#include "FlacSource.h" -#include -#include -#include -#include -#include -#include -#include - -#include - - -FLAC__StreamDecoderWriteStatus FlacSource::_write_callback(const FLAC__StreamDecoder *, const FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *client_data) -{ - assert(client_data != NULL); - FlacSource *instance = reinterpret_cast(client_data); - assert(instance != NULL); - return instance->write_callback(frame, buffer); -} - -FLAC__StreamDecoderWriteStatus FlacSource::write_callback(const FLAC__Frame *frame, const FLAC__int32 * const buffer[]) -{ - m_outBufLen = 0; - - if ( m_outBuf ) - { - size_t i; - for(i = 0; i < frame->header.blocksize; i++) - { - switch ( m_channels ) - { - case 1: - m_outBuf[m_outBufLen] = (FLAC__int16)buffer[0][i]; // mono - m_outBufLen++; - break; - case 2: - m_outBuf[m_outBufLen] = (FLAC__int16)buffer[0][i]; // left channel - m_outBuf[m_outBufLen+1] = (FLAC__int16)buffer[1][i]; // right channel - m_outBufLen += 2; - break; - } - } - m_samplePos += frame->header.blocksize; - } - - return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE; -} - -// --------------------------------------------------------------------- - -void FlacSource::_metadata_callback(const FLAC__StreamDecoder *, const FLAC__StreamMetadata *metadata, void *client_data) -{ - assert(client_data != NULL); - FlacSource *instance = reinterpret_cast(client_data); - assert(instance != NULL); - instance->metadata_callback(metadata); -} - -void FlacSource::metadata_callback( const FLAC__StreamMetadata *metadata ) -{ - switch ( metadata->type ) - { - case FLAC__METADATA_TYPE_STREAMINFO: - m_channels = metadata->data.stream_info.channels; - m_totalSamples = metadata->data.stream_info.total_samples; - m_samplerate = metadata->data.stream_info.sample_rate; - m_bps = metadata->data.stream_info.bits_per_sample; - m_maxFrameSize = metadata->data.stream_info.max_framesize; - break; - case FLAC__METADATA_TYPE_VORBIS_COMMENT: - m_commentData = FLAC__metadata_object_clone(metadata); - break; - default: - break; - } -} - -// --------------------------------------------------------------------- - -void FlacSource::_error_callback(const FLAC__StreamDecoder *, FLAC__StreamDecoderErrorStatus status, void *client_data) -{ - assert(client_data != NULL); - FlacSource *instance = reinterpret_cast(client_data); - assert(instance != NULL); - instance->error_callback(status); -} - -void FlacSource::error_callback(FLAC__StreamDecoderErrorStatus status) -{ - std::cerr << "Got FLAC error: " << FLAC__StreamDecoderErrorStatusString[status] << std::endl; -} - -// --------------------------------------------------------------------- - -FlacSource::FlacSource() - : m_decoder( 0 ) - , m_fileSize( 0 ) - , m_outBuf( 0 ) - , m_outBufLen( 0 ) - , m_outBufPos( 0 ) - , m_samplePos( 0 ) - , m_maxFrameSize( 0 ) - , m_commentData( 0 ) - , m_bps( 0 ) - , m_channels( 0 ) - , m_samplerate( 0 ) - , m_totalSamples( 0 ) - , m_eof( false ) -{ -} - -// --------------------------------------------------------------------- - -FlacSource::~FlacSource() -{ - if ( m_decoder ) - { - FLAC__stream_decoder_finish( m_decoder ); - FLAC__stream_decoder_delete( m_decoder ); - } - if ( m_commentData ) - FLAC__metadata_object_delete( m_commentData ); - if ( m_outBuf ) - free( m_outBuf ); -} - -// --------------------------------------------------------------------- - -void FlacSource::init(const QString& fileName) -{ - m_fileName = fileName; - - if ( !m_decoder ) - { - FILE *f = fopen(QFile::encodeName(m_fileName), "rb" ); - if ( f ) - { - // Need to check which init call to use; flac doesn't do that for us - unsigned char header[35]; - bool isOgg = false; - fread( header, 1, 35, f ); - if ( memcmp(header, "OggS", 4) == 0 && - memcmp(&header[29], "FLAC", 4) == 0 ) - isOgg = true; - - // getInfo() will need this to calculate bitrate - fseek( f, 0, SEEK_END ); - m_fileSize = ftell(f); - - rewind( f ); - - m_decoder = FLAC__stream_decoder_new(); - FLAC__stream_decoder_set_metadata_respond(m_decoder, FLAC__METADATA_TYPE_STREAMINFO); - FLAC__stream_decoder_set_metadata_respond(m_decoder, FLAC__METADATA_TYPE_VORBIS_COMMENT); - - int init_status; - if ( FLAC_API_SUPPORTS_OGG_FLAC && isOgg ) - init_status = FLAC__stream_decoder_init_ogg_FILE( m_decoder, f, _write_callback, _metadata_callback, _error_callback, this ); - else - init_status = FLAC__stream_decoder_init_FILE( m_decoder, f, _write_callback, _metadata_callback, _error_callback, this ); - - if(init_status != FLAC__STREAM_DECODER_INIT_STATUS_OK) - return; - - FLAC__stream_decoder_process_until_end_of_metadata( m_decoder ); - m_outBuf = static_cast(malloc( sizeof(signed short)*m_maxFrameSize)); - - if ( m_bps != 16 ) - { - FLAC__stream_decoder_finish( m_decoder ); - FLAC__stream_decoder_delete( m_decoder ); - FLAC__metadata_object_delete( m_commentData ); - m_decoder = 0; - m_commentData = 0; - throw std::runtime_error( "ERROR: only 16 bit FLAC files are currently supported!" ); - } - } - else - throw std::runtime_error( "ERROR: cannot load FLAC file!" ); - } -} - -// --------------------------------------------------------------------- - -/*QString FlacSource::getMbid() -{ - if ( m_commentData ) - { - FLAC__StreamMetadata_VorbisComment *vc; - vc = &m_commentData->data.vorbis_comment; - for ( unsigned int i = 0; i < vc->num_comments; ++i ) - { - QByteArray key( (char*)(vc->comments[i].entry), vc->comments[i].length ); - if ( key.left(20).toLower() == "musicbrainz_trackid=" ) - { - QString val = key.mid(20); - return val; - } - } - } - - return QString(); -}*/ - -// --------------------------------------------------------------------- - -void FlacSource::getInfo(int& lengthSecs, int& samplerate, int& bitrate, int& nchannels) -{ - lengthSecs = 0; - samplerate = 0; - bitrate = 0; - nchannels = 0; - - if ( m_decoder ) - { - samplerate = m_samplerate; - nchannels = m_channels; - if ( samplerate > 0 ) - lengthSecs = static_cast( static_cast(m_totalSamples)/m_samplerate + 0.5); - - // Calcuate bitrate - if ( lengthSecs > 0 ) - { - FLAC__Metadata_SimpleIterator *it = FLAC__metadata_simple_iterator_new(); - FLAC__metadata_simple_iterator_init( it, QFile::encodeName(m_fileName), true, true ); - while( !FLAC__metadata_simple_iterator_is_last( it ) ) - { - FLAC__metadata_simple_iterator_next( it ); - } - off_t audioOffset = FLAC__metadata_simple_iterator_get_block_offset( it ) + - FLAC__metadata_simple_iterator_get_block_length( it ); - FLAC__metadata_simple_iterator_delete( it ); - bitrate = static_cast( static_cast(m_fileSize - audioOffset) * 8 / lengthSecs + 0.5 ); - } - } -} - -// --------------------------------------------------------------------- - -void FlacSource::skip( const int mSecs ) -{ - FLAC__uint64 absSample = mSecs * m_samplerate / 1000 + m_samplePos; - if ( !FLAC__stream_decoder_seek_absolute(m_decoder, absSample) ) - FLAC__stream_decoder_reset( m_decoder ); - m_outBufLen = 0; -} - -// --------------------------------------------------------------------- - -void FlacSource::skipSilence(double silenceThreshold /* = 0.0001 */) -{ - silenceThreshold *= static_cast( std::numeric_limits::max() ); - for ( ;; ) - { - double sum = 0; - bool result = FLAC__stream_decoder_process_single( m_decoder ); - // there was a fatal read - if ( !result ) - break; - - switch ( m_channels ) - { - case 1: - for (size_t j = 0; j < m_outBufLen; ++j) - sum += abs( m_outBuf[j] ); - break; - case 2: - for ( size_t j = 0; j < m_outBufLen; j+=2 ) - sum += abs( (m_outBuf[j] >> 1) - + (m_outBuf[j+1] >> 1) ); - break; - } - if ( (sum >= silenceThreshold * static_cast(m_outBufLen) ) ) - break; - } - m_outBufLen = 0; -} - -// --------------------------------------------------------------------- - -int FlacSource::updateBuffer( signed short *pBuffer, size_t bufferSize ) -{ - size_t nwrit = 0; - - for ( ;; ) - { - size_t samples_to_use = std::min (bufferSize - nwrit, m_outBufLen - m_outBufPos); - signed short* pBufferIt = pBuffer + nwrit; - - nwrit += samples_to_use; - assert( nwrit <= bufferSize ); - memcpy( pBufferIt, m_outBuf + m_outBufPos, sizeof(signed short)*samples_to_use ); - - if ( samples_to_use < m_outBufLen - m_outBufPos ) - m_outBufPos = samples_to_use; - else - { - m_outBufPos = 0; - bool result = FLAC__stream_decoder_process_single( m_decoder ); - // there was a fatal read - if ( !result ) - { - std::cerr << "Fatal error decoding FLAC" << std::endl; - return 0; - } - else if ( FLAC__stream_decoder_get_state( m_decoder ) == FLAC__STREAM_DECODER_END_OF_STREAM ) - { - m_eof = true; - break; - } - } - - if ( nwrit == bufferSize ) - return static_cast(nwrit); - } - return static_cast(nwrit); -} - -// ----------------------------------------------------------------------------- - diff --git a/thirdparty/liblastfm2/src/fingerprint/contrib/FlacSource.h b/thirdparty/liblastfm2/src/fingerprint/contrib/FlacSource.h deleted file mode 100644 index 24dd97f11..000000000 --- a/thirdparty/liblastfm2/src/fingerprint/contrib/FlacSource.h +++ /dev/null @@ -1,74 +0,0 @@ -/* - Copyright 2009 Last.fm Ltd. - Copyright 2009 John Stamp - - This file is part of liblastfm. - - liblastfm is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - liblastfm is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with liblastfm. If not, see . -*/ -#ifndef __FLAC_SOURCE_H__ -#define __FLAC_SOURCE_H__ - -#include -#include -#include - - -class FlacSource : public lastfm::FingerprintableSource -{ -public: - FlacSource(); - virtual ~FlacSource(); - - virtual void getInfo(int& lengthSecs, int& samplerate, int& bitrate, int& nchannels); - virtual void init(const QString& fileName); - - // return a chunk of PCM data from the FLAC file - virtual int updateBuffer(signed short* pBuffer, size_t bufferSize); - - virtual void skip(const int mSecs); - virtual void skipSilence(double silenceThreshold = 0.0001); - - //QString getMbid(); - - bool eof() const { return m_eof; } - -private: - static FLAC__StreamDecoderWriteStatus _write_callback(const FLAC__StreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *client_data); - static void _metadata_callback(const FLAC__StreamDecoder *decoder, const FLAC__StreamMetadata *metadata, void *client_data); - static void _error_callback(const ::FLAC__StreamDecoder *decoder, ::FLAC__StreamDecoderErrorStatus status, void *client_data); - - FLAC__StreamDecoderWriteStatus write_callback(const FLAC__Frame *frame, const FLAC__int32 * const buffer[]); - void metadata_callback( const FLAC__StreamMetadata *metadata ); - void error_callback(FLAC__StreamDecoderErrorStatus status); - - FLAC__StreamDecoder *m_decoder; - QString m_fileName; - size_t m_fileSize; - short *m_outBuf; - size_t m_outBufLen; - size_t m_outBufPos; - FLAC__uint64 m_samplePos; - unsigned m_maxFrameSize; - FLAC__StreamMetadata* m_commentData; - unsigned m_bps; - unsigned m_channels; - unsigned m_samplerate; - FLAC__uint64 m_totalSamples; - - bool m_eof; -}; - -#endif - diff --git a/thirdparty/liblastfm2/src/fingerprint/contrib/MadSource.cpp b/thirdparty/liblastfm2/src/fingerprint/contrib/MadSource.cpp deleted file mode 100644 index 00e725ae6..000000000 --- a/thirdparty/liblastfm2/src/fingerprint/contrib/MadSource.cpp +++ /dev/null @@ -1,514 +0,0 @@ -/* - Copyright 2009 Last.fm Ltd. - Copyright 2009 John Stamp - - This file is part of liblastfm. - - liblastfm is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - liblastfm is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with liblastfm. If not, see . -*/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include "MadSource.h" - -#undef max // was definded in mad - -using namespace std; - - -// ----------------------------------------------------------- - -MadSource::MadSource() - : m_pMP3_Buffer ( new unsigned char[m_MP3_BufferSize+MAD_BUFFER_GUARD] ) -{} - -// ----------------------------------------------------------- - -MadSource::~MadSource() -{ - if ( m_inputFile.isOpen() ) - { - m_inputFile.close(); - mad_synth_finish(&m_mad_synth); - mad_frame_finish(&m_mad_frame); - mad_stream_finish(&m_mad_stream); - } - if (m_pMP3_Buffer) delete[] m_pMP3_Buffer; -} - -// --------------------------------------------------------------------- - -inline short f2s(mad_fixed_t f) -{ - /* A fixed point number is formed of the following bit pattern: - * - * SWWWFFFFFFFFFFFFFFFFFFFFFFFFFFFF - * MSB LSB - * S ==> Sign (0 is positive, 1 is negative) - * W ==> Whole part bits - * F ==> Fractional part bits - * - * This pattern contains MAD_F_FRACBITS fractional bits, one - * should alway use this macro when working on the bits of a fixed - * point number. It is not guaranteed to be constant over the - * different platforms supported by libmad. - * - * The signed short value is formed, after clipping, by the least - * significant whole part bit, followed by the 15 most significant - * fractional part bits. Warning: this is a quick and dirty way to - * compute the 16-bit number, madplay includes much better - * algorithms. - */ - - /* Clipping */ - if(f >= MAD_F_ONE) - return(SHRT_MAX); - if(f <= -MAD_F_ONE) - return(-SHRT_MAX); - - /* Conversion. */ - f = f >> (MAD_F_FRACBITS-15); - return (signed short)f; -} - -// --------------------------------------------------------------------- - -string MadSource::MadErrorString(const mad_error& error) -{ - switch(error) - { - /* Generic unrecoverable errors. */ - case MAD_ERROR_BUFLEN: - return("input buffer too small (or EOF)"); - case MAD_ERROR_BUFPTR: - return("invalid (null) buffer pointer"); - case MAD_ERROR_NOMEM: - return("not enough memory"); - - /* Frame header related unrecoverable errors. */ - case MAD_ERROR_LOSTSYNC: - return("lost synchronization"); - case MAD_ERROR_BADLAYER: - return("reserved header layer value"); - case MAD_ERROR_BADBITRATE: - return("forbidden bitrate value"); - case MAD_ERROR_BADSAMPLERATE: - return("reserved sample frequency value"); - case MAD_ERROR_BADEMPHASIS: - return("reserved emphasis value"); - - /* Recoverable errors */ - case MAD_ERROR_BADCRC: - return("CRC check failed"); - case MAD_ERROR_BADBITALLOC: - return("forbidden bit allocation value"); - case MAD_ERROR_BADSCALEFACTOR: - return("bad scalefactor index"); - case MAD_ERROR_BADFRAMELEN: - return("bad frame length"); - case MAD_ERROR_BADBIGVALUES: - return("bad big_values count"); - case MAD_ERROR_BADBLOCKTYPE: - return("reserved block_type"); - case MAD_ERROR_BADSCFSI: - return("bad scalefactor selection info"); - case MAD_ERROR_BADDATAPTR: - return("bad main_data_begin pointer"); - case MAD_ERROR_BADPART3LEN: - return("bad audio data length"); - case MAD_ERROR_BADHUFFTABLE: - return("bad Huffman table select"); - case MAD_ERROR_BADHUFFDATA: - return("Huffman data overrun"); - case MAD_ERROR_BADSTEREO: - return("incompatible block_type for JS"); - - /* Unknown error. This switch may be out of sync with libmad's - * defined error codes. - */ - default: - return("Unknown error code"); - } -} - - -// ----------------------------------------------------------------------------- - -bool MadSource::isRecoverable(const mad_error& error, bool log) -{ - if (MAD_RECOVERABLE (error)) - { - /* Do not print a message if the error is a loss of - * synchronization and this loss is due to the end of - * stream guard bytes. (See the comments marked {3} - * supra for more informations about guard bytes.) - */ - if (error != MAD_ERROR_LOSTSYNC /*|| mad_stream.this_frame != pGuard */ && log) - { - cerr << "Recoverable frame level error: " - << MadErrorString(error) << endl; - } - - return true; - } - else - { - if (error == MAD_ERROR_BUFLEN) - return true; - else - { - stringstream ss; - - ss << "Unrecoverable frame level error: " - << MadErrorString (error) << endl; - throw ss.str(); - } - } - - return false; -} - -// ----------------------------------------------------------- - -void MadSource::init(const QString& fileName) -{ - m_inputFile.setFileName( m_fileName = fileName ); - bool fine = m_inputFile.open( QIODevice::ReadOnly ); - - if ( !fine ) - { - throw std::runtime_error ("Cannot load mp3 file!"); - } - - mad_stream_init(&m_mad_stream); - mad_frame_init (&m_mad_frame); - mad_synth_init (&m_mad_synth); - mad_timer_reset(&m_mad_timer); - - m_pcmpos = m_mad_synth.pcm.length; -} - -// ----------------------------------------------------------------------------- - -/*QString MadSource::getMbid() -{ - char out[MBID_BUFFER_SIZE]; - int const r = getMP3_MBID( QFile::encodeName( m_fileName ), out ); - if (r == 0) - return QString::fromLatin1( out ); - return QString(); -}*/ - -void MadSource::getInfo(int& lengthSecs, int& samplerate, int& bitrate, int& nchannels ) -{ - // get the header plus some other stuff.. - QFile inputFile(m_fileName); - bool fine = inputFile.open( QIODevice::ReadOnly ); - - if ( !fine ) - { - throw std::runtime_error ("ERROR: Cannot load file for getInfo!"); - return; - } - - unsigned char* pMP3_Buffer = new unsigned char[m_MP3_BufferSize+MAD_BUFFER_GUARD]; - - mad_stream madStream; - mad_header madHeader; - mad_timer_t madTimer; - - mad_stream_init(&madStream); - mad_timer_reset(&madTimer); - - double avgSamplerate = 0; - double avgBitrate = 0; - double avgNChannels = 0; - int nFrames = 0; - - while ( fetchData( inputFile, pMP3_Buffer, m_MP3_BufferSize, madStream) ) - { - if ( mad_header_decode(&madHeader, &madStream) != 0 ) - { - if ( isRecoverable(madStream.error) ) - continue; - else - break; - } - - mad_timer_add(&madTimer, madHeader.duration); - - avgSamplerate += madHeader.samplerate; - avgBitrate += madHeader.bitrate; - - if ( madHeader.mode == MAD_MODE_SINGLE_CHANNEL ) - ++avgNChannels; - else - avgNChannels += 2; - - ++nFrames; - } - - inputFile.close(); - mad_stream_finish(&madStream); - mad_header_finish(&madHeader); - delete[] pMP3_Buffer; - - - lengthSecs = static_cast(madTimer.seconds); - samplerate = static_cast( (avgSamplerate/nFrames) + 0.5 ); - bitrate = static_cast( (avgBitrate/nFrames) + 0.5 ); - nchannels = static_cast( (avgNChannels/nFrames) + 0.5 ); -} - -// ----------------------------------------------------------- - - -bool MadSource::fetchData( QFile& mp3File, - unsigned char* pMP3_Buffer, - const int MP3_BufferSize, - mad_stream& madStream ) -{ - unsigned char *pReadStart = NULL; - unsigned char *pGuard = NULL; - - if ( madStream.buffer == NULL || - madStream.error == MAD_ERROR_BUFLEN ) - { - - size_t readSize; - size_t remaining; - - /* {2} libmad may not consume all bytes of the input - * buffer. If the last frame in the buffer is not wholly - * contained by it, then that frame's start is pointed by - * the next_frame member of the Stream structure. This - * common situation occurs when mad_frame_decode() fails, - * sets the stream error code to MAD_ERROR_BUFLEN, and - * sets the next_frame pointer to a non NULL value. (See - * also the comment marked {4} bellow.) - * - * When this occurs, the remaining unused bytes must be - * put back at the beginning of the buffer and taken in - * account before refilling the buffer. This means that - * the input buffer must be large enough to hold a whole - * frame at the highest observable bit-rate (currently 448 - * kb/s). XXX=XXX Is 2016 bytes the size of the largest - * frame? (448000*(1152/32000))/8 - */ - if (madStream.next_frame != NULL) - { - remaining = madStream.bufend - madStream.next_frame; - memmove (pMP3_Buffer, madStream.next_frame, remaining); - - pReadStart = pMP3_Buffer + remaining; - readSize = MP3_BufferSize - remaining; - } - else - { - readSize = MP3_BufferSize; - pReadStart = pMP3_Buffer; - remaining = 0; - } - - readSize = mp3File.read( reinterpret_cast(pReadStart), readSize ); - - // nothing else to read! - if (readSize <= 0) - return false; - - if ( mp3File.atEnd() ) - { - pGuard = pReadStart + readSize; - - memset (pGuard, 0, MAD_BUFFER_GUARD); - readSize += MAD_BUFFER_GUARD; - } - - // Pipe the new buffer content to libmad's stream decoder facility. - mad_stream_buffer( &madStream, pMP3_Buffer, - static_cast(readSize + remaining)); - - madStream.error = MAD_ERROR_NONE; - } - - return true; -} - -// ----------------------------------------------------------------------------- - -void MadSource::skipSilence(double silenceThreshold /* = 0.0001 */) -{ - mad_frame madFrame; - mad_synth madSynth; - - mad_frame_init(&madFrame); - mad_synth_init (&madSynth); - - silenceThreshold *= static_cast( numeric_limits::max() ); - - for (;;) - { - if ( !fetchData( m_inputFile, m_pMP3_Buffer, m_MP3_BufferSize, m_mad_stream) ) - break; - - if ( mad_frame_decode(&madFrame, &m_mad_stream) != 0 ) - { - if ( isRecoverable(m_mad_stream.error) ) - continue; - else - break; - } - - mad_synth_frame (&madSynth, &madFrame); - - double sum = 0; - - switch (madSynth.pcm.channels) - { - case 1: - for (size_t j = 0; j < madSynth.pcm.length; ++j) - sum += abs(f2s(madSynth.pcm.samples[0][j])); - break; - case 2: - for (size_t j = 0; j < madSynth.pcm.length; ++j) - sum += abs(f2s( - (madSynth.pcm.samples[0][j] >> 1) - + (madSynth.pcm.samples[1][j] >> 1))); - break; - } - - if ( (sum >= silenceThreshold * madSynth.pcm.length) ) - break; - } - - mad_frame_finish(&madFrame); -} - -// ----------------------------------------------------------------------------- - -void MadSource::skip(const int mSecs) -{ - if ( mSecs <= 0 ) - return; - - mad_header madHeader; - mad_header_init(&madHeader); - - for (;;) - { - if (!fetchData( m_inputFile, m_pMP3_Buffer, m_MP3_BufferSize, m_mad_stream)) - break; - - if ( mad_header_decode(&madHeader, &m_mad_stream) != 0 ) - { - if ( isRecoverable(m_mad_stream.error) ) - continue; - else - break; - } - - mad_timer_add(&m_mad_timer, madHeader.duration); - - if ( mad_timer_count(m_mad_timer, MAD_UNITS_MILLISECONDS) >= mSecs ) - break; - } - - mad_header_finish(&madHeader); -} - -// ----------------------------------------------------------- - -int MadSource::updateBuffer(signed short* pBuffer, size_t bufferSize) -{ - size_t nwrit = 0; //number of samples written to the output buffer - - for (;;) - { - // get a (valid) frame - // m_pcmpos == 0 could mean two things - // - we have completely decoded a frame, but the output buffer is still - // not full (it would make more sense for pcmpos == pcm.length(), but - // the loop assigns pcmpos = 0 at the end and does it this way! - // - we are starting a stream - if ( m_pcmpos == m_mad_synth.pcm.length ) - { - if ( !fetchData( m_inputFile, m_pMP3_Buffer, m_MP3_BufferSize, m_mad_stream) ) - { - break; // nothing else to read - } - - // decode the frame - if (mad_frame_decode (&m_mad_frame, &m_mad_stream)) - { - if ( isRecoverable(m_mad_stream.error) ) - continue; - else - break; - } // if (mad_frame_decode (&madFrame, &madStream)) - - mad_timer_add (&m_mad_timer, m_mad_frame.header.duration); - mad_synth_frame (&m_mad_synth, &m_mad_frame); - - m_pcmpos = 0; - } - - size_t samples_for_mp3 = m_mad_synth.pcm.length - m_pcmpos; - size_t samples_for_buf = bufferSize - nwrit; - signed short* pBufferIt = pBuffer + nwrit; - size_t i = 0, j = 0; - - switch( m_mad_synth.pcm.channels ) - { - case 1: - { - size_t samples_to_use = min (samples_for_mp3, samples_for_buf); - for (i = 0; i < samples_to_use; ++i ) - pBufferIt[i] = f2s( m_mad_synth.pcm.samples[0][i+m_pcmpos] ); - } - j = i; - break; - - case 2: - for (; i < samples_for_mp3 && j < samples_for_buf ; ++i, j+=2 ) - { - pBufferIt[j] = f2s( m_mad_synth.pcm.samples[0][i+m_pcmpos] ); - pBufferIt[j+1] = f2s( m_mad_synth.pcm.samples[1][i+m_pcmpos] ); - } - break; - - default: - cerr << "wtf kind of mp3 has " << m_mad_synth.pcm.channels << " channels??\n"; - break; - } - - m_pcmpos += i; - nwrit += j; - - assert( nwrit <= bufferSize ); - - if (nwrit == bufferSize) - return static_cast(nwrit); - } - - return static_cast(nwrit); -} - -// ----------------------------------------------------------------------------- - diff --git a/thirdparty/liblastfm2/src/fingerprint/contrib/MadSource.h b/thirdparty/liblastfm2/src/fingerprint/contrib/MadSource.h deleted file mode 100644 index c22cb6d5d..000000000 --- a/thirdparty/liblastfm2/src/fingerprint/contrib/MadSource.h +++ /dev/null @@ -1,69 +0,0 @@ -/* - Copyright 2009 Last.fm Ltd. - Copyright 2009 John Stamp - - This file is part of liblastfm. - - liblastfm is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - liblastfm is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with liblastfm. If not, see . -*/ - -#ifndef __MP3_SOURCE_H__ -#define __MP3_SOURCE_H__ - -#include -#include -#include -#include -#include -#include - - -class MadSource : public lastfm::FingerprintableSource -{ -public: - MadSource(); - ~MadSource(); - - virtual void getInfo(int& lengthSecs, int& samplerate, int& bitrate, int& nchannels); - virtual void init(const QString& fileName); - virtual int updateBuffer(signed short* pBuffer, size_t bufferSize); - virtual void skip(const int mSecs); - virtual void skipSilence(double silenceThreshold = 0.0001); - virtual bool eof() const { return m_inputFile.atEnd(); } - -private: - static bool fetchData( QFile& mp3File, - unsigned char* pMP3_Buffer, - const int MP3_BufferSize, - mad_stream& madStream ); - - static bool isRecoverable(const mad_error& error, bool log = false); - - static std::string MadErrorString(const mad_error& error); - - struct mad_stream m_mad_stream; - struct mad_frame m_mad_frame; - mad_timer_t m_mad_timer; - struct mad_synth m_mad_synth; - - QFile m_inputFile; - - unsigned char* m_pMP3_Buffer; - static const int m_MP3_BufferSize = (5*8192); - QString m_fileName; - - size_t m_pcmpos; -}; - -#endif diff --git a/thirdparty/liblastfm2/src/fingerprint/contrib/VorbisSource.cpp b/thirdparty/liblastfm2/src/fingerprint/contrib/VorbisSource.cpp deleted file mode 100644 index fd4defb17..000000000 --- a/thirdparty/liblastfm2/src/fingerprint/contrib/VorbisSource.cpp +++ /dev/null @@ -1,204 +0,0 @@ -/* - Copyright 2009 Last.fm Ltd. - Copyright 2009 John Stamp - - This file is part of liblastfm. - - liblastfm is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - liblastfm is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with liblastfm. If not, see . -*/ -#include "VorbisSource.h" -#include -#include -#include -#include -#include -#include -#include - -// These specify the output format -static const int wordSize = 2; // 16 bit output -static const int isSigned = 1; -#if __BIG_ENDIAN__ -static const int isBigEndian = 1; -#else -static const int isBigEndian = 0; -#endif - - -VorbisSource::VorbisSource() - : m_channels( 0 ) - , m_samplerate( 0 ) - , m_eof( false ) -{ - memset( &m_vf, 0, sizeof(m_vf) ); -} - -// --------------------------------------------------------------------- - -VorbisSource::~VorbisSource() -{ - // ov_clear() also closes the file - ov_clear( &m_vf ); -} - -// --------------------------------------------------------------------- - -void VorbisSource::init(const QString& fileName) -{ - m_fileName = fileName; - - if ( m_vf.datasource ) - { - std::cerr << "Warning: file already appears to be open"; - return; - } - - FILE *fp = fopen(QFile::encodeName(m_fileName), "rb" ); - if( !fp ) - throw std::runtime_error( "ERROR: Cannot open ogg file!" ); - - // See the warning about calling ov_open on Windows - if ( ov_test_callbacks( fp, &m_vf, NULL, 0, OV_CALLBACKS_DEFAULT ) < 0 ) - { - fclose( fp ); - throw std::runtime_error( "ERROR: This is not an ogg vorbis file!" ); - } - - ov_test_open( &m_vf ); - - // Don't fingerprint files with more than one logical bitstream - // They most likely contain more than one track - if ( ov_streams( &m_vf ) != 1 ) - throw std::runtime_error( "ERROR: ogg file contains multiple bitstreams" ); - - m_channels = ov_info( &m_vf, 0 )->channels; - m_samplerate = static_cast(ov_info( &m_vf, 0 )->rate); - m_eof = false; -} - -void VorbisSource::getInfo( int& lengthSecs, int& samplerate, int& bitrate, int& nchannels) -{ - // stream info - nchannels = ov_info( &m_vf, -1 )->channels; - samplerate = static_cast(ov_info( &m_vf, -1 )->rate); - lengthSecs = static_cast(ov_time_total( &m_vf, -1 ) + 0.5); - bitrate = static_cast(ov_bitrate( &m_vf, -1 )); -} - -// --------------------------------------------------------------------- - -void VorbisSource::skip( const int mSecs ) -{ - if ( mSecs < 0 ) - return; - - double ts = mSecs / 1000.0 + ov_time_tell( &m_vf ); - ov_time_seek( &m_vf, ts ); -} - -// --------------------------------------------------------------------- - -void VorbisSource::skipSilence(double silenceThreshold /* = 0.0001 */) -{ - silenceThreshold *= static_cast( std::numeric_limits::max() ); - - char sampleBuffer[4096]; - int bs = 0; - for (;;) - { - long charReadBytes = ov_read( &m_vf, sampleBuffer, 4096, isBigEndian, wordSize, isSigned, &bs ); - - // eof - if ( !charReadBytes ) - { - m_eof = true; - break; - } - if ( charReadBytes < 0 ) - { - // a bad bit of data: OV_HOLE || OV_EBADLINK - continue; - } - else if ( charReadBytes > 0 ) - { - double sum = 0; - int16_t *buf = reinterpret_cast(sampleBuffer); - switch ( m_channels ) - { - case 1: - for (long j = 0; j < charReadBytes/wordSize; j++) - sum += abs( buf[j] ); - break; - case 2: - for (long j = 0; j < charReadBytes/wordSize; j+=2) - sum += abs( (buf[j] >> 1) + (buf[j+1] >> 1) ); - break; - } - if ( sum >= silenceThreshold * static_cast(charReadBytes/wordSize/m_channels) ) - break; - } - } -} - -// --------------------------------------------------------------------- - -int VorbisSource::updateBuffer( signed short *pBuffer, size_t bufferSize ) -{ - char buf[ bufferSize * wordSize ]; - int bs = 0; - size_t charwrit = 0; //number of samples written to the output buffer - - for (;;) - { - long charReadBytes = ov_read( &m_vf, buf, static_cast(bufferSize * wordSize - charwrit), - isBigEndian, wordSize, isSigned, &bs ); - if ( !charReadBytes ) - { - m_eof = true; - break; // nothing else to read - } - - // Don't really need this though since we're excluding files that have - // more than one logical bitstream - if ( bs != 0 ) - { - vorbis_info *vi = ov_info( &m_vf, -1 ); - if ( m_channels != vi->channels || m_samplerate != vi->rate ) - { - std::cerr << "Files that change channel parameters or samplerate are currently not supported" << std::endl; - return 0; - } - } - - if( charReadBytes < 0 ) - { - std::cerr << "Warning: corrupt section of data, attempting to continue..." << std::endl; - continue; - } - - char* pBufferIt = reinterpret_cast(pBuffer) + charwrit; - charwrit += charReadBytes; - - assert( charwrit <= bufferSize * wordSize ); - memcpy( pBufferIt, buf, charReadBytes ); - - if (charwrit == bufferSize * wordSize) - return static_cast(charwrit/wordSize); - } - - return static_cast(charwrit/wordSize); -} - -// ----------------------------------------------------------------------------- - diff --git a/thirdparty/liblastfm2/src/fingerprint/contrib/VorbisSource.h b/thirdparty/liblastfm2/src/fingerprint/contrib/VorbisSource.h deleted file mode 100644 index 988ce6239..000000000 --- a/thirdparty/liblastfm2/src/fingerprint/contrib/VorbisSource.h +++ /dev/null @@ -1,47 +0,0 @@ -/* - Copyright 2009 Last.fm Ltd. - Copyright 2009 John Stamp - - This file is part of liblastfm. - - liblastfm is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - liblastfm is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with liblastfm. If not, see . -*/ -#ifndef __VORBIS_SOURCE_H__ -#define __VORBIS_SOURCE_H__ - -#include -#include - - -class VorbisSource : public lastfm::FingerprintableSource -{ -public: - VorbisSource(); - ~VorbisSource(); - virtual void getInfo(int& lengthSecs, int& samplerate, int& bitrate, int& nchannels); - virtual void init(const QString& fileName); - virtual int updateBuffer(signed short* pBuffer, size_t bufferSize); - virtual void skip(const int mSecs); - virtual void skipSilence(double silenceThreshold = 0.0001); - virtual bool eof() const { return m_eof; } - -private: - OggVorbis_File m_vf; - QString m_fileName; - int m_channels; - int m_samplerate; - bool m_eof; -}; - -#endif diff --git a/thirdparty/liblastfm2/src/fingerprint/contrib/lastfm-fingerprint.pro b/thirdparty/liblastfm2/src/fingerprint/contrib/lastfm-fingerprint.pro deleted file mode 100644 index bd615e723..000000000 --- a/thirdparty/liblastfm2/src/fingerprint/contrib/lastfm-fingerprint.pro +++ /dev/null @@ -1,13 +0,0 @@ -QT = core xml network -LIBS += -L$$DESTDIR -llastfm -llastfm_fingerprint -LIBS += -lvorbisfile -lFLAC -lfaad -lmp4ff -lmad -SOURCES = AacSource.cpp FlacSource.cpp MadSource.cpp VorbisSource.cpp main.cpp - -mac { - INCLUDEPATH += /opt/local/include - LIBS += -L/opt/local/lib - - DEFINES += MACPORTS_SUCKS - SOURCES -= AacSource.cpp - LIBS -= -lmp4ff -} diff --git a/thirdparty/liblastfm2/src/fingerprint/contrib/main.cpp b/thirdparty/liblastfm2/src/fingerprint/contrib/main.cpp deleted file mode 100644 index 3b035f2d8..000000000 --- a/thirdparty/liblastfm2/src/fingerprint/contrib/main.cpp +++ /dev/null @@ -1,173 +0,0 @@ -/* - Copyright 2009 Last.fm Ltd. - Copyright 2009 John Stamp - - This file is part of liblastfm. - - liblastfm is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - liblastfm is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with liblastfm. If not, see . -*/ - -// ubuntu 9.04: sudo apt-get install libmad0-dev libvorbis-dev libflac-dev libfaac-dev -// macports: sudo port install libmad libvorbis libflac -// Windows: lol - -#include "MadSource.h" -#include "VorbisSource.h" -#include "FlacSource.h" -#include "AacSource.h" -#include -#include -#include -#include -#include -int typeOf(const QString& path); -lastfm::FingerprintableSource* factory(int type); -enum { MP3, OGG, FLAC, AAC, UNKNOWN }; -namespace lastfm { Track taglib(const QString& path); } - - -int main(int argc, char** argv) try -{ - if (argc < 2) { - std::cerr << "usage: " << argv[0] << " path" << std::endl; - return 1; - } - - QCoreApplication app(argc, argv); - QEventLoop loop; - - QString const path = QFile::decodeName(argv[1]); - - lastfm::Track t = lastfm::taglib(path); //see contrib //TODO mbid - lastfm::Fingerprint fp(t); - if (fp.id().isNull()) { - lastfm::FingerprintableSource* src = factory(typeOf(path)); - fp.generate(src); - QNetworkReply* reply = fp.submit(); - loop.connect(reply, SIGNAL(finished()), SLOT(quit())); - fp.decode(reply); - } - - QNetworkReply* reply = fp.id().getSuggestions(); - loop.connect(reply, SIGNAL(finished()), SLOT(quit())); - - std::cout << reply->readAll().data() << std::endl; //returns XML - return 0; -} -catch (std::exception& e) -{ - std::cerr << e.what() << std::endl; -} - -lastfm::FingerprintableSource* factory(int type) -{ - switch (type) { - case MP3: return new MadSource; - case OGG: return new VorbisSource; - case FLAC: return new FlacSource; - #ifndef MACPORTS_SUCKS - case AAC: return new AacSource; - #endif - default: throw std::runtime_error("Cannot handle filetype"); - } -} - -int typeOf(const QString& fileName) -{ - QStringList parts = fileName.split( "." ); - QString extension; - if ( parts.size() > 1 ) - extension = parts.last(); - - // Let's be trusting about extensions - if ( extension.toLower() == "mp3" ) - return MP3; - else if ( extension.toLower() == "ogg" ) - return OGG; - else if ( extension.toLower() == "oga" ) - return FLAC; - else if ( extension.toLower() == "flac" ) - return FLAC; - else if ( extension.toLower() == "aac" ) - return AAC; - else if ( extension.toLower() == "m4a" ) - return AAC; - - // So much for relying on extensions. Let's try file magic instead. - FILE *fp = NULL; - unsigned char header[35]; - - fp = fopen(QFile::encodeName(fileName), "rb"); - if ( !fp ) - { - return UNKNOWN; - } - int fType = UNKNOWN; - fread( header, 1, 35, fp ); - - // Some formats can have ID3 tags (or not), so let's just - // get them out of the way first before we check what we have. - if ( memcmp( header, "ID3", 3) == 0 ) - { - int tagsize = 0; - /* high bit is not used */ - tagsize = (header[6] << 21) | (header[7] << 14) | - (header[8] << 7) | (header[9] << 0); - - tagsize += 10; - fseek( fp, tagsize, SEEK_SET ); - fread( header, 1, 35, fp ); - } - - if ( (header[0] == 0xFF) && ((header[1] & 0xFE) == 0xFA ) ) - { - fType = MP3; - } - else if ( memcmp(header, "OggS", 4) == 0 ) - { - if ( memcmp(&header[29], "vorbis", 6) == 0 ) - { - // ogg vorbis (.ogg) - fType = OGG; - } - else if ( memcmp(&header[29], "FLAC", 4) == 0 ) - { - // ogg flac (.oga) - fType = FLAC; - } - } - else if ( memcmp(header, "fLaC", 4 ) == 0 ) - { - // flac file - fType = FLAC; - } - else if ( (header[0] == 0xFF) && ((header[1] & 0xF6) == 0xF0) ) - { - // aac adts - fType = AAC; - } - else if (memcmp(header, "ADIF", 4) == 0) - { - // aac adif - fType = AAC; - } - else if ( memcmp( &header[4], "ftyp", 4 ) == 0 ) - { - // mp4 header: aac - fType = AAC; - } - - fclose(fp); - return fType; -} diff --git a/thirdparty/liblastfm2/src/fingerprint/fingerprint.pro b/thirdparty/liblastfm2/src/fingerprint/fingerprint.pro deleted file mode 100644 index 043ad7bfb..000000000 --- a/thirdparty/liblastfm2/src/fingerprint/fingerprint.pro +++ /dev/null @@ -1,25 +0,0 @@ -TEMPLATE = lib -TARGET = lastfm_fingerprint -LIBS += -L$$DESTDIR -llastfm -QT = core xml network sql -include( _files.qmake ) -DEFINES += LASTFM_FINGERPRINT_LIB - -INSTALLS = target -target.path = /lib - -mac:CONFIG( app_bundle ) { - LIBS += libfftw3f.a libsamplerate.a -L/opt/local/include - INCLUDEPATH += /opt/local/include:/opt/qt/qt-current/lib/QtSql.framework/Include/ -}else{ - INCLUDEPATH += /opt/qt/qt-current/lib/QtSql.framework/Include/ - CONFIG += link_pkgconfig - PKGCONFIG += samplerate - win32 { - CONFIG += link_pkgconfig - DEFINES += __NO_THREAD_CHECK - QMAKE_LFLAGS_DEBUG += /NODEFAULTLIB:msvcrt.lib /NODEFAULTLIB:libcmt.lib - } - PKGCONFIG += fftw3f - -} diff --git a/thirdparty/liblastfm2/src/fingerprint/fplib/CircularArray.h b/thirdparty/liblastfm2/src/fingerprint/fplib/CircularArray.h deleted file mode 100644 index bfec5a8fd..000000000 --- a/thirdparty/liblastfm2/src/fingerprint/fplib/CircularArray.h +++ /dev/null @@ -1,292 +0,0 @@ -/* - Copyright 2005-2009 Last.fm Ltd. - - This file is part of liblastfm. - - liblastfm is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - liblastfm is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with liblastfm. If not, see . -*/ -#ifndef __CIRCULAR_ARRAY_H -#define __CIRCULAR_ARRAY_H - -#include -#include -#include -#include -#include // for memset -#include // for max - -#ifndef NULL -#define NULL 0 -#endif - -template< typename T > -class CircularArray -{ - -public: - - typedef size_t size_type; - - ///////////////////////////////////////////////////////////// - - // IMPORTANT: The distance must be redefined!! - // See declaration of iterator from stl_iterator_base_types.h: - // template - // struct iterator { ... - - // ---------- Forward declarations - - class iterator : - public std::iterator - { - // it should be by default because is an inner class, but I put it just to be sure.. - friend class CircularArray; - - private: - iterator( size_type idx, T* pData, size_type size ) : _idx(idx), _pData(pData), _size(size) {} - - public: - - //typedef random_access_iterator_tag iterator_category; - - iterator() : _idx(0), _pData(NULL) {} - - iterator& operator++() - { // preincrement - _idx = (_idx + 1) % _size; - return (*this); - } - - iterator operator++(int) - { // postincrement - iterator _Tmp = *this; - _idx = (_idx + 1) % _size; - return (_Tmp); - } - - void operator+=(size_type offs) - { - this->_idx = (_idx + offs) % _size; - } - - iterator operator+(size_type offs) const - { - size_type newIdx = (_idx + offs) % _size; - iterator _Tmp(newIdx, _pData, _size); - return _Tmp; - } - - // return the distance between this iterator and it - size_t operator-(const iterator& it) const - { - if ( this->_idx > it._idx ) - return this->_idx - it._idx; - else - return this->_idx + (_size - it._idx); - } - - iterator operator-(size_type offs) const - { - size_type newIdx; - - if ( offs <= _idx ) - newIdx = _idx - offs; - else - newIdx = _size - ((_idx - offs) % _size); // note: should be ok, but to be checked better - - iterator _Tmp(newIdx, _pData, _size); - return _Tmp; - } - - iterator& operator--() - { // predecrement - if (_idx == 0) - _idx = _size - 1; - else - --_idx; - return (*this); - } - - iterator operator--(int) - { // postdecrement - iterator _Tmp = *this; - if (_idx == 0) - _idx = _size - 1; - else - --_idx; - return (_Tmp); - } - - T& operator*() const - { // return designated object - return _pData[_idx]; - } - - T* operator->() const - { // return pointer to class object - return &_pData[_idx]; - } - - /* T& operator=(const T& right) - { // assign reference right to _val - return ( this->_idx = right._idx ); - }*/ - - bool operator==(const iterator& right) const - { // test for iterator equality - return ( this->_idx == right._idx ); - } - - bool operator!=(const iterator& right) const - { // test for iterator inequality - return ( this->_idx != right._idx ); - } - - protected: - size_type _idx; - T* _pData; - size_type _size; - }; - - ///////////////////////////////////////////////////////////// - - - CircularArray() - : _headIdx(0), _pData(NULL), _size(0) - { } - - CircularArray( size_type size ) - : _headIdx(0), _pData(NULL) - { - this->resize(size); - } - - CircularArray( size_type size, const T& init ) - : _headIdx(0), _pData(NULL) - { - this->resize(size, init); - } - - ~CircularArray() - { - this->clear(); - } - - // remember: it is not working (yet!) with negative numbers! - T& operator[](size_type offset) - { - return _pData[ (_headIdx + offset) % _size ]; - } - - void resize( size_type size ) - { - _headIdx = 0; - if ( size == _size ) - return; - - this->clear(); - _pData = new T[size]; - _size = size; - } - - void resize( size_type size, const T& init ) - { - this->resize(size, false); - this->fill(init); - } - - void fill( const T& val ) - { - for (size_type i=0; i<_size; ++i) - _pData[i] = val; - } - - void zero_fill() - { - memset( _pData, 0, _size * sizeof(T) ); - } - - bool empty() const - { - return ( _pData == NULL ); - } - - void clear() - { - if (_pData) - delete [] _pData; - _pData = NULL; - _headIdx = 0; - _size = 0; - } - - iterator head() const - { - if (_pData == NULL) - std::cerr << "WARNING: iterator in CircularArray points to an empty CircularArray" << std::endl; - return iterator(_headIdx, _pData, _size); - } - - void shift_head( int offset ) - { - if ( offset < 0) - { - int mod = (-offset) % (int)_size; - mod -= (int)_headIdx; - _headIdx = _size - mod; - } - else - _headIdx = (_headIdx + offset) % _size; - } - - size_type size() const - { - return _size; - } - - //// to be changed to an input forward iterator - //template - //void get_data( TIterator toFillIt, size_type size = 0 ) - //{ - // if ( size == 0 ) - // size = _size; - // iterator it = head(); - // - // for (size_type i = 0; i < size; ++i) - // *(toFillIt++) = *(it++); - //} - - // IMPORTANT! Destination buffer MUST be the same size! - void copy_buffer( T* pDest ) - { - memcpy( pDest, _pData, sizeof(T)*_size ); - } - - // returns the buffer - T* get_buffer() const - { - return _pData; - } - - -private: - - size_type _headIdx; // index - T* _pData; // array of data - size_type _size; // size of data - -}; - -#endif // __CIRCULAR_ARRAY_H diff --git a/thirdparty/liblastfm2/src/fingerprint/fplib/Filter.cpp b/thirdparty/liblastfm2/src/fingerprint/fplib/Filter.cpp deleted file mode 100644 index eed4ea3a3..000000000 --- a/thirdparty/liblastfm2/src/fingerprint/fplib/Filter.cpp +++ /dev/null @@ -1,128 +0,0 @@ -/* - Copyright 2005-2009 Last.fm Ltd. - - This file is part of liblastfm. - - liblastfm is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - liblastfm is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with liblastfm. If not, see . -*/ -#include -#include // for max -#include - -#include "Filter.h" -#include "fp_helper_fun.h" - -using namespace std; - -namespace fingerprint -{ - -Filter::Filter(unsigned int id, float threshold, float weight) -: id(id), threshold(threshold), weight(weight) -{ - float time_rate = 1.5; - - unsigned int t = 1; - vector time_lengths; - - while (t < KEYWIDTH) - { - time_lengths.push_back(t); - t = max( static_cast( round__(time_rate*t) ) + - static_cast( round__(time_rate*t) % 2), - t+1 ); - } - - unsigned int filter_count = 0; - - for (wt = 1; wt <= time_lengths.size(); wt++) - { - for (wb = 1; wb <= NBANDS; wb++) - { - for (first_band = 1; first_band <= NBANDS - wb + 1; - first_band++) - { - unsigned int time = time_lengths[wt-1]; - filter_count++; - - if (filter_count == id) - { - wt = time_lengths[wt-1]; - filter_type = 1; - return; - } - - if (time > 1) - { - filter_count++; - if (filter_count == id) - { - wt = time_lengths[wt-1]; - filter_type = 2; - return; - } - } - - if (wb > 1) - { - filter_count++; - if (filter_count == id) - { - wt = time_lengths[wt-1]; - filter_type = 3; - return; - } - } - - if (time > 1 && wb > 1) - { - filter_count++; - if (filter_count == id) - { - wt = time_lengths[wt-1]; - filter_type = 4; - return; - } - } - - if (time > 3) - { - filter_count++; - if (filter_count == id) - { - wt = time_lengths[wt-1]; - filter_type = 5; - return; - } - } - - if (wb > 3) - { - filter_count++; - if (filter_count == id) - { - wt = time_lengths[wt-1]; - filter_type = 6; - return; - } - } - - } // for first_band - } // for wb - } // for wt -} - -} // end of namespace fingerprint - -// ----------------------------------------------------------------------------- diff --git a/thirdparty/liblastfm2/src/fingerprint/fplib/Filter.h b/thirdparty/liblastfm2/src/fingerprint/fplib/Filter.h deleted file mode 100644 index 04185eec2..000000000 --- a/thirdparty/liblastfm2/src/fingerprint/fplib/Filter.h +++ /dev/null @@ -1,47 +0,0 @@ -/* - Copyright 2005-2009 Last.fm Ltd. - - This file is part of liblastfm. - - liblastfm is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - liblastfm is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with liblastfm. If not, see . -*/ -#ifndef __FILTER_H -#define __FILTER_H - -namespace fingerprint -{ - -struct Filter -{ - /// Constructs a new filter with id. - Filter(unsigned int id, float threshold, float weight); - - unsigned int id; //< filter id - unsigned int wt; //< time width - unsigned int first_band; //< first band - unsigned int wb; //< band width - unsigned int filter_type; //< filter type - - float threshold; //< threshold for filter - float weight; //< filter weight - - // number of frames in time - static const unsigned int KEYWIDTH = 100; - // number of bands to divide the signal (log step) - static const unsigned int NBANDS = 33; -}; - -} - -#endif // __FILTER_H diff --git a/thirdparty/liblastfm2/src/fingerprint/fplib/FingerprintExtractor.cpp b/thirdparty/liblastfm2/src/fingerprint/fplib/FingerprintExtractor.cpp deleted file mode 100644 index 305aad7b5..000000000 --- a/thirdparty/liblastfm2/src/fingerprint/fplib/FingerprintExtractor.cpp +++ /dev/null @@ -1,786 +0,0 @@ -/* - Copyright 2005-2009 Last.fm Ltd. - - This file is part of liblastfm. - - liblastfm is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - liblastfm is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with liblastfm. If not, see . -*/ -#include -#include -#include -#include -#include -#include -#include -#include - -#include // libsamplerate - -#include "FingerprintExtractor.h" -#include "fp_helper_fun.h" // for GroupData -#include "Filter.h" -#include "FloatingAverage.h" -#include "OptFFT.h" - -////////////////////////////////////////////////////////////////////////// - -namespace fingerprint -{ - -using namespace std; -static const int NUM_FRAMES_CLIENT = 32; // ~= 10 secs. - -enum eProcessType -{ - PT_UNKNOWN, - PT_FOR_QUERY, - PT_FOR_FULLSUBMIT -}; - -////////////////////////////////////////////////////////////////////////// - -class PimplData -{ - -public: - - PimplData() - : m_pDownsampledPCM(NULL), m_pDownsampledCurrIt(NULL), - m_normalizedWindowMs(static_cast(NORMALIZATION_SKIP_SECS * 1000 * 2)), - m_compensateBufferSize(FRAMESIZE-OVERLAPSAMPLES + Filter::KEYWIDTH * OVERLAPSAMPLES), - m_downsampledProcessSize(NUM_FRAMES_CLIENT*FRAMESIZE), - // notice that the buffer has extra space on either side for the normalization window - m_fullDownsampledBufferSize( m_downsampledProcessSize + // the actual processed part - m_compensateBufferSize + // a compensation buffer for the fft - ((m_normalizedWindowMs * DFREQ / 1000) / 2) ), // a compensation buffer for the normalization - m_normWindow(m_normalizedWindowMs * DFREQ / 1000), - m_pFFT(NULL), m_pDownsampleState(NULL), m_processType(PT_UNKNOWN) - { - m_pFFT = new OptFFT(m_downsampledProcessSize + m_compensateBufferSize); - m_pDownsampledPCM = new float[m_fullDownsampledBufferSize]; - - // the end of ||-------m_bufferSize-------|-cb-|---norm/2---|| - // ^-- pEndDownsampledBuf - m_pEndDownsampledBuf = m_pDownsampledPCM + m_fullDownsampledBufferSize; - - // loading filters - size_t numFilters = sizeof(rFilters) / sizeof(RawFilter) ; - for (size_t i = 0; i < numFilters; ++i) - m_filters.push_back( Filter( rFilters[i].ftid, rFilters[i].thresh, rFilters[i].weight ) ); - - } - - ~PimplData() - { - if ( m_pFFT ) - delete m_pFFT; - m_pFFT = NULL; - if ( m_pDownsampledPCM ) - delete [] m_pDownsampledPCM; - m_pDownsampledPCM = NULL; - - if ( m_pDownsampleState ) - src_delete(m_pDownsampleState) ; - - } - - float* m_pDownsampledPCM; - float* m_pDownsampledCurrIt; - - const unsigned int m_normalizedWindowMs; - const size_t m_compensateBufferSize; - const size_t m_downsampledProcessSize; - const size_t m_fullDownsampledBufferSize; - - FloatingAverage m_normWindow; - OptFFT* m_pFFT; - - ////////////////////////////////////////////////////////////////////////// - - // libsamplerate - SRC_STATE* m_pDownsampleState; - SRC_DATA m_downsampleData; - - vector m_floatInData; - - ////////////////////////////////////////////////////////////////////////// - - - bool m_groupsReady; - bool m_preBufferPassed; - - eProcessType m_processType; - - size_t m_toSkipSize; - size_t m_toSkipMs; - - size_t m_skippedSoFar; - bool m_skipPassed; - - float* m_pEndDownsampledBuf; - - int m_freq; - int m_nchannels; - - unsigned int m_lengthMs; - int m_minUniqueKeys; - unsigned int m_uniqueKeyWindowMs; - - unsigned int m_toProcessKeys; - unsigned int m_totalWindowKeys; - - vector m_filters; - - deque m_groupWindow; - vector m_groups; - unsigned int m_processedKeys; - - vector m_partialBits; // here just to avoid reallocation - -#if __BIG_ENDIAN__ - -#define reorderbits(X) ((((unsigned int)(X) & 0xff000000) >> 24) | \ - (((unsigned int)(X) & 0x00ff0000) >> 8) | \ - (((unsigned int)(X) & 0x0000ff00) << 8) | \ - (((unsigned int)(X) & 0x000000ff) << 24)) - - vector m_bigEndianGroups; -#endif -}; - -////////////////////////////////////////////////////////////////////////// - -void initCustom( PimplData& pd, - int freq, int nchannels, - unsigned int lengthMs, unsigned int skipMs, - int minUniqueKeys, unsigned int uniqueKeyWindowMs, int duration ); - -inline float getRMS( const FloatingAverage& signal ); -unsigned int processKeys( deque& groups, size_t size, PimplData& pd ); -void integralImage( float** ppFrames, unsigned int nFrames ); -void computeBits( vector& bits, - const vector& f, - float ** frames, unsigned int nframes ); - - -void src_short_to_float_and_mono_array(const short *in, float *out, int srclen, int nchannels); - -////////////////////////////////////////////////////////////////////////// - -// ----------------------------------------------------------------------------- - -FingerprintExtractor::FingerprintExtractor() -: m_pPimplData(NULL) -{ - m_pPimplData = new PimplData(); -} - -// ----------------------------------------------------------------------------- - -FingerprintExtractor::~FingerprintExtractor() -{ - if ( m_pPimplData ) - delete m_pPimplData; -} - -// ----------------------------------------------------------------------------- - -size_t FingerprintExtractor::getToSkipMs() -{ return m_pPimplData->m_toSkipMs; } - -// ----------------------------------------------------------------------------- - -size_t FingerprintExtractor::getMinimumDurationMs() -{ - return static_cast( (QUERY_SIZE_SECS + NORMALIZATION_SKIP_SECS * 2 + GUARD_SIZE_SECS) * 1000 ); -} - -// ----------------------------------------------------------------------------- - -size_t FingerprintExtractor::getVersion() -{ return FINGERPRINT_LIB_VERSION; } - -// ----------------------------------------------------------------------------- - -void FingerprintExtractor::initForQuery(int freq, int nchannels, int duration ) -{ - m_pPimplData->m_skipPassed = false; - m_pPimplData->m_processType = PT_FOR_QUERY; - - if ( !m_pPimplData ) - throw std::runtime_error("Not enough RAM to allocate the fingerprinter!"); - - initCustom( *m_pPimplData, - freq, nchannels, - static_cast(QUERY_SIZE_SECS * 1000), - static_cast(QUERY_START_SECS * 1000), - MIN_UNIQUE_KEYS, - static_cast(UPDATE_SIZE_SECS * 1000), duration ); -} - -// ----------------------------------------------------------------------------- - -void FingerprintExtractor::initForFullSubmit(int freq, int nchannels ) -{ - m_pPimplData->m_skipPassed = true; - m_pPimplData->m_processType = PT_FOR_FULLSUBMIT; - - if ( !m_pPimplData ) - throw std::runtime_error("Not enough RAM to allocate the fingerprinter!"); - - initCustom( *m_pPimplData, - freq, nchannels, - numeric_limits::max(), - 0, MIN_UNIQUE_KEYS, 0, -1 ); -} - -// ----------------------------------------------------------------------------- - -void initCustom( PimplData& pd, - int freq, int nchannels, - unsigned int lengthMs, - unsigned int skipMs, - int minUniqueKeys, - unsigned int uniqueKeyWindowMs, int duration ) -{ - ////////////////////////////////////////////////////////////////////////// - pd.m_freq = freq; - pd.m_nchannels = nchannels; - pd.m_lengthMs = lengthMs; - pd.m_minUniqueKeys = minUniqueKeys; - pd.m_uniqueKeyWindowMs = uniqueKeyWindowMs; - ////////////////////////////////////////////////////////////////////////// - - // *********************************************************************** - if ( pd.m_pDownsampleState ) - pd.m_pDownsampleState = src_delete(pd.m_pDownsampleState) ; - pd.m_pDownsampleState = src_new (SRC_SINC_FASTEST, 1, NULL) ; - pd.m_downsampleData.src_ratio = FDFREQ / freq; - // *********************************************************************** - - ////////////////////////////////////////////////////////////////////////// - if ( pd.m_processType == PT_FOR_FULLSUBMIT ) - skipMs = 0; // make sure - else if ( duration > 0 ) - { - // skip + size + right normalization window + FFT guard - // - int stdDurationMs = static_cast((QUERY_START_SECS + QUERY_SIZE_SECS + NORMALIZATION_SKIP_SECS + GUARD_SIZE_SECS) * 1000); - int actualDurationMs = duration * 1000; - // compute the actual skipMs depending on the duration - if ( actualDurationMs < stdDurationMs ) - skipMs -= max( stdDurationMs - actualDurationMs, 0 ); - } - - pd.m_toSkipMs = max( static_cast(skipMs) - static_cast((pd.m_normalizedWindowMs/2)), 0 ); - pd.m_toSkipSize = static_cast( freq * nchannels * - (pd.m_toSkipMs / 1000.0) ); // half the norm window in secs; - - //if ( pd.m_processType == PT_FOR_QUERY && skipMs > pd.m_normalizedWindowMs/2 ) - //{ - // pd.m_toSkipMs = skipMs - (pd.m_normalizedWindowMs/2); - // pd.m_toSkipSize = static_cast( freq * nchannels * - // (pd.m_toSkipMs / 1000.0) ); // half the norm window in secs - //} - //else - //{ - // pd.m_toSkipMs = 0; - // pd.m_toSkipSize = 0; // half of the normalization window will be skipped in ANY case - //} - - pd.m_skippedSoFar = 0; - pd.m_groupsReady = false; - pd.m_preBufferPassed = false; - - // prepare the position for pre-buffering - pd.m_pDownsampledCurrIt = pd.m_pDownsampledPCM + (pd.m_downsampledProcessSize - (pd.m_normWindow.size() / 2) ); - - pd.m_toProcessKeys = fingerprint::getTotalKeys(pd.m_lengthMs);// (m_lengthMs * DFREQ) / (1000 * OVERLAPSAMPLES) + 1; - pd.m_totalWindowKeys = fingerprint::getTotalKeys(pd.m_uniqueKeyWindowMs); //(m_uniqueKeyWindowMs * DFREQ) / (1000 * OVERLAPSAMPLES) + 1; - - if (pd.m_toProcessKeys == 1) - pd.m_toProcessKeys = 0; - if (pd.m_totalWindowKeys == 1) - pd.m_totalWindowKeys = 0; - - pd.m_processedKeys = 0; - - pd.m_groupWindow.clear(); - pd.m_processedKeys = 0; -} - -// ----------------------------------------------------------------------------- - - -// * cb = compensate buffer size -// * norm = floating normalization window size -// -// PREBUFFER: -// (-------m_bufferSize-------) -// || EMPTY |---norm/2---|-cb-|---norm/2---|| -// 1. {--------read frames-----------} -// 2. {--read normalize window--} -// 3. {----} normalize -// -// 1. read [norm + cb] frames to m_bufferSize - norm/2 -// 2. read [m_buffersize - norm/2...m_buffersize + norm/2] into normalize window -// 3. normalize [m_bufferSize..m_bufferSize+cb] -// -// PROCESS: -// -// ||-------m_bufferSize-------|-cb-|---norm/2---|| -// 1. <--------------------------{------copy-------} -// 2. {--------read frames-------} -// 3. {---------normalize--------} -// 4. {------fft/process/whatevs------} -// -// 1. copy [m_bufferSize..m_bufferSize + cb + norm/2] to beginning -// 2. read m_bufferSize frames to cb + norm/2 -// 3. normalize [cb..m_bufferSize+cb] -// 4. fft/process/whatevs [0...m_bufferSize+cb] -// -// repeat until enough blocks processed and enough groups! -// -bool FingerprintExtractor::process( const short* pPCM, size_t num_samples, bool end_of_stream ) -{ - if ( num_samples == 0 ) - return false; - - // easier read - PimplData& pd = *m_pPimplData; - - if ( pd.m_processType == PT_UNKNOWN ) - throw std::runtime_error("Please call initForQuery() or initForFullSubmit() before process()!"); - - const short* pSourcePCMIt = pPCM; - const short* pSourcePCMIt_end = pPCM + num_samples; - - if ( !pd.m_skipPassed ) - { - // needs to skip data? (reminder: the query needs to skip QUERY_START_SECS (- half of the normalization window) - if ( pd.m_skippedSoFar + num_samples > pd.m_toSkipSize ) - { - pSourcePCMIt = pPCM + (pd.m_toSkipSize - pd.m_skippedSoFar); - pd.m_skipPassed = true; - } - else - { - // need more data - pd.m_skippedSoFar += num_samples; - return false; - } - } - - pair readData(0,0); - pd.m_downsampleData.end_of_input = end_of_stream ? 1 : 0; - - ////////////////////////////////////////////////////////////////////////// - // PREBUFFER: - if ( !pd.m_preBufferPassed ) - { - // 1. downsample [norm + cb] frames to m_bufferSize - norm/2 - pd.m_floatInData.resize( (pSourcePCMIt_end - pSourcePCMIt) / pd.m_nchannels); - src_short_to_float_and_mono_array( pSourcePCMIt, - &(pd.m_floatInData[0]), static_cast(pSourcePCMIt_end - pSourcePCMIt), - pd.m_nchannels); - - pd.m_downsampleData.data_in = &(pd.m_floatInData[0]); - pd.m_downsampleData.input_frames = static_cast(pd.m_floatInData.size()); - - pd.m_downsampleData.data_out = pd.m_pDownsampledCurrIt; - pd.m_downsampleData.output_frames = static_cast(pd.m_pEndDownsampledBuf - pd.m_pDownsampledCurrIt); - - int err = src_process(pd.m_pDownsampleState, &(pd.m_downsampleData)); - if ( err ) - throw std::runtime_error( src_strerror(err) ); - - pd.m_pDownsampledCurrIt += pd.m_downsampleData.output_frames_gen; - - if ( pd.m_pDownsampledCurrIt != pd.m_pEndDownsampledBuf ) - return false; // NEED MORE DATA - - pSourcePCMIt += pd.m_downsampleData.input_frames_used * pd.m_nchannels; - - size_t pos = pd.m_downsampledProcessSize; - size_t window_pos = pd.m_downsampledProcessSize - pd.m_normWindow.size() / 2; - const size_t end_window_pos = window_pos + pd.m_normWindow.size(); - - // 2. read [m_buffersize - norm/2...m_buffersize + norm/2] into normalize window - for (; window_pos < end_window_pos ; ++window_pos) - pd.m_normWindow.add(pd.m_pDownsampledPCM[window_pos] * pd.m_pDownsampledPCM[window_pos]); - - // 3. normalize [m_bufferSize..m_bufferSize+cb] - for (; pos < pd.m_downsampledProcessSize + pd.m_compensateBufferSize; ++pos, ++window_pos) - { - pd.m_pDownsampledPCM[pos] /= getRMS(pd.m_normWindow); - pd.m_normWindow.add(pd.m_pDownsampledPCM[window_pos] * pd.m_pDownsampledPCM[window_pos]); - } - - pd.m_preBufferPassed = true; - } - - ////////////////////////////////////////////////////////////////////////// - // PROCESS: - - bool found_enough_unique_keys = false; - while (pd.m_toProcessKeys == 0 || pd.m_processedKeys < pd.m_toProcessKeys || !found_enough_unique_keys) - { - - // 1. copy [m_bufferSize..m_bufferSize + cb + norm/2] to beginning - if ( pd.m_pDownsampledCurrIt == pd.m_pEndDownsampledBuf ) - { - memcpy( pd.m_pDownsampledPCM, pd.m_pDownsampledPCM + pd.m_downsampledProcessSize, - (pd.m_compensateBufferSize + (pd.m_normWindow.size() / 2)) * sizeof(float)); - pd.m_pDownsampledCurrIt = pd.m_pDownsampledPCM + (pd.m_compensateBufferSize + (pd.m_normWindow.size() / 2)); - } - - // 2. read m_bufferSize frames to cb + norm/2 - pd.m_floatInData.resize( (pSourcePCMIt_end - pSourcePCMIt) / pd.m_nchannels); - - if ( pd.m_floatInData.empty() ) - return false; - - src_short_to_float_and_mono_array( pSourcePCMIt, - &(pd.m_floatInData[0]), static_cast(pSourcePCMIt_end - pSourcePCMIt), - pd.m_nchannels); - - pd.m_downsampleData.data_in = &(pd.m_floatInData[0]); - pd.m_downsampleData.input_frames = static_cast(pd.m_floatInData.size()); - - pd.m_downsampleData.data_out = pd.m_pDownsampledCurrIt; - pd.m_downsampleData.output_frames = static_cast(pd.m_pEndDownsampledBuf - pd.m_pDownsampledCurrIt); - - int err = src_process(pd.m_pDownsampleState, &(pd.m_downsampleData)); - if ( err ) - throw std::runtime_error( src_strerror(err) ); - - pd.m_pDownsampledCurrIt += pd.m_downsampleData.output_frames_gen; - - if ( pd.m_pDownsampledCurrIt != pd.m_pEndDownsampledBuf && !end_of_stream ) - return false; // NEED MORE DATA - - //pSourcePCMIt += readData.second; - pSourcePCMIt += pd.m_downsampleData.input_frames_used * pd.m_nchannels; - - // ******************************************************************** - - // 3. normalize [cb..m_bufferSize+cb] - size_t pos = static_cast(pd.m_compensateBufferSize); - size_t window_pos = static_cast(pd.m_compensateBufferSize + (pd.m_normWindow.size() / 2)); - - for(; pos < pd.m_downsampledProcessSize + pd.m_compensateBufferSize /* m_fullDownsampledBufferSize*/; ++pos, ++window_pos) - { - pd.m_pDownsampledPCM[pos] /= getRMS(pd.m_normWindow); - pd.m_normWindow.add(pd.m_pDownsampledPCM[window_pos] * pd.m_pDownsampledPCM[window_pos]); - } - - // 4. fft/process/whatevs [0...m_bufferSize+cb] - pd.m_processedKeys += processKeys(pd.m_groupWindow, pos, pd); - - // we have too many keys, now we have to chop either one end or the other - if (pd.m_toProcessKeys != 0 && pd.m_processedKeys > pd.m_toProcessKeys) - { - // set up window begin and end - deque::iterator itBeg = pd.m_groupWindow.begin(), itEnd = pd.m_groupWindow.end(); - unsigned int offset_left, offset_right; - - found_enough_unique_keys = - fingerprint::findSignificantGroups( itBeg, itEnd, offset_left, offset_right, pd.m_toProcessKeys, - pd.m_totalWindowKeys, pd.m_minUniqueKeys); - - // if we're happy with this set, snip the beginning and end of the grouped keys - if (found_enough_unique_keys) - { - itBeg->count -= offset_left; - if (offset_right > 0 && itEnd != pd.m_groupWindow.end()) - { - itEnd->count = offset_right; - ++itEnd; - } - } - - // chop the deque - copy(itBeg, itEnd, pd.m_groupWindow.begin()); - pd.m_groupWindow.resize(itEnd - itBeg); - - // recalc keys - pd.m_processedKeys = 0; - for (deque::const_iterator it = pd.m_groupWindow.begin(); it != pd.m_groupWindow.end(); ++it) - pd.m_processedKeys += it->count; - } - - if ( end_of_stream ) - break; - - } // while (totalKeys == 0 || keys < totalKeys || !found_enough_unique_keys) - - - if (pd.m_toProcessKeys != 0 && pd.m_processedKeys < pd.m_toProcessKeys) - throw std::runtime_error("Couldn't deliver the requested number of keys (it's the file too short?)"); - - if ((pd.m_toProcessKeys != 0 && !found_enough_unique_keys) || - (pd.m_toProcessKeys == 0 && !enoughUniqueGoodGroups(pd.m_groupWindow.begin(), pd.m_groupWindow.end(), pd.m_minUniqueKeys))) - { - throw std::runtime_error("Not enough unique keys (it's the file too short?)"); - } - - // copy to a vector so that they can be returned as contiguous data - pd.m_groups.resize(pd.m_groupWindow.size()); - copy(pd.m_groupWindow.begin(), pd.m_groupWindow.end(), pd.m_groups.begin()); - - pd.m_groupsReady = true; - pd.m_processType = PT_UNKNOWN; - return true; -} - -// ----------------------------------------------------------------------------- - -pair FingerprintExtractor::getFingerprint() -{ - // easier read - PimplData& pd = *m_pPimplData; - - if ( pd.m_groupsReady ) - { -#if __BIG_ENDIAN__ - pd.m_bigEndianGroups.resize(pd.m_groups.size()); - for ( size_t i = 0; i < pd.m_groups.size(); ++i ) - { - pd.m_bigEndianGroups[i].key = reorderbits(pd.m_groups[i].key); - pd.m_bigEndianGroups[i].count = reorderbits(pd.m_groups[i].count); - } - - return make_pair(reinterpret_cast(&pd.m_bigEndianGroups[0]), pd.m_bigEndianGroups.size() * sizeof(GroupData) ); - -#else - return make_pair(reinterpret_cast(&pd.m_groups[0]), pd.m_groups.size() * sizeof(GroupData) ); -#endif - } - else - return make_pair(reinterpret_cast(0), 0); // here's where null_ptr would become useful! -} - -// ----------------------------------------------------------------------------- -// ----------------------------------------------------------------------------- -// ----------------------------------------------------------------------------- - -float getRMS(const FloatingAverage& signal) -{ - // we don't want to normalize by the real rms, because excessive clipping will occur - float rms = sqrtf(static_cast(signal.getAverage())) * 10.0F; - - if (rms < 0.1F) - rms = 0.1F; - else if (rms > 3.0F) - rms = 3.0F; - - return rms; -} - -// ----------------------------------------------------------------------------- - -unsigned int processKeys( deque& groups, size_t size, PimplData& pd ) -{ - size_t read_size = min(size, pd.m_downsampledProcessSize + pd.m_compensateBufferSize); - - unsigned int numFrames = pd.m_pFFT->process(pd.m_pDownsampledPCM, read_size); - - if ( numFrames <= Filter::KEYWIDTH ) - return 0; // skip it when the number of frames is too small - - float** ppFrames = pd.m_pFFT->getFrames(); - - integralImage(ppFrames, numFrames); - computeBits(pd.m_partialBits, pd.m_filters, ppFrames, numFrames); - fingerprint::keys2GroupData(pd.m_partialBits, groups, false); - - return static_cast(pd.m_partialBits.size()); - -} - -// ----------------------------------------------------------------------------- - -void integralImage(float** ppFrames, unsigned int nFrames) -{ - for (unsigned int y = 1; y < nFrames; y++) - { - ppFrames[y][0] += ppFrames[y-1][0]; - } - - for (unsigned int x = 1; x < Filter::NBANDS; x++) - { - ppFrames[0][x] += ppFrames[0][x-1]; - } - - for (unsigned int y = 1; y < nFrames; y++) - { - for (unsigned int x = 1; x < Filter::NBANDS; x++) - { - ppFrames[y][x] += static_cast( static_cast(ppFrames[y-1][x]) + - static_cast(ppFrames[y][x-1]) - - static_cast(ppFrames[y-1][x-1]) ); - } - } -} - -// --------------------------------------------------------------------- -// -/// Convert bands to bits, using the supplied filters -void computeBits( vector& bits, - const vector& f, - float ** frames, unsigned int nframes ) -{ - unsigned int first_time = Filter::KEYWIDTH / 2 + 1; - unsigned int last_time = nframes - Filter::KEYWIDTH / 2; - - unsigned int numBits = last_time - first_time + 1; - bits.resize(numBits); - - const unsigned int fSize = static_cast(f.size()); - std::bitset<32> bt; - double X = 0; - - for (unsigned int t2 = first_time; t2 <= last_time; ++t2) - { - - for (unsigned int i = 0; i < fSize; ++i) - { - // we subtract 1 from t1 and b1 because we use integral images - - unsigned int t1 = (unsigned int) ((float) t2 - f[i].wt / 2.0 - 1); - unsigned int t3 = (unsigned int) ((float) t2 + f[i].wt / 2.0 - 1); - unsigned int b1 = f[i].first_band; - unsigned int b2 = (unsigned int) round__((float) b1 + f[i].wb / 2.0) - 1; - unsigned int b3 = b1 + f[i].wb - 1; - --b1; - - unsigned int t_1q = (t1 + t2) / 2; // one quarter time - unsigned int t_3q = t_1q + (t3 - t1 + 1) / 2; // three quarter time - unsigned int b_1q = (b1 + b2) / 2; // one quarter band - unsigned int b_3q = b_1q + (b3 - b1) / 2; // three quarter band - - X = 0; - - // we should check from t1 > 0, but in practice, this doesn't happen - // we subtract 1 from everything because this came from matlab where indices start from 1 - switch (f[i].filter_type) { - case 1: { // total energy - if (b1 > 0) - X = static_cast(frames[t3-1][b3-1]) - static_cast(frames[t3-1][b1-1]) - - static_cast(frames[t1-1][b3-1]) + static_cast(frames[t1-1][b1-1]); - else - X = static_cast(frames[t3-1][b3-1]) - static_cast(frames[t1-1][b3-1]); - break; - } - case 2: { // energy difference over time - if (b1 > 0) - X = static_cast(frames[t1-1][b1-1]) - 2*static_cast(frames[t2-2][b1-1]) - + static_cast(frames[t3-1][b1-1]) - static_cast(frames[t1-1][b3-1]) - + 2*static_cast(frames[t2-2][b3-1]) - static_cast(frames[t3-1][b3-1]); - else - X = - static_cast(frames[t1-1][b3-1]) + 2*static_cast(frames[t2-2][b3-1]) - - static_cast(frames[t3-1][b3-1]); - break; - - } - case 3: { // energy difference over bands - if (b1 > 0) - X = static_cast(frames[t1-1][b1-1]) - static_cast(frames[t3-1][b1-1]) - - 2*static_cast(frames[t1-1][b2-1]) + 2*static_cast(frames[t3-1][b2-1]) - + static_cast(frames[t1-1][b3-1]) - static_cast(frames[t3-1][b3-1]); - else - X = - 2*static_cast(frames[t1-1][b2-1]) + 2*static_cast(frames[t3-1][b2-1]) - + static_cast(frames[t1-1][b3-1]) - static_cast(frames[t3-1][b3-1]); - break; - } - case 4: { - // energy difference over time and bands - if (b1 > 0) - X = static_cast(frames[t1-1][b1-1]) - 2*static_cast(frames[t2-2][b1-1]) - + static_cast(frames[t3-1][b1-1]) - 2*static_cast(frames[t1-1][b2-1]) - + 4*static_cast(frames[t2-2][b2-1]) - 2*static_cast(frames[t3-1][b2-1]) - + static_cast(frames[t1-1][b3-1]) - 2*static_cast(frames[t2-2][b3-1]) - + static_cast(frames[t3-1][b3-1]); - else - X = - 2*static_cast(frames[t1-1][b2-1]) + 4*static_cast(frames[t2-2][b2-1]) - - 2*static_cast(frames[t3-1][b2-1]) + static_cast(frames[t1-1][b3-1]) - - 2*static_cast(frames[t2-2][b3-1]) + static_cast(frames[t3-1][b3-1]); - break; - } - case 5: { // time peak - if (b1 > 0) - X = - static_cast(frames[t1-1][b1-1]) + 2*static_cast(frames[t_1q-1][b1-1]) - - 2*static_cast(frames[t_3q-1][b1-1]) + static_cast(frames[t3-1][b1-1]) - + static_cast(frames[t1-1][b3-1]) - 2*static_cast(frames[t_1q-1][b3-1]) - + 2*static_cast(frames[t_3q-1][b3-1]) - static_cast(frames[t3-1][b3-1]); - else - X = static_cast(frames[t1-1][b3-1]) - 2*static_cast(frames[t_1q-1][b3-1]) - + 2*static_cast(frames[t_3q-1][b3-1]) - static_cast(frames[t3-1][b3-1]); - - break; - } - case 6: { // band beak - if (b1 > 0) - X = - static_cast(frames[t1-1][b1-1]) + static_cast(frames[t3-1][b1-1]) - + 2*static_cast(frames[t1-1][b_1q-1]) - 2*static_cast(frames[t3-1][b_1q-1]) - - 2*static_cast(frames[t1-1][b_3q-1]) + 2*static_cast(frames[t3-1][b_3q-1]) - + static_cast(frames[t1-1][b3-1]) - static_cast(frames[t3-1][b3-1]); - else - X = + 2*static_cast(frames[t1-1][b_1q-1]) - 2*static_cast(frames[t3-1][b_1q-1]) - - 2*static_cast(frames[t1-1][b_3q-1]) + 2*static_cast(frames[t3-1][b_3q-1]) - + static_cast(frames[t1-1][b3-1]) - static_cast(frames[t3-1][b3-1]); - - break; - } - } - - bt[i] = X > f[i].threshold; - } - - bits[t2 - first_time] = bt.to_ulong(); - } -} - -// ----------------------------------------------------------------------------- - -void src_short_to_float_and_mono_array( const short *in, float *out, int srclen, int nchannels ) -{ - switch ( nchannels ) - { - case 1: - src_short_to_float_array(in, out, srclen); - break; - case 2: - { - // this can be optimized - int j = 0; - const double div = numeric_limits::max() * nchannels; - for ( int i = 0; i < srclen; i += 2, ++j ) - { - out[j] = static_cast( static_cast(static_cast(in[i]) + static_cast(in[i+1])) / div ); - } - } - break; - - default: - throw( std::runtime_error("Unsupported number of channels!") ); - } - -} - -// ----------------------------------------------------------------------------- - -} // end of namespace - -// ----------------------------------------------------------------------------- diff --git a/thirdparty/liblastfm2/src/fingerprint/fplib/FingerprintExtractor.h b/thirdparty/liblastfm2/src/fingerprint/fplib/FingerprintExtractor.h deleted file mode 100644 index fac9b5887..000000000 --- a/thirdparty/liblastfm2/src/fingerprint/fplib/FingerprintExtractor.h +++ /dev/null @@ -1,77 +0,0 @@ -/* - Copyright 2005-2009 Last.fm Ltd. - - This file is part of liblastfm. - - liblastfm is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - liblastfm is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with liblastfm. If not, see . -*/ -#ifndef __FINGERPRINT_EXTRACTOR_H -#define __FINGERPRINT_EXTRACTOR_H - -#include // for pair -#include // for size_t - -namespace fingerprint { - -// ----------------------------------------------------------------------------- - -class PimplData; - -class FingerprintExtractor -{ -public: - - FingerprintExtractor(); // ctor - ~FingerprintExtractor(); // dtor - - // duration (in seconds!) is optional, but if you want to submit tracks <34 secs - // it must be provided. - void initForQuery(int freq, int nchannels, int duration = -1); - void initForFullSubmit(int freq, int nchannels); - - // return false if it needs more data, otherwise true - // IMPORTANT: num_samples specify the size of the *short* array pPCM, that is - // the number of samples that are in the buffer. This includes - // the stereo samples, i.e. - // [L][R][L][R][L][R][L][R] would be num_samples=8 - bool process(const short* pPCM, size_t num_samples, bool end_of_stream = false); - - // returns pair if the data is not ready - std::pair getFingerprint(); - - ////////////////////////////////////////////////////////////////////////// - - // The FingerprintExtractor assumes that the file start from the beginning - // but since the first SkipMs are ignored, it's possible to feed it with NULL. - // In order to know how much must be skipped (in milliseconds) call this function. - // Remark: this is only for "advanced" users! - size_t getToSkipMs(); - - // Return the minimum duration of the file (in ms) - // Any file with a length smaller than this value will be discarded - static size_t getMinimumDurationMs(); - - // return the version of the fingerprint - static size_t getVersion(); - -private: - - PimplData* m_pPimplData; -}; - -// ----------------------------------------------------------------------------- - -} // end of namespace fingerprint - -#endif // __FINGERPRINT_EXTRACTOR_H diff --git a/thirdparty/liblastfm2/src/fingerprint/fplib/FloatingAverage.h b/thirdparty/liblastfm2/src/fingerprint/fplib/FloatingAverage.h deleted file mode 100644 index 1be665bd0..000000000 --- a/thirdparty/liblastfm2/src/fingerprint/fplib/FloatingAverage.h +++ /dev/null @@ -1,106 +0,0 @@ -/* - Copyright 2005-2009 Last.fm Ltd. - - This file is part of liblastfm. - - liblastfm is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - liblastfm is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with liblastfm. If not, see . -*/ -#ifndef __FLOAT_AVERAGE_H__ -#define __FLOAT_AVERAGE_H__ - -//#include -#include -#include "CircularArray.h" - -template -class FloatingAverage -{ -public: - FloatingAverage(size_t size) - { - m_values.resize(size); - m_valIt = m_values.head(); - m_sum = 0; - m_bufferFilled = false; - } - - void purge() - { - m_sum = 0; - const T* pCircularBuffer = m_values.get_buffer(); - const int size = m_values.size(); - - for ( int i = 0; i < size; ++i ) - m_sum += pCircularBuffer[i]; - } - - void add(const T& value) - { - m_sum += value; - - if ( m_bufferFilled ) - { - m_sum -= *m_valIt; - *m_valIt = value; - ++m_valIt; - } - else - { - *m_valIt = value; - ++m_valIt; - if ( m_valIt == m_values.head() ) - m_bufferFilled = true; - } - } - - T getAverage() const - { - if ( !m_bufferFilled ) - return m_sum / (m_valIt - m_values.head()); - else - return m_sum / m_values.size(); - } - - T getError() const - { - T real_sum = 0; - const T* pCircularBuffer = m_values.get_buffer(); - for ( int i = 0; i < size; ++i ) - real_sum += pCircularBuffer[i]; - return abs(real_sum - m_sum) / this->size(); - } - - size_t size() const - { - return m_values.size(); - } - - void clear() - { - m_bufferFilled = false; - m_values.zero_fill(); - m_valIt = m_values.head(); - m_sum = 0; - } - -private: - //std::deque m_values; - CircularArray m_values; - typename CircularArray::iterator m_valIt; - - bool m_bufferFilled; - T m_sum; -}; - -#endif // __FLOAT_AVERAGE_H__ diff --git a/thirdparty/liblastfm2/src/fingerprint/fplib/OptFFT.cpp b/thirdparty/liblastfm2/src/fingerprint/fplib/OptFFT.cpp deleted file mode 100644 index 3728c974c..000000000 --- a/thirdparty/liblastfm2/src/fingerprint/fplib/OptFFT.cpp +++ /dev/null @@ -1,411 +0,0 @@ -/* - Copyright 2005-2009 Last.fm Ltd. - - This file is part of liblastfm. - - liblastfm is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - liblastfm is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with liblastfm. If not, see . -*/ -#include "OptFFT.h" -#include "fp_helper_fun.h" -#include "Filter.h" // for NBANDS - -#include -#include -#include -#include -#include -#include -#include -#include - -using namespace std; -// ---------------------------------------------------------------------- - -namespace fingerprint -{ - - static const float hann[] = { - 0.000000f,0.000002f,0.000009f,0.000021f,0.000038f,0.000059f,0.000085f,0.000115f,0.000151f,0.000191f,0.000236f, - 0.000285f,0.000339f,0.000398f,0.000462f,0.000530f,0.000603f,0.000681f,0.000763f,0.000850f,0.000942f,0.001038f, - 0.001140f,0.001245f,0.001356f,0.001471f,0.001591f,0.001716f,0.001845f,0.001980f,0.002118f,0.002262f,0.002410f, - 0.002563f,0.002720f,0.002883f,0.003049f,0.003221f,0.003397f,0.003578f,0.003764f,0.003954f,0.004149f,0.004349f, - 0.004553f,0.004762f,0.004976f,0.005194f,0.005417f,0.005645f,0.005877f,0.006114f,0.006355f,0.006602f,0.006853f, - 0.007108f,0.007368f,0.007633f,0.007903f,0.008177f,0.008455f,0.008739f,0.009027f,0.009319f,0.009617f,0.009919f, - 0.010225f,0.010536f,0.010852f,0.011172f,0.011497f,0.011827f,0.012161f,0.012499f,0.012843f,0.013191f,0.013543f, - 0.013900f,0.014262f,0.014628f,0.014999f,0.015374f,0.015754f,0.016139f,0.016528f,0.016921f,0.017320f,0.017722f, - 0.018130f,0.018541f,0.018958f,0.019379f,0.019804f,0.020234f,0.020668f,0.021107f,0.021551f,0.021999f,0.022451f, - 0.022908f,0.023370f,0.023836f,0.024306f,0.024781f,0.025260f,0.025744f,0.026233f,0.026725f,0.027223f,0.027724f, - 0.028231f,0.028741f,0.029256f,0.029776f,0.030300f,0.030828f,0.031361f,0.031898f,0.032440f,0.032986f,0.033536f, - 0.034091f,0.034650f,0.035214f,0.035781f,0.036354f,0.036930f,0.037512f,0.038097f,0.038687f,0.039281f,0.039879f, - 0.040482f,0.041089f,0.041701f,0.042316f,0.042936f,0.043561f,0.044189f,0.044822f,0.045460f,0.046101f,0.046747f, - 0.047397f,0.048052f,0.048710f,0.049373f,0.050040f,0.050711f,0.051387f,0.052067f,0.052751f,0.053439f,0.054132f, - 0.054828f,0.055529f,0.056234f,0.056943f,0.057657f,0.058374f,0.059096f,0.059822f,0.060552f,0.061286f,0.062024f, - 0.062767f,0.063513f,0.064264f,0.065019f,0.065777f,0.066540f,0.067307f,0.068078f,0.068854f,0.069633f,0.070416f, - 0.071204f,0.071995f,0.072790f,0.073590f,0.074393f,0.075201f,0.076012f,0.076828f,0.077647f,0.078470f,0.079298f, - 0.080129f,0.080964f,0.081804f,0.082647f,0.083494f,0.084345f,0.085200f,0.086059f,0.086922f,0.087788f,0.088659f, - 0.089533f,0.090412f,0.091294f,0.092180f,0.093070f,0.093963f,0.094861f,0.095762f,0.096667f,0.097576f,0.098489f, - 0.099406f,0.100326f,0.101250f,0.102178f,0.103109f,0.104045f,0.104984f,0.105926f,0.106873f,0.107823f,0.108777f, - 0.109734f,0.110696f,0.111661f,0.112629f,0.113601f,0.114577f,0.115557f,0.116540f,0.117526f,0.118517f,0.119511f, - 0.120508f,0.121509f,0.122514f,0.123522f,0.124534f,0.125549f,0.126568f,0.127590f,0.128616f,0.129645f,0.130678f, - 0.131714f,0.132754f,0.133797f,0.134844f,0.135894f,0.136948f,0.138005f,0.139065f,0.140129f,0.141196f,0.142266f, - 0.143340f,0.144418f,0.145498f,0.146582f,0.147670f,0.148760f,0.149854f,0.150951f,0.152052f,0.153156f,0.154263f, - 0.155373f,0.156487f,0.157603f,0.158723f,0.159847f,0.160973f,0.162103f,0.163236f,0.164372f,0.165511f,0.166653f, - 0.167799f,0.168947f,0.170099f,0.171254f,0.172411f,0.173572f,0.174737f,0.175904f,0.177074f,0.178247f,0.179423f, - 0.180603f,0.181785f,0.182970f,0.184158f,0.185350f,0.186544f,0.187741f,0.188941f,0.190144f,0.191350f,0.192559f, - 0.193771f,0.194986f,0.196203f,0.197423f,0.198647f,0.199873f,0.201102f,0.202333f,0.203568f,0.204805f,0.206045f, - 0.207288f,0.208534f,0.209782f,0.211033f,0.212287f,0.213544f,0.214803f,0.216065f,0.217329f,0.218597f,0.219867f, - 0.221139f,0.222414f,0.223692f,0.224972f,0.226255f,0.227541f,0.228829f,0.230120f,0.231413f,0.232709f,0.234007f, - 0.235308f,0.236611f,0.237917f,0.239225f,0.240536f,0.241849f,0.243165f,0.244483f,0.245803f,0.247126f,0.248451f, - 0.249779f,0.251108f,0.252441f,0.253775f,0.255112f,0.256451f,0.257793f,0.259137f,0.260483f,0.261831f,0.263182f, - 0.264534f,0.265889f,0.267247f,0.268606f,0.269967f,0.271331f,0.272697f,0.274065f,0.275435f,0.276808f,0.278182f, - 0.279558f,0.280937f,0.282318f,0.283700f,0.285085f,0.286472f,0.287861f,0.289251f,0.290644f,0.292039f,0.293435f, - 0.294834f,0.296235f,0.297637f,0.299041f,0.300448f,0.301856f,0.303266f,0.304678f,0.306091f,0.307507f,0.308924f, - 0.310343f,0.311764f,0.313187f,0.314611f,0.316038f,0.317466f,0.318895f,0.320327f,0.321760f,0.323194f,0.324631f, - 0.326069f,0.327509f,0.328950f,0.330393f,0.331837f,0.333283f,0.334731f,0.336180f,0.337631f,0.339083f,0.340537f, - 0.341993f,0.343449f,0.344908f,0.346368f,0.347829f,0.349291f,0.350755f,0.352221f,0.353688f,0.355156f,0.356626f, - 0.358097f,0.359569f,0.361042f,0.362517f,0.363994f,0.365471f,0.366950f,0.368430f,0.369911f,0.371394f,0.372877f, - 0.374362f,0.375848f,0.377336f,0.378824f,0.380314f,0.381804f,0.383296f,0.384789f,0.386283f,0.387778f,0.389274f, - 0.390771f,0.392269f,0.393768f,0.395269f,0.396770f,0.398272f,0.399775f,0.401279f,0.402784f,0.404290f,0.405797f, - 0.407305f,0.408813f,0.410322f,0.411833f,0.413344f,0.414856f,0.416368f,0.417882f,0.419396f,0.420911f,0.422427f, - 0.423944f,0.425461f,0.426979f,0.428497f,0.430017f,0.431537f,0.433057f,0.434578f,0.436100f,0.437623f,0.439146f, - 0.440669f,0.442193f,0.443718f,0.445243f,0.446769f,0.448295f,0.449822f,0.451349f,0.452877f,0.454405f,0.455934f, - 0.457463f,0.458992f,0.460522f,0.462052f,0.463582f,0.465113f,0.466644f,0.468176f,0.469708f,0.471240f,0.472772f, - 0.474305f,0.475837f,0.477370f,0.478904f,0.480437f,0.481971f,0.483505f,0.485039f,0.486573f,0.488107f,0.489641f, - 0.491176f,0.492710f,0.494245f,0.495780f,0.497314f,0.498849f,0.500384f,0.501918f,0.503453f,0.504988f,0.506522f, - 0.508057f,0.509591f,0.511126f,0.512660f,0.514194f,0.515728f,0.517262f,0.518796f,0.520330f,0.521863f,0.523396f, - 0.524929f,0.526462f,0.527994f,0.529526f,0.531058f,0.532590f,0.534121f,0.535652f,0.537183f,0.538713f,0.540243f, - 0.541773f,0.543302f,0.544831f,0.546359f,0.547887f,0.549414f,0.550941f,0.552468f,0.553994f,0.555519f,0.557044f, - 0.558569f,0.560093f,0.561616f,0.563139f,0.564661f,0.566182f,0.567703f,0.569223f,0.570743f,0.572262f,0.573780f, - 0.575298f,0.576815f,0.578331f,0.579846f,0.581361f,0.582875f,0.584388f,0.585900f,0.587412f,0.588922f,0.590432f, - 0.591941f,0.593449f,0.594957f,0.596463f,0.597968f,0.599473f,0.600977f,0.602479f,0.603981f,0.605482f,0.606981f, - 0.608480f,0.609978f,0.611474f,0.612970f,0.614464f,0.615958f,0.617450f,0.618941f,0.620431f,0.621920f,0.623408f, - 0.624895f,0.626380f,0.627865f,0.629348f,0.630830f,0.632310f,0.633790f,0.635268f,0.636745f,0.638220f,0.639695f, - 0.641167f,0.642639f,0.644109f,0.645578f,0.647046f,0.648512f,0.649977f,0.651440f,0.652902f,0.654363f,0.655822f, - 0.657279f,0.658735f,0.660190f,0.661643f,0.663094f,0.664544f,0.665993f,0.667440f,0.668885f,0.670329f,0.671771f, - 0.673212f,0.674650f,0.676088f,0.677523f,0.678957f,0.680389f,0.681820f,0.683249f,0.684676f,0.686101f,0.687525f, - 0.688946f,0.690366f,0.691785f,0.693201f,0.694616f,0.696029f,0.697439f,0.698849f,0.700256f,0.701661f,0.703065f, - 0.704466f,0.705866f,0.707263f,0.708659f,0.710053f,0.711444f,0.712834f,0.714222f,0.715608f,0.716991f,0.718373f, - 0.719752f,0.721130f,0.722505f,0.723879f,0.725250f,0.726619f,0.727986f,0.729351f,0.730714f,0.732074f,0.733432f, - 0.734788f,0.736142f,0.737494f,0.738843f,0.740191f,0.741536f,0.742878f,0.744219f,0.745557f,0.746892f,0.748226f, - 0.749557f,0.750886f,0.752212f,0.753536f,0.754857f,0.756177f,0.757493f,0.758808f,0.760120f,0.761429f,0.762736f, - 0.764041f,0.765343f,0.766642f,0.767939f,0.769234f,0.770526f,0.771815f,0.773102f,0.774386f,0.775668f,0.776947f, - 0.778224f,0.779497f,0.780769f,0.782037f,0.783303f,0.784567f,0.785827f,0.787085f,0.788340f,0.789593f,0.790842f, - 0.792089f,0.793334f,0.794575f,0.795814f,0.797050f,0.798283f,0.799513f,0.800741f,0.801965f,0.803187f,0.804406f, - 0.805622f,0.806835f,0.808046f,0.809253f,0.810458f,0.811659f,0.812858f,0.814054f,0.815246f,0.816436f,0.817623f, - 0.818807f,0.819987f,0.821165f,0.822340f,0.823512f,0.824680f,0.825846f,0.827008f,0.828168f,0.829324f,0.830477f, - 0.831628f,0.832775f,0.833918f,0.835059f,0.836197f,0.837331f,0.838462f,0.839591f,0.840715f,0.841837f,0.842955f, - 0.844071f,0.845183f,0.846291f,0.847397f,0.848499f,0.849598f,0.850693f,0.851786f,0.852874f,0.853960f,0.855042f, - 0.856121f,0.857197f,0.858269f,0.859338f,0.860404f,0.861466f,0.862524f,0.863580f,0.864631f,0.865680f,0.866725f, - 0.867766f,0.868804f,0.869839f,0.870870f,0.871897f,0.872922f,0.873942f,0.874959f,0.875973f,0.876983f,0.877989f, - 0.878992f,0.879991f,0.880987f,0.881979f,0.882967f,0.883952f,0.884934f,0.885911f,0.886885f,0.887856f,0.888822f, - 0.889785f,0.890745f,0.891701f,0.892653f,0.893601f,0.894545f,0.895486f,0.896423f,0.897357f,0.898287f,0.899213f, - 0.900135f,0.901053f,0.901968f,0.902879f,0.903786f,0.904689f,0.905588f,0.906484f,0.907376f,0.908264f,0.909148f, - 0.910028f,0.910904f,0.911777f,0.912645f,0.913510f,0.914371f,0.915228f,0.916081f,0.916930f,0.917775f,0.918616f, - 0.919454f,0.920287f,0.921116f,0.921942f,0.922763f,0.923581f,0.924394f,0.925204f,0.926009f,0.926810f,0.927608f, - 0.928401f,0.929191f,0.929976f,0.930757f,0.931534f,0.932308f,0.933077f,0.933842f,0.934603f,0.935359f,0.936112f, - 0.936861f,0.937605f,0.938345f,0.939082f,0.939814f,0.940542f,0.941265f,0.941985f,0.942701f,0.943412f,0.944119f, - 0.944822f,0.945521f,0.946215f,0.946906f,0.947592f,0.948274f,0.948951f,0.949625f,0.950294f,0.950959f,0.951620f, - 0.952276f,0.952928f,0.953576f,0.954220f,0.954859f,0.955495f,0.956125f,0.956752f,0.957374f,0.957992f,0.958606f, - 0.959215f,0.959820f,0.960420f,0.961017f,0.961609f,0.962196f,0.962780f,0.963358f,0.963933f,0.964503f,0.965069f, - 0.965630f,0.966187f,0.966740f,0.967288f,0.967832f,0.968371f,0.968906f,0.969437f,0.969963f,0.970485f,0.971002f, - 0.971515f,0.972023f,0.972527f,0.973027f,0.973522f,0.974012f,0.974498f,0.974980f,0.975457f,0.975930f,0.976398f, - 0.976862f,0.977321f,0.977776f,0.978226f,0.978672f,0.979113f,0.979549f,0.979982f,0.980409f,0.980832f,0.981251f, - 0.981665f,0.982075f,0.982480f,0.982880f,0.983276f,0.983667f,0.984054f,0.984436f,0.984814f,0.985187f,0.985556f, - 0.985919f,0.986279f,0.986634f,0.986984f,0.987329f,0.987670f,0.988007f,0.988339f,0.988666f,0.988989f,0.989307f, - 0.989620f,0.989929f,0.990233f,0.990532f,0.990827f,0.991118f,0.991403f,0.991684f,0.991961f,0.992233f,0.992500f, - 0.992762f,0.993020f,0.993273f,0.993522f,0.993766f,0.994005f,0.994240f,0.994470f,0.994695f,0.994916f,0.995132f, - 0.995343f,0.995550f,0.995752f,0.995949f,0.996142f,0.996329f,0.996513f,0.996691f,0.996865f,0.997035f,0.997199f, - 0.997359f,0.997514f,0.997665f,0.997810f,0.997952f,0.998088f,0.998220f,0.998347f,0.998469f,0.998587f,0.998700f, - 0.998808f,0.998912f,0.999010f,0.999105f,0.999194f,0.999279f,0.999359f,0.999434f,0.999505f,0.999571f,0.999632f, - 0.999689f,0.999740f,0.999787f,0.999830f,0.999868f,0.999900f,0.999929f,0.999952f,0.999971f,0.999985f,0.999995f, - 0.999999f,0.999999f,0.999995f,0.999985f,0.999971f,0.999952f,0.999929f,0.999900f,0.999868f,0.999830f,0.999787f, - 0.999740f,0.999689f,0.999632f,0.999571f,0.999505f,0.999434f,0.999359f,0.999279f,0.999194f,0.999105f,0.999010f, - 0.998912f,0.998808f,0.998700f,0.998587f,0.998469f,0.998347f,0.998220f,0.998088f,0.997952f,0.997810f,0.997665f, - 0.997514f,0.997359f,0.997199f,0.997035f,0.996865f,0.996691f,0.996513f,0.996329f,0.996142f,0.995949f,0.995752f, - 0.995550f,0.995343f,0.995132f,0.994916f,0.994695f,0.994470f,0.994240f,0.994005f,0.993766f,0.993522f,0.993273f, - 0.993020f,0.992762f,0.992500f,0.992233f,0.991961f,0.991684f,0.991403f,0.991118f,0.990827f,0.990532f,0.990233f, - 0.989929f,0.989620f,0.989307f,0.988989f,0.988666f,0.988339f,0.988007f,0.987670f,0.987329f,0.986984f,0.986634f, - 0.986279f,0.985919f,0.985556f,0.985187f,0.984814f,0.984436f,0.984054f,0.983667f,0.983276f,0.982880f,0.982480f, - 0.982075f,0.981665f,0.981251f,0.980832f,0.980409f,0.979982f,0.979549f,0.979113f,0.978672f,0.978226f,0.977776f, - 0.977321f,0.976862f,0.976398f,0.975930f,0.975457f,0.974980f,0.974498f,0.974012f,0.973522f,0.973027f,0.972527f, - 0.972023f,0.971515f,0.971002f,0.970485f,0.969963f,0.969437f,0.968906f,0.968371f,0.967832f,0.967288f,0.966740f, - 0.966187f,0.965630f,0.965069f,0.964503f,0.963933f,0.963358f,0.962780f,0.962196f,0.961609f,0.961017f,0.960420f, - 0.959820f,0.959215f,0.958606f,0.957992f,0.957374f,0.956752f,0.956125f,0.955495f,0.954859f,0.954220f,0.953576f, - 0.952928f,0.952276f,0.951620f,0.950959f,0.950294f,0.949625f,0.948951f,0.948274f,0.947592f,0.946906f,0.946215f, - 0.945521f,0.944822f,0.944119f,0.943412f,0.942701f,0.941985f,0.941265f,0.940542f,0.939814f,0.939082f,0.938345f, - 0.937605f,0.936861f,0.936112f,0.935359f,0.934603f,0.933842f,0.933077f,0.932308f,0.931534f,0.930757f,0.929976f, - 0.929191f,0.928401f,0.927608f,0.926810f,0.926009f,0.925204f,0.924394f,0.923581f,0.922763f,0.921942f,0.921116f, - 0.920287f,0.919454f,0.918616f,0.917775f,0.916930f,0.916081f,0.915228f,0.914371f,0.913510f,0.912645f,0.911777f, - 0.910904f,0.910028f,0.909148f,0.908264f,0.907376f,0.906484f,0.905588f,0.904689f,0.903786f,0.902879f,0.901968f, - 0.901053f,0.900135f,0.899213f,0.898287f,0.897357f,0.896423f,0.895486f,0.894545f,0.893601f,0.892653f,0.891701f, - 0.890745f,0.889785f,0.888822f,0.887856f,0.886885f,0.885911f,0.884934f,0.883952f,0.882967f,0.881979f,0.880987f, - 0.879991f,0.878992f,0.877989f,0.876983f,0.875973f,0.874959f,0.873942f,0.872922f,0.871897f,0.870870f,0.869839f, - 0.868804f,0.867766f,0.866725f,0.865680f,0.864631f,0.863580f,0.862524f,0.861466f,0.860404f,0.859338f,0.858269f, - 0.857197f,0.856121f,0.855042f,0.853960f,0.852874f,0.851786f,0.850693f,0.849598f,0.848499f,0.847397f,0.846291f, - 0.845183f,0.844071f,0.842955f,0.841837f,0.840715f,0.839591f,0.838462f,0.837331f,0.836197f,0.835059f,0.833918f, - 0.832775f,0.831628f,0.830477f,0.829324f,0.828168f,0.827008f,0.825846f,0.824680f,0.823512f,0.822340f,0.821165f, - 0.819987f,0.818807f,0.817623f,0.816436f,0.815246f,0.814054f,0.812858f,0.811659f,0.810458f,0.809253f,0.808046f, - 0.806835f,0.805622f,0.804406f,0.803187f,0.801965f,0.800741f,0.799513f,0.798283f,0.797050f,0.795814f,0.794575f, - 0.793334f,0.792089f,0.790842f,0.789593f,0.788340f,0.787085f,0.785827f,0.784567f,0.783303f,0.782037f,0.780769f, - 0.779497f,0.778224f,0.776947f,0.775668f,0.774386f,0.773102f,0.771815f,0.770526f,0.769234f,0.767939f,0.766642f, - 0.765343f,0.764041f,0.762736f,0.761429f,0.760120f,0.758808f,0.757493f,0.756177f,0.754857f,0.753536f,0.752212f, - 0.750886f,0.749557f,0.748226f,0.746892f,0.745557f,0.744219f,0.742878f,0.741536f,0.740191f,0.738843f,0.737494f, - 0.736142f,0.734788f,0.733432f,0.732074f,0.730714f,0.729351f,0.727986f,0.726619f,0.725250f,0.723879f,0.722505f, - 0.721130f,0.719752f,0.718373f,0.716991f,0.715608f,0.714222f,0.712834f,0.711444f,0.710053f,0.708659f,0.707263f, - 0.705866f,0.704466f,0.703065f,0.701661f,0.700256f,0.698849f,0.697439f,0.696029f,0.694616f,0.693201f,0.691785f, - 0.690366f,0.688946f,0.687525f,0.686101f,0.684676f,0.683249f,0.681820f,0.680389f,0.678957f,0.677523f,0.676088f, - 0.674650f,0.673212f,0.671771f,0.670329f,0.668885f,0.667440f,0.665993f,0.664544f,0.663094f,0.661643f,0.660190f, - 0.658735f,0.657279f,0.655822f,0.654363f,0.652902f,0.651440f,0.649977f,0.648512f,0.647046f,0.645578f,0.644109f, - 0.642639f,0.641167f,0.639695f,0.638220f,0.636745f,0.635268f,0.633790f,0.632310f,0.630830f,0.629348f,0.627865f, - 0.626380f,0.624895f,0.623408f,0.621920f,0.620431f,0.618941f,0.617450f,0.615958f,0.614464f,0.612970f,0.611474f, - 0.609978f,0.608480f,0.606981f,0.605482f,0.603981f,0.602479f,0.600977f,0.599473f,0.597968f,0.596463f,0.594957f, - 0.593449f,0.591941f,0.590432f,0.588922f,0.587412f,0.585900f,0.584388f,0.582875f,0.581361f,0.579846f,0.578331f, - 0.576815f,0.575298f,0.573780f,0.572262f,0.570743f,0.569223f,0.567703f,0.566182f,0.564661f,0.563139f,0.561616f, - 0.560093f,0.558569f,0.557044f,0.555519f,0.553994f,0.552468f,0.550941f,0.549414f,0.547887f,0.546359f,0.544831f, - 0.543302f,0.541773f,0.540243f,0.538713f,0.537183f,0.535652f,0.534121f,0.532590f,0.531058f,0.529526f,0.527994f, - 0.526462f,0.524929f,0.523396f,0.521863f,0.520330f,0.518796f,0.517262f,0.515728f,0.514194f,0.512660f,0.511126f, - 0.509591f,0.508057f,0.506522f,0.504988f,0.503453f,0.501918f,0.500384f,0.498849f,0.497314f,0.495780f,0.494245f, - 0.492710f,0.491176f,0.489641f,0.488107f,0.486573f,0.485039f,0.483505f,0.481971f,0.480437f,0.478904f,0.477370f, - 0.475837f,0.474305f,0.472772f,0.471240f,0.469708f,0.468176f,0.466644f,0.465113f,0.463582f,0.462052f,0.460522f, - 0.458992f,0.457463f,0.455934f,0.454405f,0.452877f,0.451349f,0.449822f,0.448295f,0.446769f,0.445243f,0.443718f, - 0.442193f,0.440669f,0.439146f,0.437623f,0.436100f,0.434578f,0.433057f,0.431537f,0.430017f,0.428497f,0.426979f, - 0.425461f,0.423944f,0.422427f,0.420911f,0.419396f,0.417882f,0.416368f,0.414856f,0.413344f,0.411833f,0.410322f, - 0.408813f,0.407305f,0.405797f,0.404290f,0.402784f,0.401279f,0.399775f,0.398272f,0.396770f,0.395269f,0.393768f, - 0.392269f,0.390771f,0.389274f,0.387778f,0.386283f,0.384789f,0.383296f,0.381804f,0.380314f,0.378824f,0.377336f, - 0.375848f,0.374362f,0.372877f,0.371394f,0.369911f,0.368430f,0.366950f,0.365471f,0.363994f,0.362517f,0.361042f, - 0.359569f,0.358097f,0.356626f,0.355156f,0.353688f,0.352221f,0.350755f,0.349291f,0.347829f,0.346368f,0.344908f, - 0.343449f,0.341993f,0.340537f,0.339083f,0.337631f,0.336180f,0.334731f,0.333283f,0.331837f,0.330393f,0.328950f, - 0.327509f,0.326069f,0.324631f,0.323194f,0.321760f,0.320327f,0.318895f,0.317466f,0.316038f,0.314611f,0.313187f, - 0.311764f,0.310343f,0.308924f,0.307507f,0.306091f,0.304678f,0.303266f,0.301856f,0.300448f,0.299041f,0.297637f, - 0.296235f,0.294834f,0.293435f,0.292039f,0.290644f,0.289251f,0.287861f,0.286472f,0.285085f,0.283700f,0.282318f, - 0.280937f,0.279558f,0.278182f,0.276808f,0.275435f,0.274065f,0.272697f,0.271331f,0.269967f,0.268606f,0.267247f, - 0.265889f,0.264534f,0.263182f,0.261831f,0.260483f,0.259137f,0.257793f,0.256451f,0.255112f,0.253775f,0.252441f, - 0.251108f,0.249779f,0.248451f,0.247126f,0.245803f,0.244483f,0.243165f,0.241849f,0.240536f,0.239225f,0.237917f, - 0.236611f,0.235308f,0.234007f,0.232709f,0.231413f,0.230120f,0.228829f,0.227541f,0.226255f,0.224972f,0.223692f, - 0.222414f,0.221139f,0.219867f,0.218597f,0.217329f,0.216065f,0.214803f,0.213544f,0.212287f,0.211033f,0.209782f, - 0.208534f,0.207288f,0.206045f,0.204805f,0.203568f,0.202333f,0.201102f,0.199873f,0.198647f,0.197423f,0.196203f, - 0.194986f,0.193771f,0.192559f,0.191350f,0.190144f,0.188941f,0.187741f,0.186544f,0.185350f,0.184158f,0.182970f, - 0.181785f,0.180603f,0.179423f,0.178247f,0.177074f,0.175904f,0.174737f,0.173572f,0.172411f,0.171254f,0.170099f, - 0.168947f,0.167799f,0.166653f,0.165511f,0.164372f,0.163236f,0.162103f,0.160973f,0.159847f,0.158723f,0.157603f, - 0.156487f,0.155373f,0.154263f,0.153156f,0.152052f,0.150951f,0.149854f,0.148760f,0.147670f,0.146582f,0.145498f, - 0.144418f,0.143340f,0.142266f,0.141196f,0.140129f,0.139065f,0.138005f,0.136948f,0.135894f,0.134844f,0.133797f, - 0.132754f,0.131714f,0.130678f,0.129645f,0.128616f,0.127590f,0.126568f,0.125549f,0.124534f,0.123522f,0.122514f, - 0.121509f,0.120508f,0.119511f,0.118517f,0.117526f,0.116540f,0.115557f,0.114577f,0.113601f,0.112629f,0.111661f, - 0.110696f,0.109734f,0.108777f,0.107823f,0.106873f,0.105926f,0.104984f,0.104045f,0.103109f,0.102178f,0.101250f, - 0.100326f,0.099406f,0.098489f,0.097576f,0.096667f,0.095762f,0.094861f,0.093963f,0.093070f,0.092180f,0.091294f, - 0.090412f,0.089533f,0.088659f,0.087788f,0.086922f,0.086059f,0.085200f,0.084345f,0.083494f,0.082647f,0.081804f, - 0.080964f,0.080129f,0.079298f,0.078470f,0.077647f,0.076828f,0.076012f,0.075201f,0.074393f,0.073590f,0.072790f, - 0.071995f,0.071204f,0.070416f,0.069633f,0.068854f,0.068078f,0.067307f,0.066540f,0.065777f,0.065019f,0.064264f, - 0.063513f,0.062767f,0.062024f,0.061286f,0.060552f,0.059822f,0.059096f,0.058374f,0.057657f,0.056943f,0.056234f, - 0.055529f,0.054828f,0.054132f,0.053439f,0.052751f,0.052067f,0.051387f,0.050711f,0.050040f,0.049373f,0.048710f, - 0.048052f,0.047397f,0.046747f,0.046101f,0.045460f,0.044822f,0.044189f,0.043561f,0.042936f,0.042316f,0.041701f, - 0.041089f,0.040482f,0.039879f,0.039281f,0.038687f,0.038097f,0.037512f,0.036930f,0.036354f,0.035781f,0.035214f, - 0.034650f,0.034091f,0.033536f,0.032986f,0.032440f,0.031898f,0.031361f,0.030828f,0.030300f,0.029776f,0.029256f, - 0.028741f,0.028231f,0.027724f,0.027223f,0.026725f,0.026233f,0.025744f,0.025260f,0.024781f,0.024306f,0.023836f, - 0.023370f,0.022908f,0.022451f,0.021999f,0.021551f,0.021107f,0.020668f,0.020234f,0.019804f,0.019379f,0.018958f, - 0.018541f,0.018130f,0.017722f,0.017320f,0.016921f,0.016528f,0.016139f,0.015754f,0.015374f,0.014999f,0.014628f, - 0.014262f,0.013900f,0.013543f,0.013191f,0.012843f,0.012499f,0.012161f,0.011827f,0.011497f,0.011172f,0.010852f, - 0.010536f,0.010225f,0.009919f,0.009617f,0.009319f,0.009027f,0.008739f,0.008455f,0.008177f,0.007903f,0.007633f, - 0.007368f,0.007108f,0.006853f,0.006602f,0.006355f,0.006114f,0.005877f,0.005645f,0.005417f,0.005194f,0.004976f, - 0.004762f,0.004553f,0.004349f,0.004149f,0.003954f,0.003764f,0.003578f,0.003397f,0.003221f,0.003049f,0.002883f, - 0.002720f,0.002563f,0.002410f,0.002262f,0.002118f,0.001980f,0.001845f,0.001716f,0.001591f,0.001471f,0.001356f, - 0.001245f,0.001140f,0.001038f,0.000942f,0.000850f,0.000763f,0.000681f,0.000603f,0.000530f,0.000462f,0.000398f, - 0.000339f,0.000285f,0.000236f,0.000191f,0.000151f,0.000115f,0.000085f,0.000059f,0.000038f,0.000021f,0.000009f, - 0.000002f,0.000000f }; - -// ----------------------------------------------------------------------------- - -OptFFT::OptFFT(const size_t maxDataSize) -{ - assert( maxDataSize % OVERLAPSAMPLES == 0 ); - - // DOUBLE - //m_pIn = static_cast( fftw_malloc(sizeof(double) * FRAMESIZE) ); - //m_pOut = static_cast( fftw_malloc(sizeof(fftw_complex) * (FRAMESIZE/2 + 1)) ); - //m_p = fftw_plan_dft_r2c_1f(FRAMESIZE, m_pIn, m_pOut, FFTW_ESTIMATE); // FFTW_ESTIMATE or FFTW_MEASURE - - // FLOAT - // m_pIn = static_cast( fftwf_malloc(sizeof(float) * FRAMESIZE) ); - // m_pOut = static_cast( fftwf_malloc(sizeof(fftwf_complex) * (FRAMESIZE/2 + 1)) ); - - //// in destroyed when line executed - //m_p = fftwf_plan_dft_r2c_1d(FRAMESIZE, m_pIn, m_pOut, FFTW_ESTIMATE); // FFTW_ESTIMATE or FFTW_MEASURE - - //----------------------------------------------------------------- - - int numSamplesPerFrame = FRAMESIZE; - int numSamplesPerFrameOut = FRAMESIZE/2+1; - - m_maxFrames = static_cast ( (maxDataSize - FRAMESIZE) / OVERLAPSAMPLES + 1 ); - - m_pIn = static_cast ( fftwf_malloc(sizeof(float) * (numSamplesPerFrame * m_maxFrames) ) ); - if ( !m_pIn ) - { - ostringstream oss; - oss << "fftwf_malloc failed on m_pIn. Trying to allocate <" - << sizeof(float) * (numSamplesPerFrame * m_maxFrames) - << "> bytes"; - throw std::runtime_error(oss.str()); - } - - m_pOut = static_cast( fftwf_malloc(sizeof(fftwf_complex) * (numSamplesPerFrameOut* m_maxFrames) ) ); - if ( !m_pOut ) - { - ostringstream oss; - oss << "fftwf_malloc failed on m_pOut. Trying to allocate <" - << sizeof(fftwf_complex) * (numSamplesPerFrameOut* m_maxFrames) - << "> bytes"; - - throw std::runtime_error(oss.str()); - } - - // in destroyed when line executed - m_p = fftwf_plan_many_dft_r2c(1, &numSamplesPerFrame, m_maxFrames, - m_pIn, &numSamplesPerFrame, 1, numSamplesPerFrame, - m_pOut, &numSamplesPerFrameOut, - 1, numSamplesPerFrameOut, - FFTW_ESTIMATE | FFTW_DESTROY_INPUT); - - if ( !m_p ) - throw std::runtime_error ("fftwf_plan_many_dft_r2c failed"); - - double base = exp( log( static_cast(MAXFREQ) / static_cast(MINFREQ) ) / - static_cast(Filter::NBANDS) - ); - - m_powTable.resize( Filter::NBANDS+1 ); - for ( unsigned int i = 0; i < Filter::NBANDS + 1; ++i ) - m_powTable[i] = static_cast( (pow(base, static_cast(i)) - 1.0) * MINCOEF ); - - m_pFrames = new float*[m_maxFrames]; - - if ( !m_pFrames ) - { - ostringstream oss; - oss << "Allocation failed on m_pFrames. Trying to allocate <" - << sizeof(float*) * m_maxFrames - << "> bytes"; - - throw std::runtime_error(oss.str()); - } - - - for (int i = 0; i < m_maxFrames; ++i) - { - m_pFrames[i] = new float[Filter::NBANDS]; - if ( !m_pFrames[i] ) - throw std::runtime_error("Allocation failed on m_pFrames"); - } - -} - -// ---------------------------------------------------------------------- - -OptFFT::~OptFFT() -{ - fftwf_destroy_plan(m_p); - - fftwf_free(m_pIn); - fftwf_free(m_pOut); - - for (int i = 0; i < m_maxFrames; ++i) - delete [] m_pFrames[i]; - - delete [] m_pFrames; -} - -// ---------------------------------------------------------------------- - -int OptFFT::process(float* pInData, const size_t dataSize) -{ - // generally is the same of the one we used in the constructor (m_maxFrames) but - // might be less at the end of the stream - int nFrames = static_cast( (dataSize - FRAMESIZE) / OVERLAPSAMPLES + 1 ); - - float* pIn_It = m_pIn; - - for (int i = 0; i < nFrames; ++i) - { - memcpy( pIn_It, &pInData[i*OVERLAPSAMPLES], sizeof(float) * FRAMESIZE); - // apply hanning window - applyHann(pIn_It, FRAMESIZE); - - pIn_It += FRAMESIZE; - } - - // fill the rest with zeroes - if ( nFrames < m_maxFrames ) - memset( pIn_It, 0, sizeof(float) * (m_maxFrames-nFrames) * FRAMESIZE ); - - fftwf_execute(m_p); - - int totSamples = (FRAMESIZE/2+1) * // numSamplesPerFrameOut - nFrames; // the frames actually in the input - - // scaling (?) - float scalingFactor = static_cast(FRAMESIZE) / 2.0f; - for (int k = 0; k < totSamples; ++k) - { - m_pOut[k][0] /= scalingFactor; - m_pOut[k][1] /= scalingFactor; - } - - int frameStart; - unsigned int outBlocStart; - unsigned int outBlocEnd; - - for (int i = 0; i < nFrames; ++i) - { - frameStart = i * (FRAMESIZE/2+1); - - // compute bands - for (unsigned int j = 0; j < Filter::NBANDS; j++) - { - outBlocStart = m_powTable[j] + frameStart; - outBlocEnd = m_powTable[j+1] + frameStart; - - m_pFrames[i][j] = 0; - - // WARNING: We're double counting the last one here. - // this bug is to match matlab's implementation bug in power2band.m - unsigned int end_k = outBlocEnd + static_cast(MINCOEF); - for (unsigned int k = outBlocStart + static_cast(MINCOEF); k <= end_k; k++) - { - m_pFrames[i][j] += m_pOut[k][0] * m_pOut[k][0] + - m_pOut[k][1] * m_pOut[k][1]; - } - - // WARNING: if we change the k<=end to k(outBlocEnd - outBlocStart + 1); - } - } - - return nFrames; -} - -// ----------------------------------------------------------------------------- - -void OptFFT::applyHann( float* pInData, const size_t dataSize ) -{ - assert (dataSize == 2048); - - for ( size_t i = 0; i < dataSize; ++i ) - pInData[i] *= hann[i]; -} - -// ----------------------------------------------------------------------------- - -} // end of namespace - -// ---------------------------------------------------------------------- diff --git a/thirdparty/liblastfm2/src/fingerprint/fplib/OptFFT.h b/thirdparty/liblastfm2/src/fingerprint/fplib/OptFFT.h deleted file mode 100644 index 2a704ee73..000000000 --- a/thirdparty/liblastfm2/src/fingerprint/fplib/OptFFT.h +++ /dev/null @@ -1,63 +0,0 @@ -/* - Copyright 2005-2009 Last.fm Ltd. - - This file is part of liblastfm. - - liblastfm is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - liblastfm is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with liblastfm. If not, see . -*/ -#ifndef __OPT_FFT_H -#define __OPT_FFT_H - -#include -#include - -namespace fingerprint -{ - -class OptFFT -{ -public: - - OptFFT(const size_t maxDataSize); - ~OptFFT(); - - int - process(float* pInData, const size_t dataSize); - - float** - getFrames() { return m_pFrames; } - -private: - - void applyHann(float* pInData, const size_t dataSize); - - fftwf_plan m_p; - fftwf_complex * m_pOut; - float* m_pIn; - - //float m_base; - - int m_numSamples; - int m_numOutSamples; - - float** m_pFrames; - int m_maxFrames; - - std::vector m_powTable; - -}; - -} // end of namespace - -#endif // OPT_FFT diff --git a/thirdparty/liblastfm2/src/fingerprint/fplib/fp_helper_fun.h b/thirdparty/liblastfm2/src/fingerprint/fplib/fp_helper_fun.h deleted file mode 100644 index 947b63037..000000000 --- a/thirdparty/liblastfm2/src/fingerprint/fplib/fp_helper_fun.h +++ /dev/null @@ -1,443 +0,0 @@ -/* - Copyright 2005-2009 Last.fm Ltd. - - This file is part of liblastfm. - - liblastfm is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - liblastfm is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with liblastfm. If not, see . -*/ -#ifndef __FINGERPRINT_HELPER_FUNCTIONS_H -#define __FINGERPRINT_HELPER_FUNCTIONS_H - -#include -#include -#include - -namespace fingerprint -{ - -// ----------------------------------------------------------------------------- - -static const size_t FINGERPRINT_LIB_VERSION = 1; -static const float QUERY_START_SECS = 20; -static const float QUERY_SIZE_SECS = 14; -static const float UPDATE_SIZE_SECS = 10; -//FFT needs also a buffer that depends on the input freq. 3 secs should be enough up to 48Khz -static const float GUARD_SIZE_SECS = 3; -static const float NORMALIZATION_SKIP_SECS = 2.5; -static const int MIN_UNIQUE_KEYS = 75; -static const unsigned int MAX_GOOD_GROUP_SIZE = 200; -static const int SHA_SIZE = 32; - -///////////////////////////////////////////////////// -// For FFT. DO NOT TOUCH THEM! -// number of samples in a frame -static const int FRAMESIZE = 2048; -static const int OVERLAP = 32; -static const int OVERLAPSAMPLES = (FRAMESIZE/OVERLAP); // 64 - -// down-sampled frequency -static const int DFREQ = 5512; -static const float FDFREQ = 5512.5f; - -// ----------------------------------------------------------------------------- - -struct GroupData -{ - unsigned int key; // the key (or local descriptor) - unsigned int count; // the number of frames sharing this key -}; - -// ----------------------------------------------------------------------------- -// ----------------------------------------------------------------------------- - -inline -unsigned int getTotalKeys( - int mSecs ) -{ - return static_cast((static_cast(mSecs) / (1000.0 * OVERLAPSAMPLES) ) * DFREQ ) + 1; -} - -// ----------------------------------------------------------------------------- - -template -void simpleSkip( - GroupDataIt& begIt, const GroupDataIt& endIt, - unsigned int numSkipKeys ) -{ - if ( numSkipKeys <= 0 ) - return; - - unsigned int nKeys; - for ( nKeys = 0; nKeys < numSkipKeys && begIt != endIt; ++begIt ) - nKeys += begIt->count; - - // clear crop at the end - if ( nKeys > numSkipKeys ) - { - --begIt; - begIt->count = nKeys - numSkipKeys; - } - -} - -// ----------------------------------------------------------------------------- - -template -void cutGroups( - std::vector& groups, - const unsigned int startMS, - const unsigned int lengthMS ) -{ - typename std::vector::iterator itBeg = groups.begin(), itEnd = groups.begin(); - - unsigned int keys_begin, keys_end; - - for (keys_begin = getTotalKeys(startMS); - itBeg != groups.end() && keys_begin > itBeg->count; ++itBeg) - keys_begin -= itBeg->count; - - for (keys_end = getTotalKeys(startMS + lengthMS); - itEnd != groups.end() && keys_end > itEnd->count; ++itEnd) - keys_end -= itEnd->count; - - if (itBeg == groups.end()) // in the umpossible scenario that you try to cut past the size of the groups - { - groups.clear(); - return; - } - - itBeg->count -= keys_begin; - if (keys_end > 0 && itEnd != groups.end()) - { - itEnd->count = keys_end; - ++itEnd; - } - - copy(itBeg, itEnd, groups.begin()); - groups.resize(itEnd - itBeg); - - keys_begin = getTotalKeys(lengthMS); - for (typename std::vector::iterator it = groups.begin(); it != groups.end(); ++it) - keys_begin -= it->count; -} - -// ------------------------------------------------------------------------- - -template -void keys2GroupData( - const std::vector& keys, // in - std::vector& groupData, - bool clearDst = true ) // out -{ - if (clearDst) - groupData.clear(); - - if (keys.empty()) - return; - - TGroupData tmpGroup; - std::vector::const_iterator it = keys.begin(); - - if ( !groupData.empty() ) - { - // get the last group - tmpGroup = groupData.back(); - groupData.pop_back(); - } - else - { - // new group! - tmpGroup.key = *it; - tmpGroup.count = 1; - ++it; // move to the next key - } - - for (; it != keys.end(); ++it) - { - if ( *it != tmpGroup.key ) - { - // new group ready! - groupData.push_back( tmpGroup ); - tmpGroup.key = *it; - tmpGroup.count = 0; - } - - ++tmpGroup.count; - } - - // last group - groupData.push_back( tmpGroup ); -} - -// ------------------------------------------------------------------------- - -template -void keys2GroupData( - const std::vector& keys, // in - std::deque& groupData, - bool clearDst = true ) // out -{ - if (clearDst) - groupData.clear(); - - if (keys.empty()) - return; - - TGroupData tmpGroup; - std::vector::const_iterator it = keys.begin(); - - if ( !groupData.empty() ) - { - // get the last group - tmpGroup = groupData.back(); - groupData.pop_back(); - } - else - { - // new group! - tmpGroup.key = *it; - tmpGroup.count = 1; - ++it; // move to the next key - } - - for (; it != keys.end(); ++it) - { - if ( *it != tmpGroup.key ) - { - // new group ready! - groupData.push_back( tmpGroup ); - tmpGroup.key = *it; - tmpGroup.count = 0; - } - - ++tmpGroup.count; - } - - // last group - groupData.push_back( tmpGroup ); -} - -// ------------------------------------------------------------------------- - -template -inline -void groupData2Keys( - const std::vector& groupData, // in - std::vector& keys ) // out -{ - keys.clear(); - - typename std::vector::const_iterator it; - - for (it = groupData.begin(); it != groupData.end(); ++it) - { - for (unsigned int j = 0; j < it->count; ++j) - keys.push_back(it->key); - } -} - -// ------------------------------------------------------------------------- - -template -bool findSignificantGroups( - GroupDataIt& beg, GroupDataIt& end, unsigned int& offset_left, unsigned int& offset_right, - unsigned int windowKeySize, unsigned int subWindowKeySize, unsigned int minUniqueKeys) -{ - GroupDataIt itBeg = beg, itEnd = beg, itWindowBeg = beg, itWindowEnd = beg; - - offset_left = 0; - unsigned int window_offset_left; - unsigned int window_offset_right; - - // this amounts to around a 500 ms hop for, say, a 20 second sub-window - unsigned int key_hop_size = subWindowKeySize / 40; - - // trail out itEnd - for (offset_right = windowKeySize; itEnd != end && offset_right > itEnd->count; ++itEnd) - offset_right -= itEnd->count; - - // dang man, we don't even have enough groups to span the window size - if (itEnd == end && offset_right > 0) - return false; - - // 0 window size means just scan the whole range - if (windowKeySize == 0) - itEnd = end; - - // trail out itWindowBeg - for (window_offset_left = (windowKeySize - subWindowKeySize) / 2; - window_offset_left > itWindowBeg->count; ++itWindowBeg) - window_offset_left -= itWindowBeg->count; - - // trail out itWindowEnd - for (window_offset_right = (windowKeySize + subWindowKeySize) / 2; - window_offset_right > itWindowEnd->count; ++itWindowEnd) - window_offset_right -= itWindowEnd->count; - - while (itEnd != end) - { - if (enoughUniqueGoodGroups(itWindowBeg, itWindowEnd, minUniqueKeys)) - { - beg = itBeg; - end = itEnd; - return true; - } - - // okay, jump key_hop_size on end iterator - for (offset_right += key_hop_size; itEnd != end && offset_right > itEnd->count; ++itEnd) - offset_right -= itEnd->count; - - // if we didn't hop the full hop size, modify the hop size to only hop as far as we hopped - if (itEnd == end) - key_hop_size -= offset_right; - - for (offset_left += key_hop_size; offset_left > itBeg->count; ++itBeg) - offset_left -= itBeg->count; - for (window_offset_right += key_hop_size; window_offset_right > itWindowEnd->count; ++itWindowEnd) - window_offset_right -= itWindowEnd->count; - for (window_offset_left += key_hop_size; window_offset_left > itWindowBeg->count; ++itWindowBeg) - window_offset_left -= itWindowBeg->count; - } - - beg = itBeg; - end = itEnd; - - return enoughUniqueGoodGroups(itWindowBeg, itWindowEnd, minUniqueKeys); -} - -// ----------------------------------------------------------------------------- - -template -bool -reduceGroups( - std::vector& groups, unsigned int startKeySize, - unsigned int windowKeySize, unsigned int subWindowKeySize, unsigned int minUniqueKeys ) -{ - unsigned int offset_left = 0; - unsigned int offset_right = 0; - - typename std::vector::iterator begIt = groups.begin(); - typename std::vector::iterator endIt = groups.end(); - - simpleSkip(begIt, endIt, startKeySize); - bool result = findSignificantGroups( begIt, endIt, - offset_left, offset_right, - windowKeySize, subWindowKeySize, minUniqueKeys ); - - if ( !result ) - { - groups.clear(); - return false; - } - - begIt->count -= offset_left; - if (offset_right > 0 && endIt != groups.end()) - { - endIt->count = offset_right; - ++endIt; - } - - std::vector resGrups(begIt, endIt); - groups.swap(resGrups); - - return true; -} - - -// ------------------------------------------------------------------------- - -template -inline bool enoughUniqueGoodGroups( - const GroupDataIt& beg, - const GroupDataIt& end, - unsigned int minUniqueKeys) -{ - std::set groupKeys; - - for (GroupDataIt it = beg; it != end && static_cast(groupKeys.size()) < minUniqueKeys; ++it) - { - if (it->count > MAX_GOOD_GROUP_SIZE) - return false; - - groupKeys.insert(it->key); - } - - return static_cast(groupKeys.size()) >= minUniqueKeys; -} - -// ----------------------------------------------------------------------------- -////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////// -// Used by the fingerprint keys operation - -// minimum and maximum frequency to consider -#define MINFREQ 300 -#define MAXFREQ 2000 - -// amount of time in a frame -#define FRAME_TLEN ((float) FRAMESIZE / (float) DFREQ) -#define MINCOEF (FRAME_TLEN * MINFREQ) - -#define round__(x) ((int)(x + .5)) - -struct RawFilter -{ - unsigned int ftid; - float thresh; - float weight; -}; - -const RawFilter rFilters[] = { - { 26752, -4.37515e-07f, 0.260836f }, // filterID, threshold, alpha (weight) - { 23871, -2.44615e-05f, 0.263986f }, - { 26777, -3.69244e-08f, 0.267763f }, - { 4635, -1.13672e-05f, 0.269428f }, - { 2937, 5.28804e-09f, 0.271896f }, - { 27405, -0.000126494f, 0.272362f }, - { 10782, 4.27478e-08f, 0.272609f }, - { 21033, -6.7912e-07f, 0.276099f }, - { 27117, 8.07178e-06f, 0.277762f }, - { 27072, 2.46044e-05f, 0.27883f }, - { 24228, 4.11255e-07f, 0.281743f }, - { 23838, 0.000228396f, 0.284479f }, - { 17165, -1.19495e-07f, 0.286304f }, - { 25263, 0.000398279f, 0.287066f }, - { 20721, 7.15095e-07f, 0.288913f }, - { 8502, -2.78361e-07f, 0.290424f }, - { 17175, -1.08429e-08f, 0.292219f }, - { 17811, -3.29527e-08f, 0.292554f }, - { 27495, -4.47575e-07f, 0.290119f }, - { 23538, -3.04273e-09f, 0.294539f }, - { 8205, 4.02691e-07f, 0.293525f }, - { 12177, 1.16873e-06f, 0.293832f }, - { 27051, -0.000902544f, 0.296453f }, - { 27111, -2.38425e-05f, 0.297428f }, - { 21779, -1.0669e-07f, 0.297302f }, - { 14817, -9.52849e-09f, 0.299f }, - { 27087, 1.22163e-05f, 0.296502f }, - { 27081, -2.8758e-09f, 0.300112f }, - { 20394, 1.28237e-06f, 0.298693f }, - { 28209, 0.000624447f, 0.29812f }, - { 23533, -2.19406e-06f, 0.299773f }, - { 23865, -1.28037e-08f, 0.300777f } // this is iteration 1 -}; - -// ----------------------------------------------------------------------------- - -} - -// ----------------------------------------------------------------------------- - -#endif // __FINGERPRINT_HELPER_FUNCTIONS_H - diff --git a/thirdparty/liblastfm2/src/global.h b/thirdparty/liblastfm2/src/global.h deleted file mode 100644 index 8a513d802..000000000 --- a/thirdparty/liblastfm2/src/global.h +++ /dev/null @@ -1,132 +0,0 @@ -/* - Copyright 2009 Last.fm Ltd. - - Primarily authored by Max Howell, Jono Cole and Doug Mansell - - This file is part of liblastfm. - - liblastfm is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - liblastfm is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with liblastfm. If not, see . -*/ - -#ifndef LASTFM_GLOBAL_H -#define LASTFM_GLOBAL_H - -#define LASTFM_VERSION 0x00000400 -#define LASTFM_VERSION_STRING "0.4.0" -#define LASTFM_MAJOR_VERSION 0 -#define LASTFM_MINOR_VERSION 4 -#define LASTFM_PATCH_VERSION 0 - - -#include - -#ifndef LASTFM_LIB_STATIC -#ifdef LASTFM_LIB - #define LASTFM_DLLEXPORT Q_DECL_EXPORT -#else - #define LASTFM_DLLEXPORT Q_DECL_IMPORT -#endif -#ifdef LASTFM_FINGERPRINT_LIB - #define LASTFM_FINGERPRINT_DLLEXPORT Q_DECL_EXPORT -#else - #define LASTFM_FINGERPRINT_DLLEXPORT Q_DECL_IMPORT -#endif -#else // LASTFM_LIB_STATIC - #define LASTFM_DLLEXPORT - #define LASTFM_FINGERPRINT_DLLEXPORT -#endif // LASTFM_LIB_STATIC - - -#include -#include - -namespace lastfm -{ - /** http://labs.trolltech.com/blogs/2008/10/09/coding-tip-pretty-printing-enum-values - * Tips for making this take a single parameter welcome! :) - * - * eg. lastfm::qMetaEnumString( error, "NetworkError" ); - */ - template static inline QString qMetaEnumString( int enum_value, const char* enum_name ) - { - QMetaObject meta = T::staticMetaObject; - for (int i=0; i < meta.enumeratorCount(); ++i) - { - QMetaEnum m = meta.enumerator(i); - if (m.name() == QLatin1String(enum_name)) - return QLatin1String(m.valueToKey(enum_value)); - } - return QString("Unknown enum value for \"%1\": %2").arg( enum_name ).arg( enum_value ); - } - - - enum ImageSize - { - Small, - Medium, - Large, /** seemingly 174x174 */ - ExtraLarge, - Mega - }; - - - //convenience - class Album; - class Artist; - class Audioscrobbler; - class AuthenticatedUser; - class Fingerprint; - class FingerprintableSource; - class FingerprintId; - class Mbid; - class MutableTrack; - class NetworkAccessManager; - class Playlist; - class User; - class RadioStation; - class Tag; - class Track; - class XmlQuery; - class Xspf; -} - - -#ifdef LASTFM_COLLAPSE_NAMESPACE -using lastfm::Album; -using lastfm::Artist; -using lastfm::Audioscrobbler; -using lastfm::AuthenticatedUser; -using lastfm::Fingerprint; -using lastfm::FingerprintId; -using lastfm::Mbid; -using lastfm::MutableTrack; -using lastfm::Playlist; -using lastfm::User; -using lastfm::RadioStation; -using lastfm::Tag; -using lastfm::Track; -using lastfm::XmlQuery; -using lastfm::Xspf; -#endif - - -//convenience -class QDomDocument; -class QNetworkAccessManager; -class QNetworkReply; - - -//convenience for development -#include - -#endif //LASTFM_GLOBAL_H diff --git a/thirdparty/liblastfm2/src/lastfm.pro b/thirdparty/liblastfm2/src/lastfm.pro deleted file mode 100644 index e3ae70af6..000000000 --- a/thirdparty/liblastfm2/src/lastfm.pro +++ /dev/null @@ -1,87 +0,0 @@ -TEMPLATE = lib -QT = core network xml - -INSTALLS = target -target.path = /lib - -win32{ - DEFINES += LASTFM_LIB _ATL_DLL - LIBS += winhttp.lib wbemuuid.lib # ws configuration -} -mac{ - LIBS += -framework SystemConfiguration # ws configuration - #TODO we should only use these with the carbon version of Qt! - LIBS += -framework Carbon -framework CoreFoundation # various -} - -linux*{ - QT += dbus -} - -SOURCES += \ - ws/ws.cpp \ - ws/NetworkConnectionMonitor.cpp \ - ws/NetworkAccessManager.cpp \ - ws/InternetConnectionMonitor.cpp \ - types/Xspf.cpp \ - types/User.cpp \ - types/Track.cpp \ - types/Tasteometer.cpp \ - types/Tag.cpp \ - types/Playlist.cpp \ - types/Mbid.cpp \ - types/FingerprintId.cpp \ - types/Artist.cpp \ - types/Album.cpp \ - scrobble/ScrobbleCache.cpp \ - scrobble/Audioscrobbler.cpp \ - radio/RadioTuner.cpp \ - radio/RadioStation.cpp \ - core/XmlQuery.cpp \ - core/UrlBuilder.cpp \ - core/misc.cpp - -HEADERS += \ - ws/ws.h \ - ws/NetworkConnectionMonitor.h \ - ws/NetworkAccessManager.h \ - ws/InternetConnectionMonitor.h \ - types/Xspf.h \ - types/User.h \ - types/Track.h \ - types/Tasteometer.h \ - types/Tag.h \ - types/Playlist.h \ - types/Mbid.h \ - types/FingerprintId.h \ - types/Artist.h \ - types/Album.h \ - types/AbstractType.h \ - scrobble/ScrobblePoint.h \ - scrobble/ScrobbleCache.h \ - scrobble/Audioscrobbler.h \ - radio/RadioTuner.h \ - radio/RadioStation.h \ - global.h \ - core/XmlQuery.h \ - core/UrlBuilder.h \ - core/misc.h - -win32:SOURCES += ws/win/WNetworkConnectionMonitor_win.cpp \ - ws/win/WmiSink.cpp \ - ws/win/Pac.cpp \ - ws/win/NdisEvents.cpp - -win32:HEADERS += ws/win/WNetworkConnectionMonitor.h \ - ws/win/WmiSink.h \ - ws/win/Pac.h \ - ws/win/NdisEvents.h \ - ws/win/IeSettings.h \ - ws/win/ComSetup.h - -mac:SOURCES += ws/mac/MNetworkConnectionMonitor_mac.cpp - -mac:HEADERS += ws/mac/ProxyDict.h \ - ws/mac/MNetworkConnectionMonitor.h - -!win32:VERSION = 0.4.0 diff --git a/thirdparty/liblastfm2/src/radio/RadioStation.cpp b/thirdparty/liblastfm2/src/radio/RadioStation.cpp deleted file mode 100755 index c0889d409..000000000 --- a/thirdparty/liblastfm2/src/radio/RadioStation.cpp +++ /dev/null @@ -1,337 +0,0 @@ -/* - Copyright 2009 Last.fm Ltd. - - This file is part of liblastfm. - - liblastfm is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - liblastfm is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with liblastfm. If not, see . -*/ - -#include -#include - -#include "RadioStation.h" -#include "../core/XmlQuery.h" - - -const float k_defaultRep(0.5); -const float k_defaultMainstr(0.5); -const bool k_defaultDisco(false); - -lastfm::RadioStation -lastfm::RadioStation::library( const lastfm::User& user ) -{ - QList users; - users << user; - return library( users ); -} - -lastfm::RadioStation -lastfm::RadioStation::library( QList& users ) -{ - RadioStation s( libraryStr( users ) ); - if( users.count() == 1 ) - s.setTitle( QObject::tr( "%1%2s Library Radio").arg( lastfm::ws::Username, QChar(0x2019) )); - - else { - QString title; - for( QList::const_iterator i = users.begin(); i != users.end(); i++ ) { - if( i == users.end() - 1 ) - title += " and " + *i; - else - title += ", " + *i; - } - - s.setTitle( title ); - } - - return s; -} - - -lastfm::RadioStation -lastfm::RadioStation::recommendations( const lastfm::User& user ) -{ - RadioStation s( recommendationsStr( user ) ); - - s.setTitle( QObject::tr( "%1%2s Recommended Radio").arg( lastfm::ws::Username, QChar(0x2019) )); - - return s; -} - -lastfm::RadioStation -lastfm::RadioStation::friends( const lastfm::User& user ) -{ - RadioStation s( friendsStr( user ) ); - - s.setTitle( QObject::tr( "%1%2s Friends Radio").arg( lastfm::ws::Username, QChar(0x2019) )); - - return s; -} - -lastfm::RadioStation -lastfm::RadioStation::neighbourhood( const lastfm::User& user ) -{ - RadioStation s( neighbourhoodStr( user ) ); - s.setTitle( QObject::tr( "%1%2s Neighbours%2 Radio").arg( lastfm::ws::Username, QChar(0x2019) )); - return s; -} - - -lastfm::RadioStation -lastfm::RadioStation::tag( const lastfm::Tag& tag ) -{ - QList tags; - tags << tag; - return lastfm::RadioStation::tag( tags ); -} - - -lastfm::RadioStation -lastfm::RadioStation::tag( QList& tag ) -{ - return RadioStation( tagStr( tag ) ); -} - - -lastfm::RadioStation -lastfm::RadioStation::similar( const lastfm::Artist& artist ) -{ - QList artists; - artists << artist; - return similar( artists ); -} - - -lastfm::RadioStation -lastfm::RadioStation::similar( QList& artists ) -{ - return RadioStation( similarStr( artists ) ); -} - - -lastfm::RadioStation -lastfm::RadioStation::mix( const lastfm::User& user ) -{ - RadioStation s( mixStr( user ) ); - s.setTitle( QObject::tr( "%1%2s Mix Radio").arg( lastfm::ws::Username, QChar(0x2019) ) ); - return s; -} - - -QString -lastfm::RadioStation::url() const -{ - return m_url.toString() + (m_tagFilter.isEmpty() ? "" : "/tag/" + m_tagFilter); -} - - -void -lastfm::RadioStation::setTitle( const QString& s ) -{ - // Stop the radio station getting renamed when the web services don't know what it's called - if ( !m_title.isEmpty() && s.compare( "a radio station", Qt::CaseInsensitive ) == 0 ) - return; - - QString title = s.trimmed(); - - if ( title.compare( QObject::tr("%1%2s Library Radio").arg( lastfm::ws::Username, QChar(0x2019) ), Qt::CaseInsensitive ) == 0 ) - title = QObject::tr("My Library Radio"); - else if ( title.compare( QObject::tr("%1%2s Mix Radio").arg( lastfm::ws::Username, QChar(0x2019) ), Qt::CaseInsensitive ) == 0 ) - title = QObject::tr("My Mix Radio"); - else if ( title.compare( QObject::tr("%1%2s Recommended Radio").arg( lastfm::ws::Username, QChar(0x2019) ), Qt::CaseInsensitive ) == 0 ) - title = QObject::tr("My Recommended Radio"); - else if ( title.compare( QObject::tr("%1%2s Friends%2 Radio").arg( lastfm::ws::Username, QChar(0x2019) ), Qt::CaseInsensitive ) == 0 ) - title = QObject::tr("My Friends%1 Radio").arg( QChar( 0x2019 ) ); - else if ( title.compare( QObject::tr("%1%2s Friends Radio").arg( lastfm::ws::Username, QChar(0x2019) ), Qt::CaseInsensitive ) == 0 ) - title = QObject::tr("My Friends%1 Radio").arg( QChar( 0x2019 ) ); - else if ( title.compare( QObject::tr("%1%2s Neighbours%2 Radio").arg( lastfm::ws::Username, QChar(0x2019) ), Qt::CaseInsensitive ) == 0 ) - title = QObject::tr("My Neighbours%1 Radio").arg( QChar( 0x2019 ) ); - else if ( title.compare( QObject::tr("%1%2s Neighbours Radio").arg( lastfm::ws::Username ), Qt::CaseInsensitive ) == 0 ) - title = QObject::tr("My Neighbours%1 Radio").arg( QChar( 0x2019 ) ); - - m_title = title; -} - - -QString -lastfm::RadioStation::title() const -{ - return m_title; // + (m_tagFilter.isEmpty() ? "" : ": " + m_tagFilter); -} - - -void -lastfm::RadioStation::setTagFilter( const QString& tag ) -{ - m_tagFilter = tag; -} - - -QNetworkReply* -lastfm::RadioStation::getSampleArtists( int limit ) const -{ - QMap map; - map["method"] = "radio.getSampleArtists"; - map["station"] = m_url.toString(); - map["limit"] = QString::number( limit ); - return ws::get( map ); -} - - -QNetworkReply* -lastfm::RadioStation::getTagSuggestions( int limit ) const -{ - QMap map; - map["method"] = "radio.getTagSuggestions"; - map["station"] = m_url.toString(); - map["limit"] = QString::number( limit ); - return ws::get( map ); -} - - -//static -QList -lastfm::RadioStation::list( QNetworkReply* r ) -{ - QList result; - try { - foreach (XmlQuery xq, XmlQuery( r->readAll() ).children("station")) { - lastfm::RadioStation rs( QUrl::fromPercentEncoding( xq["url"].text().toUtf8() ) ); - rs.setTitle(xq["name"].text()); - result.append(rs); - } - } - catch (ws::ParseError& e) - { - qWarning() << e.what(); - } - return result; -} - - -bool -lastfm::RadioStation::operator==( const RadioStation& that ) const -{ - return this->m_url == that.m_url && this->m_tagFilter == that.m_tagFilter; -} - - -void -lastfm::RadioStation::setString( const QString& string ) -{ - // If it's a tag filtered station then extract that part - QString tempString = string; - - if ( !tempString.startsWith("lastfm://tag/") ) - { - int index = tempString.indexOf("/tag/"); - - if ( index != -1 ) - { - m_tagFilter = tempString.mid( index + 5, tempString.count() - (index + 5) ); - tempString = tempString.mid( 0, index ); - } - } - - m_url = tempString; -} - - -void -lastfm::RadioStation::setRep(float rep) -{ - m_rep = rep; -} - - -void -lastfm::RadioStation::setMainstr(float mainstr) -{ - m_mainstr = mainstr; -} - - -void -lastfm::RadioStation::setDisco(bool disco) -{ - m_disco = disco; -} - - -float lastfm::RadioStation::rep() const -{ - return m_rep; -} - - -float lastfm::RadioStation::mainstr() const -{ - return m_mainstr; -} - - -bool lastfm::RadioStation::disco() const -{ - return m_disco; -} - - -QString lastfm::RadioStation::libraryStr( QList& users ) -{ - qSort(users.begin(), users.end()); - - QString url = (users.count() > 1) ? "lastfm://users/" : "lastfm://user/"; - - url.append( users[0].name() ); - - for ( int i = 1 ; i < users.count() ; ++i ) - url.append( "," + users[i].name() ); - - url.append("/personal"); - - return url; -} - - -QString lastfm::RadioStation::tagStr( QList& tags ) -{ - qSort(tags.begin(), tags.end()); - - QString url = (tags.count() > 1) ? "lastfm://tag/" : "lastfm://globaltags/"; - - url.append( tags[0].name() ); - - for ( int i = 1 ; i < tags.count() ; ++i ) - url.append( "*" + tags[i].name() ); - - return url; -} - - -QString lastfm::RadioStation::similarStr( QList& artists ) -{ - qSort(artists.begin(), artists.end()); - - QString url = (artists.count() > 1) ? "lastfm://artistnames/" : "lastfm://artist/"; - - url.append( artists[0].name() ); - - for ( int i = 1 ; i < artists.count() ; ++i ) - url.append( "," + artists[i].name() ); - - if (artists.count() == 1) - url.append( "/similarartists" ); - - return url; -} diff --git a/thirdparty/liblastfm2/src/radio/RadioStation.h b/thirdparty/liblastfm2/src/radio/RadioStation.h deleted file mode 100644 index 816c49657..000000000 --- a/thirdparty/liblastfm2/src/radio/RadioStation.h +++ /dev/null @@ -1,123 +0,0 @@ -/* - Copyright 2009 Last.fm Ltd. - - Primarily authored by Max Howell, Jono Cole and Doug Mansell - - This file is part of liblastfm. - - liblastfm is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - liblastfm is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with liblastfm. If not, see . -*/ -#ifndef LASTFM_RADIO_STATION_H -#define LASTFM_RADIO_STATION_H - -#include -#include -#include - -namespace lastfm -{ - /** @author - */ - class LASTFM_DLLEXPORT RadioStation - { - public: - RadioStation() - {} - RadioStation( const QString& s ) - { - setString( s ); - } - - static RadioStation library( const lastfm::User& user ); - static RadioStation library( QList& users ); - - static RadioStation similar( const lastfm::Artist& artist ); - static RadioStation similar( QList& artist ); - - static RadioStation tag( const lastfm::Tag& tag ); - static RadioStation tag( QList& tag ); - - static RadioStation recommendations( const lastfm::User& user ); - static RadioStation friends( const lastfm::User& user ); - static RadioStation neighbourhood( const lastfm::User& user ); - - static RadioStation mix( const lastfm::User& user ); - - QNetworkReply* getSampleArtists( int limit = 50 ) const; - QNetworkReply* getTagSuggestions( int limit = 50 ) const; - - /** eg. "mxcl's Loved Tracks" - * It is worth noting that the Radio doesn't set the title of RadioStation - * object until we have tuned to it, and then we only set the one we give - * you back. - */ - QString title() const; - /** the Last.fm url, eg. lastfm://user/mxcl/loved */ - QString url() const; - - void setTitle( const QString& title ); - - void setTagFilter( const QString& tag ); - - void setRep(float rep); - void setMainstr(float mainstr); - void setDisco(bool disco); - - float rep() const; - float mainstr() const; - bool disco() const; - - bool isLegacyPlaylist() const - { - return m_url.toString().startsWith( "lastfm://play/" ) || - m_url.toString().startsWith( "lastfm://preview/" ) || - m_url.toString().startsWith( "lastfm://track/" ) || - m_url.toString().startsWith( "lastfm://playlist/" ); - } - - // good for getRecentStations: - static QList list( QNetworkReply* ); - - bool operator==( const RadioStation& that ) const; - - private: - void setString( const QString& s ); - - static QString libraryStr( QList& user ); - static QString recommendationsStr( const lastfm::User& user ) { return "lastfm://user/" + user + "/recommended"; } - static QString friendsStr( const lastfm::User& user ) { return "lastfm://user/" + user + "/friends"; } - static QString neighbourhoodStr( const lastfm::User& user ) { return "lastfm://user/" + user + "/neighbours"; } - static QString tagStr( QList& tag ); - static QString similarStr( QList& artist ); - static QString mixStr( const lastfm::User& user ) { return "lastfm://user/" + user + "/mix"; } - private: - QUrl m_url; - QString m_title; - QString m_tagFilter; - - float m_rep; - float m_mainstr; - bool m_disco; - }; -} - - -Q_DECLARE_METATYPE( lastfm::RadioStation ) - - -inline QDebug operator<<( QDebug d, const lastfm::RadioStation& station ) -{ - return d << station.url(); -} - -#endif diff --git a/thirdparty/liblastfm2/src/radio/RadioTuner.cpp b/thirdparty/liblastfm2/src/radio/RadioTuner.cpp deleted file mode 100644 index 9f875ee22..000000000 --- a/thirdparty/liblastfm2/src/radio/RadioTuner.cpp +++ /dev/null @@ -1,219 +0,0 @@ -/* - Copyright 2009 Last.fm Ltd. - - Primarily authored by Max Howell, Jono Cole and Doug Mansell - - This file is part of liblastfm. - - liblastfm is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - liblastfm is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with liblastfm. If not, see . -*/ - -#include - -#include "RadioTuner.h" -#include "../core/XmlQuery.h" -#include "../types/Xspf.h" -#include "../ws/ws.h" - -using namespace lastfm; - -//TODO skips left -//TODO multiple locations for the same track -//TODO set rtp flag in getPlaylist (whether user is scrobbling this radio session or not) - -// limit the number of retries following empty playlists: -#define MAX_TUNING_ATTEMPTS 3 - - -RadioTuner::RadioTuner( const RadioStation& station ) - : m_retry_counter( 0 ), m_fetchingPlaylist( false ), m_requestedPlaylist(false) -{ - m_twoSecondTimer = new QTimer( this ); - m_twoSecondTimer->setSingleShot( true ); - connect( m_twoSecondTimer, SIGNAL(timeout()), SLOT(onTwoSecondTimeout())); - - qDebug() << station.url(); - - //Empty RadioStation implies that the radio - //should tune to the previous station. - if( station.url().isEmpty() ) - { - fetchFiveMoreTracks(); - } - else - { - QMap map; - map["method"] = "radio.tune"; - map["station"] = station.url(); - map["additional_info"] = "1"; - connect( ws::post(map), SIGNAL(finished()), SLOT(onTuneReturn()) ); - } -} - -void -RadioTuner::retune( const RadioStation& station ) -{ - m_playlistQueue.clear(); - m_retuneStation = station; - - qDebug() << station.url(); -} - - -void -RadioTuner::onTuneReturn() -{ - try { - XmlQuery lfm = qobject_cast(sender())->readAll(); - emit title( lfm["station"]["name"].text() ); - - qDebug() << lfm; - - emit supportsDisco( lfm["station"]["supportsdiscovery"].text() == "1" ); - fetchFiveMoreTracks(); - } - catch (ws::ParseError& e) - { - emit error( e.enumValue(), e.message() ); - } -} - - -void -RadioTuner::fetchFiveMoreTracks() -{ - if ( !m_retuneStation.url().isEmpty() ) - { - // We have been asked to retune so do it now - QMap map; - map["method"] = "radio.tune"; - map["station"] = m_retuneStation.url(); - map["additional_info"] = "1"; - - QNetworkReply* reply = ws::post(map); - connect( reply, SIGNAL(finished()), SLOT(onTuneReturn()) ); - - m_retuneStation = RadioStation(); - m_twoSecondTimer->stop(); - } - else - { - if ( !m_twoSecondTimer->isActive() ) - { - //TODO check documentation, I figure this needs a session key - QMap map; - map["method"] = "radio.getPlaylist"; - map["additional_info"] = "1"; - map["rtp"] = "1"; // see above - connect( ws::post( map ), SIGNAL(finished()), SLOT(onGetPlaylistReturn()) ); - m_fetchingPlaylist = true; - } - else - m_requestedPlaylist = true; - } -} - - -bool -RadioTuner::tryAgain() -{ - qDebug() << "Bad response count" << m_retry_counter; - - if (++m_retry_counter > MAX_TUNING_ATTEMPTS) - return false; - fetchFiveMoreTracks(); - return true; -} - - -void -RadioTuner::onGetPlaylistReturn() -{ - // We shouldn't request another playlist for 2 seconds because we'll get the same one - // in a different order. This QTimer will block until it has finished. If one or more - // playlists have been requested in the meantime, it will fetch one on timeout - m_twoSecondTimer->start( 2000 ); - - // This will block us fetching two playlists at once - m_fetchingPlaylist = false; - - try { - XmlQuery lfm = qobject_cast(sender())->readAll(); - emit title( lfm["playlist"]["title"].text() ); - - qDebug() << lfm; - - Xspf* xspf = new Xspf( lfm["playlist"], this ); - connect( xspf, SIGNAL(expired()), SLOT(onXspfExpired()) ); - - if ( xspf->isEmpty() ) - { - // give up after too many empty playlists :( - if (!tryAgain()) - emit error( ws::NotEnoughContent, tr("Not enough content") ); - } - else - { - m_retry_counter = 0; - m_playlistQueue << xspf; - emit trackAvailable(); - } - } - catch (ws::ParseError& e) - { - qWarning() << e.what(); - emit error( e.enumValue(), e.message() ); - } -} - -void -RadioTuner::onTwoSecondTimeout() -{ - if (m_requestedPlaylist) - { - m_requestedPlaylist = false; - fetchFiveMoreTracks(); - } -} - -void -RadioTuner::onXspfExpired() -{ - int index = m_playlistQueue.indexOf( static_cast(sender()) ); - if ( index != -1 ) - m_playlistQueue.takeAt( index )->deleteLater(); -} - -Track -RadioTuner::takeNextTrack() -{ - if ( m_playlistQueue.isEmpty() ) - { - // If there are no tracks here and we're not fetching tracks - // it's probably because the playlist expired so fetch more now - if ( !m_fetchingPlaylist ) - fetchFiveMoreTracks(); - - return Track(); - } - - Track result = m_playlistQueue[0]->takeFirst(); - - if ( m_playlistQueue[0]->isEmpty() ) - m_playlistQueue.removeFirst(); - - if ( m_playlistQueue.isEmpty() ) - fetchFiveMoreTracks(); - - return result; -} diff --git a/thirdparty/liblastfm2/src/radio/RadioTuner.h b/thirdparty/liblastfm2/src/radio/RadioTuner.h deleted file mode 100644 index 7193d53ab..000000000 --- a/thirdparty/liblastfm2/src/radio/RadioTuner.h +++ /dev/null @@ -1,85 +0,0 @@ -/* - Copyright 2009 Last.fm Ltd. - - Primarily authored by Max Howell, Jono Cole and Doug Mansell - - This file is part of liblastfm. - - liblastfm is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - liblastfm is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with liblastfm. If not, see . -*/ -#ifndef LASTFM_TUNER_H -#define LASTFM_TUNER_H - -#include -#include -#include -#include -#include - -namespace lastfm -{ - /** With regard to error handling. We handle Ws::TryAgain up to 5 times, - * don't try again after that! Just tell the user to try again later. - */ - class LASTFM_DLLEXPORT RadioTuner : public QObject - { - Q_OBJECT - - public: - /** You need to have assigned Ws::* for this to work, creating the tuner - * automatically fetches the first 5 tracks for the station */ - explicit RadioTuner( const RadioStation& ); - - Track takeNextTrack(); - - void retune( const RadioStation& ); - - signals: - void title( const QString& ); - void supportsDisco( bool supportsDisco ); - void trackAvailable(); - void error( lastfm::ws::Error, const QString& message ); - - private slots: - void onTuneReturn(); - void onGetPlaylistReturn(); - void onXspfExpired(); - - void onTwoSecondTimeout(); - - private: - /** Tries again up to 5 times - * @returns true if we tried again, otherwise you should emit error */ - bool tryAgain(); - /** Will emit 5 tracks from tracks(), they have to played within an hour - * or the streamer will refuse to stream them. Also the previous five are - * invalidated apart from the one that is currently playing, so sorry, you - * can't build up big lists of tracks. - * - * I feel I must point out that asking the user which one they want to play - * is also not allowed according to our terms and conditions, which you - * already agreed to in order to get your API key. Sorry about that dude. - */ - void fetchFiveMoreTracks(); - - private: - QList m_playlistQueue; - uint m_retry_counter; - bool m_fetchingPlaylist; - bool m_requestedPlaylist; - class QTimer* m_twoSecondTimer; - RadioStation m_retuneStation; - }; -} - -#endif diff --git a/thirdparty/liblastfm2/src/scrobble/Audioscrobbler.cpp b/thirdparty/liblastfm2/src/scrobble/Audioscrobbler.cpp deleted file mode 100644 index a6680fbe2..000000000 --- a/thirdparty/liblastfm2/src/scrobble/Audioscrobbler.cpp +++ /dev/null @@ -1,246 +0,0 @@ -/* - Copyright 2009 Last.fm Ltd. - - Primarily authored by Max Howell, Jono Cole and Doug Mansell - - This file is part of liblastfm. - - liblastfm is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - liblastfm is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with liblastfm. If not, see . -*/ - -#include - -#include "Audioscrobbler.h" -#include "ScrobbleCache.h" - -#include "../types/User.h" -#include "../types/Track.h" -#include "../ws/ws.h" -#include "../core/XmlQuery.h" - - -namespace lastfm -{ - class AudioscrobblerPrivate - { - public: - AudioscrobblerPrivate(const QString& id) - : m_id( id ) - , m_cache( ws::Username ) - {} - - ~AudioscrobblerPrivate() - { - } - - const QString m_id; - ScrobbleCache m_cache; - QList m_batch; - QPointer m_nowPlayingReply; - QPointer m_scrobbleReply; - Track m_nowPlayingTrack; - }; -} - - -lastfm::Audioscrobbler::Audioscrobbler( const QString& id ) - : d( new AudioscrobblerPrivate(id) ) -{ - submit(); -} - - -lastfm::Audioscrobbler::~Audioscrobbler() -{ - delete d; -} - - -void -lastfm::Audioscrobbler::nowPlaying( const Track& track ) -{ - if ( d->m_nowPlayingReply.isNull()) - { - d->m_nowPlayingTrack = track; - d->m_nowPlayingReply = track.updateNowPlaying(); - connect( d->m_nowPlayingReply, SIGNAL(finished()), SLOT(onNowPlayingReturn())); - } -} - - -void -lastfm::Audioscrobbler::cache( const Track& track ) -{ - QList tracks; - tracks.append( track ); - cacheBatch( tracks ); -} - - -void -lastfm::Audioscrobbler::cacheBatch( const QList& tracks ) -{ - d->m_cache.add( tracks ); - - foreach ( const Track& track, d->m_cache.tracks() ) - MutableTrack( track ).setScrobbleStatus( Track::Cached ); - - emit scrobblesCached( tracks ); - submit(); -} - - -void -lastfm::Audioscrobbler::submit() -{ - if (d->m_cache.tracks().isEmpty() // there are no tracks to submit - || !d->m_scrobbleReply.isNull() ) // we are already submitting scrobbles - return; - - // copy tracks to be submitted to a temporary list - d->m_batch = d->m_cache.tracks().mid( 0, 50 ); - - // if there is only one track use track.scrobble, otherwise use track.scrobbleBatch - if (d->m_batch.count() == 1) - d->m_scrobbleReply = d->m_batch[0].scrobble(); - else - d->m_scrobbleReply = lastfm::Track::scrobble( d->m_batch ); - - connect( d->m_scrobbleReply, SIGNAL(finished()), SLOT(onTrackScrobbleReturn())); -} - -void -lastfm::Audioscrobbler::parseTrack( const XmlQuery& trackXml, const Track& track ) -{ - MutableTrack mTrack = MutableTrack( track ); - bool isScrobble = QDomElement(trackXml).tagName() == "scrobble"; - - if ( trackXml["ignoredMessage"].attribute("code") == "0" ) - { - if ( isScrobble ) mTrack.setScrobbleStatus( Track::Submitted ); - - // corrections! - if ( trackXml["track"].attribute("corrected") == "1" - || trackXml["artist"].attribute("corrected") == "1" - || trackXml["album"].attribute("corrected") == "1" - || trackXml["albumArtist"].attribute("corrected") == "1") - { - mTrack.setCorrections(trackXml["track"].text(), - trackXml["album"].text(), - trackXml["artist"].text(), - trackXml["albumArtist"].text()); - } - } - else if ( isScrobble ) - { - mTrack.setScrobbleError( static_cast(trackXml["ignoredMessage"].attribute("code").toInt()) ); - mTrack.setScrobbleStatus( Track::Error ); - } -} - -void -lastfm::Audioscrobbler::onNowPlayingReturn() -{ - try - { - lastfm::XmlQuery lfm = static_cast(sender())->readAll(); - - qDebug() << lfm; - - if ( lfm.attribute("status") == "ok" ) - parseTrack( lfm["nowplaying"], d->m_nowPlayingTrack ); - else - emit nowPlayingError( lfm["error"].attribute("code").toInt(), lfm["error"].text() ); - - d->m_nowPlayingTrack = Track(); - d->m_nowPlayingReply = 0; - } - catch ( lastfm::ws::ParseError p ) - { - qDebug() << p.message() << p.enumValue(); - } - catch ( lastfm::ws::Error p ) - { - qDebug() << p; - } - - d->m_nowPlayingTrack = Track(); - d->m_nowPlayingReply = 0; -} - - -void -lastfm::Audioscrobbler::onTrackScrobbleReturn() -{ - try - { - lastfm::XmlQuery lfm = d->m_scrobbleReply->readAll(); - - qDebug() << lfm; - - if (lfm.attribute("status") == "ok") - { - int index = 0; - - foreach ( const XmlQuery& scrobble, lfm["scrobbles"].children("scrobble") ) - parseTrack( scrobble, d->m_batch.at( index++ ) ); - - emit scrobblesSubmitted( d->m_batch ); - - d->m_cache.remove( d->m_batch ); - d->m_batch.clear(); - } - else if ( d->m_scrobbleReply->error() == QNetworkReply::NoError ) - { - // The scrobble submission failed, but the http request was sucessful - - if ( !(lfm["error"].attribute("code") == "9" // Bad session - || lfm["error"].attribute("code") == "11" // Service offline - || lfm["error"].attribute("code") == "16") ) // Service temporarily unavailable - { - foreach ( const Track& track, d->m_batch ) - { - MutableTrack mTrack = MutableTrack( track ); - mTrack.setScrobbleError( static_cast(lfm["error"].attribute("code").toInt()) ); - mTrack.setScrobbleErrorText( lfm["error"].text() ); - mTrack.setScrobbleStatus( Track::Error ); - } - - emit scrobblesSubmitted( d->m_batch ); - - // clear the cache if it was not one of these error codes - d->m_cache.remove( d->m_batch ); - d->m_batch.clear(); - } - else - { - Q_ASSERT(false); - } - } - - d->m_scrobbleReply = 0; - - // check is there are anymore scrobbles to submit - submit(); - } - catch ( lastfm::ws::ParseError p ) - { - qDebug() << p.message() << p.enumValue(); - d->m_scrobbleReply = 0; - } - catch ( lastfm::ws::Error p ) - { - qDebug() << p; - d->m_scrobbleReply = 0; - } -} diff --git a/thirdparty/liblastfm2/src/scrobble/Audioscrobbler.h b/thirdparty/liblastfm2/src/scrobble/Audioscrobbler.h deleted file mode 100644 index 02e381415..000000000 --- a/thirdparty/liblastfm2/src/scrobble/Audioscrobbler.h +++ /dev/null @@ -1,78 +0,0 @@ -/* - Copyright 2009 Last.fm Ltd. - - Primarily authored by Max Howell, Jono Cole and Doug Mansell - - This file is part of liblastfm. - - liblastfm is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - liblastfm is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with liblastfm. If not, see . -*/ -#ifndef LASTFM_AUDIOSCROBBLER_H -#define LASTFM_AUDIOSCROBBLER_H - -#include -#include -#include -#include -#include -#include - -namespace lastfm -{ - /** @author Max Howell - * An implementation of the Audioscrobbler Realtime Submissions Protocol - * version 1.2.1 for a single Last.fm user - * http://www.audioscrobbler.net/development/protocol/ - */ - class LASTFM_DLLEXPORT Audioscrobbler : public QObject - { - Q_OBJECT - - public: - /** You will need to do QCoreApplication::setVersion and - * QCoreApplication::setApplicationName for this to work, also you will - * need to have set all the keys in the Ws namespace in WsKeys.h */ - Audioscrobbler( const QString& clientId ); - ~Audioscrobbler(); - - signals: - void scrobblesCached( const QList& tracks ); - /* Note that this is emitted after we tried to submit the scrobbles - It could just be that they have an error code */ - void scrobblesSubmitted( const QList& tracks ); - void nowPlayingError( int code, QString message ); - - public slots: - /** will ask Last.fm to update the now playing information for the - * authenticated user */ - void nowPlaying( const Track& ); - /** will cache the track and call submit() */ - void cache( const Track& ); - void cacheBatch( const QList& ); - - /** will submit the submission cache for this user */ - void submit(); - - private slots: - void onNowPlayingReturn(); - void onTrackScrobbleReturn(); - - private: - void parseTrack( const XmlQuery& trackXml, const Track& track ); - - private: - class AudioscrobblerPrivate* d; - }; -} - -#endif diff --git a/thirdparty/liblastfm2/src/scrobble/ScrobbleCache.cpp b/thirdparty/liblastfm2/src/scrobble/ScrobbleCache.cpp deleted file mode 100644 index 583d4b4d0..000000000 --- a/thirdparty/liblastfm2/src/scrobble/ScrobbleCache.cpp +++ /dev/null @@ -1,163 +0,0 @@ -/* - Copyright 2009 Last.fm Ltd. - - Primarily authored by Max Howell, Jono Cole and Doug Mansell - - This file is part of liblastfm. - - liblastfm is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - liblastfm is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with liblastfm. If not, see . -*/ -#include "ScrobbleCache.h" -#include "ScrobblePoint.h" -#include -#include -#include -#include -#include - -#if LASTFM_VERSION >= 0x00010000 -using lastfm::ScrobbleCache; -#endif - -ScrobbleCache::ScrobbleCache( const QString& username ) -{ - Q_ASSERT( username.length() ); - - m_path = lastfm::dir::runtimeData().filePath( username + "_subs_cache.xml" ); - m_username = username; - - QDomDocument xml; - read( xml ); -} - - -bool -ScrobbleCache::isValid( const Track& track, Invalidity* v ) -{ - #define TEST( test, x ) \ - if (test) { \ - if (v) *v = x; \ - return false; \ - } - - TEST( track.duration() < ScrobblePoint::kScrobbleMinLength, TooShort ); - - TEST( !track.timestamp().isValid(), NoTimestamp ); - - // actual spam prevention is something like 12 hours, but we are only - // trying to weed out obviously bad data, server side criteria for - // "the future" may change, so we should let the server decide, not us - TEST( track.timestamp() > QDateTime::currentDateTime().addMonths( 1 ), FromTheFuture ); - - TEST( track.timestamp() < QDateTime::fromString( "2003-01-01", Qt::ISODate ), FromTheDistantPast ); - - // Check if any required fields are empty - TEST( track.artist().isNull(), ArtistNameMissing ); - TEST( track.title().isEmpty(), TrackNameMissing ); - - TEST( (QStringList() << "unknown artist" - << "unknown" - << "[unknown]" - << "[unknown artist]").contains( track.artist().name().toLower() ), - ArtistInvalid ); - - return true; -} - - -void -ScrobbleCache::read( QDomDocument& xml ) -{ - m_tracks.clear(); - - QFile file( m_path ); - file.open( QFile::Text | QFile::ReadOnly ); - QTextStream stream( &file ); - stream.setCodec( "UTF-8" ); - - xml.setContent( stream.readAll() ); - - for (QDomNode n = xml.documentElement().firstChild(); !n.isNull(); n = n.nextSibling()) - if (n.nodeName() == "track") - m_tracks += Track( n.toElement() ); -} - - -void -ScrobbleCache::write() -{ - if (m_tracks.isEmpty()) - { - QFile::remove( m_path ); - } - else { - QDomDocument xml; - QDomElement e = xml.createElement( "submissions" ); - e.setAttribute( "product", QCoreApplication::applicationName() ); - e.setAttribute( "version", "2" ); - - foreach (Track i, m_tracks) - e.appendChild( i.toDomElement( xml ) ); - - xml.appendChild( e ); - - QFile file( m_path ); - file.open( QIODevice::WriteOnly | QIODevice::Text ); - - QTextStream stream( &file ); - stream.setCodec( "UTF-8" ); - stream << "\n"; - stream << xml.toString( 2 ); - file.close(); - } -} - - -void -ScrobbleCache::add( const QList& tracks ) -{ - foreach (const Track& track, tracks) - { - ScrobbleCache::Invalidity invalidity; - - if ( !isValid( track, &invalidity ) ) - { - qWarning() << invalidity; - } - else if (track.isNull()) - qDebug() << "Will not cache an empty track"; - else - m_tracks += track; - } - - write(); -} - - -int -ScrobbleCache::remove( const QList& toremove ) -{ - QMutableListIterator i( m_tracks ); - while (i.hasNext()) { - Track t = i.next(); - for (int x = 0; x < toremove.count(); ++x) - if (toremove[x] == t) - i.remove(); - } - - write(); - - // yes we return # remaining, rather # removed, but this is an internal - // function and the behaviour is documented so it's alright imo --mxcl - return m_tracks.count(); -} diff --git a/thirdparty/liblastfm2/src/scrobble/ScrobbleCache.h b/thirdparty/liblastfm2/src/scrobble/ScrobbleCache.h deleted file mode 100644 index 31219263b..000000000 --- a/thirdparty/liblastfm2/src/scrobble/ScrobbleCache.h +++ /dev/null @@ -1,84 +0,0 @@ -/* - Copyright 2009 Last.fm Ltd. - - Primarily authored by Max Howell, Jono Cole and Doug Mansell - - This file is part of liblastfm. - - liblastfm is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - liblastfm is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with liblastfm. If not, see . -*/ -#ifndef LASTFM_SCROBBLE_CACHE_H -#define LASTFM_SCROBBLE_CACHE_H - -#include "lastfm/Track" -#include -#include - -#if LASTFM_VERSION >= 0x00010000 -namespace lastfm { -#else -using lastfm::Track; -#endif - -/** absolutely not thread-safe */ -class LASTFM_DLLEXPORT ScrobbleCache -{ - QString m_username; - - void write(); /// writes m_tracks to m_path - -protected: - ScrobbleCache() - {} - - QString m_path; - QList m_tracks; - - void read( QDomDocument& xml ); /// reads from m_path into m_tracks - -public: - explicit ScrobbleCache( const QString& username ); - - /** note this is unique for Track::sameAs() and equal timestamps - * obviously playcounts will not be increased for the same timestamp */ - void add( const QList& ); - - /** returns the number of tracks left in the queue */ - int remove( const QList& ); - - QList tracks() const { return m_tracks; } - QString path() const { return m_path; } - QString username() const { return m_username; } - -private: - bool operator==( const ScrobbleCache& ); //undefined - - enum Invalidity - { - TooShort, - ArtistNameMissing, - TrackNameMissing, - ArtistInvalid, - NoTimestamp, - FromTheFuture, - FromTheDistantPast - }; - - bool isValid( const Track& track, Invalidity* = 0 ); -}; - -#if LASTFM_VERSION >= 0x00010000 -} -#endif - -#endif diff --git a/thirdparty/liblastfm2/src/scrobble/ScrobblePoint.h b/thirdparty/liblastfm2/src/scrobble/ScrobblePoint.h deleted file mode 100644 index fce857d46..000000000 --- a/thirdparty/liblastfm2/src/scrobble/ScrobblePoint.h +++ /dev/null @@ -1,59 +0,0 @@ -/* - Copyright 2009 Last.fm Ltd. - - Primarily authored by Max Howell, Jono Cole and Doug Mansell - - This file is part of liblastfm. - - liblastfm is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - liblastfm is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with liblastfm. If not, see . -*/ -#ifndef LASTFM_SCROBBLE_POINT_H -#define LASTFM_SCROBBLE_POINT_H - -#include -#include - - -class LASTFM_DLLEXPORT ScrobblePoint -{ - uint i; - -public: - ScrobblePoint() : i( kScrobbleTimeMax ) - {} - - /** j is in seconds, and should be 50% the duration of a track */ - explicit ScrobblePoint( uint j ) - { - // we special case 0, returning kScrobbleTimeMax because we are - // cruel and callous people - if (j == 0) --j; - - i = qBound( uint(kScrobbleMinLength), - j, - uint(kScrobbleTimeMax) ); - } - operator uint() const { return i; } - - // scrobbles can occur between these two percentages of track duration - static const uint kScrobblePointMin = 50; - static const uint kScrobblePointMax = 100; - static const uint kDefaultScrobblePoint = 50; - - // Shortest track length allowed to scrobble in seconds - static const uint kScrobbleMinLength = 31; - // Upper limit for scrobble time in seconds - static const uint kScrobbleTimeMax = 240; -}; - -#endif diff --git a/thirdparty/liblastfm2/src/types/AbstractType.h b/thirdparty/liblastfm2/src/types/AbstractType.h deleted file mode 100755 index 873b5dec9..000000000 --- a/thirdparty/liblastfm2/src/types/AbstractType.h +++ /dev/null @@ -1,43 +0,0 @@ -/* - Copyright 2010 Last.fm Ltd. - - Primarily authored by Micahel Coffey and Jono Cole - - This file is part of liblastfm. - - liblastfm is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - liblastfm is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with liblastfm. If not, see . -*/ - -#ifndef ABSTRACTTYPE_H -#define ABSTRACTTYPE_H - -#include -#include -#include - -#include - -namespace lastfm -{ - class LASTFM_DLLEXPORT AbstractType - { - public: - virtual QString toString() const = 0; - virtual QDomElement toDomElement( QDomDocument& ) const = 0; - virtual QUrl www() const = 0; - virtual QUrl imageUrl( ImageSize size, bool square ) const = 0; - virtual ~AbstractType() {;} - }; -}; - -#endif // ABSTRACTTYPE_H diff --git a/thirdparty/liblastfm2/src/types/Album.cpp b/thirdparty/liblastfm2/src/types/Album.cpp deleted file mode 100644 index 8a545897d..000000000 --- a/thirdparty/liblastfm2/src/types/Album.cpp +++ /dev/null @@ -1,87 +0,0 @@ -/* - Copyright 2009-2010 Last.fm Ltd. - - Primarily authored by Max Howell, Jono Cole and Doug Mansell - - This file is part of liblastfm. - - liblastfm is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - liblastfm is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with liblastfm. If not, see . -*/ -#include "Album.h" -#include "Artist.h" -#include "User.h" -#include "../core/UrlBuilder.h" -#include "../core/XmlQuery.h" -#include "../ws/ws.h" -#include -#include -#include - -QNetworkReply* -lastfm::Album::getInfo() const -{ - QMap map; - map["method"] = "album.getInfo"; - map["artist"] = m_artist; - map["album"] = m_title; - if (!lastfm::ws::Username.isEmpty()) map["username"] = lastfm::ws::Username; - if (!lastfm::ws::SessionKey.isEmpty()) map["sk"] = lastfm::ws::SessionKey; - return lastfm::ws::get(map); -} - - -QNetworkReply* -lastfm::Album::getTags() const -{ - QMap map; - map["method"] = "album.getTags"; - map["artist"] = m_artist; - map["album"] = m_title; - return lastfm::ws::get(map); -} - - -QNetworkReply* -lastfm::Album::share( const QStringList& recipients, const QString& message, bool isPublic ) const -{ - QMap map; - map["method"] = "album.share"; - map["artist"] = m_artist; - map["album"] = m_title; - map["recipient"] = recipients.join(","); - map["public"] = isPublic ? "1" : "0"; - if (message.size()) map["message"] = message; - return lastfm::ws::post(map); -} - - -QUrl -lastfm::Album::www() const -{ - return lastfm::UrlBuilder( "music" ).slash( m_artist ).slash( m_title ).url(); -} - - -QNetworkReply* -lastfm::Album::addTags( const QStringList& tags ) const -{ - if (tags.isEmpty()) - return 0; - - QMap map; - map["method"] = "album.addTags"; - map["artist"] = m_artist; - map["album"] = m_title; - map["tags"] = tags.join( QChar(',') ); - return lastfm::ws::post(map); -} diff --git a/thirdparty/liblastfm2/src/types/Album.h b/thirdparty/liblastfm2/src/types/Album.h deleted file mode 100644 index f64b59986..000000000 --- a/thirdparty/liblastfm2/src/types/Album.h +++ /dev/null @@ -1,73 +0,0 @@ -/* - Copyright 2009 Last.fm Ltd. - - Primarily authored by Max Howell, Jono Cole and Doug Mansell - - This file is part of liblastfm. - - liblastfm is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - liblastfm is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with liblastfm. If not, see . -*/ -#ifndef LASTFM_ALBUM_H -#define LASTFM_ALBUM_H - -#include -#include -#include -#include - -namespace lastfm -{ - class LASTFM_DLLEXPORT Album - { - Mbid m_mbid; - Artist m_artist; - QString m_title; - - public: - Album() - {} - - explicit Album( Mbid mbid ) : m_mbid( mbid ) - {} - - Album( Artist artist, QString title ) : m_artist( artist ), m_title( title ) - {} - - bool operator==( const Album& that ) const { return m_title == that.m_title && m_artist == that.m_artist; } - bool operator!=( const Album& that ) const { return m_title != that.m_title || m_artist != that.m_artist; } - - operator QString() const { return title(); } - QString title() const { return m_title.isEmpty() ? "[unknown]" : m_title; } - Artist artist() const { return m_artist; } - Mbid mbid() const { return m_mbid; } - - /** artist may have been set, since we allow that in the ctor, but should we handle untitled albums? */ - bool isNull() const { return m_title.isEmpty() && m_mbid.isNull(); } - - /** Album.getInfo WebService */ - QNetworkReply* getInfo() const; - QNetworkReply* share( const QStringList& recipients, const QString& message = "", bool isPublic = true ) const; - - /** use Tag::list to get the tag list out of the finished reply */ - QNetworkReply* getTags() const; - QNetworkReply* getTopTags() const; - - /** Last.fm dictates that you may submit at most 10 of these */ - QNetworkReply* addTags( const QStringList& ) const; - - /** the Last.fm website url for this album */ - QUrl www() const; - }; -} - -#endif //LASTFM_ALBUM_H diff --git a/thirdparty/liblastfm2/src/types/Artist.cpp b/thirdparty/liblastfm2/src/types/Artist.cpp deleted file mode 100644 index 1d9e14258..000000000 --- a/thirdparty/liblastfm2/src/types/Artist.cpp +++ /dev/null @@ -1,230 +0,0 @@ -/* - Copyright 2009 Last.fm Ltd. - - Primarily authored by Max Howell, Jono Cole and Doug Mansell - - This file is part of liblastfm. - - liblastfm is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - liblastfm is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with liblastfm. If not, see . -*/ -#include "Artist.h" -#include "User.h" -#include "../core/UrlBuilder.h" -#include "../core/XmlQuery.h" -#include "../ws/ws.h" -#include -#include - -using lastfm::Artist; -using lastfm::User; -using lastfm::ImageSize; -using lastfm::XmlQuery; - -QUrl -Artist::imageUrl( ImageSize size, bool square ) const -{ - if( !square ) return m_images.value( size ); - - QUrl url = m_images.value( size ); - QRegExp re( "/serve/(\\d*)s?/" ); - return QUrl( url.toString().replace( re, "/serve/\\1s/" )); -} - -static inline QList images( const lastfm::XmlQuery& e ) -{ - QList images; - images += e["image size=small"].text(); - images += e["image size=medium"].text(); - images += e["image size=large"].text(); - return images; -} - - -Artist::Artist( const XmlQuery& xml ) - :AbstractType() -{ - m_name = xml["name"].text(); - m_images = images( xml ); -} - - -QMap //private -Artist::params( const QString& method ) const -{ - QMap map; - map["method"] = "artist."+method; - map["artist"] = m_name; - return map; -} - - -QNetworkReply* -Artist::share( const QStringList& recipients, const QString& message, bool isPublic ) const -{ - QMap map = params("share"); - map["recipient"] = recipients.join(","); - map["public"] = isPublic ? "1" : "0"; - if (message.size()) map["message"] = message; - return lastfm::ws::post(map); -} - - -QUrl -Artist::www() const -{ - return UrlBuilder( "music" ).slash( Artist::name() ).url(); -} - -QNetworkReply* -Artist::getEvents(int limit) const -{ - QMap map = params("getEvents"); - if (limit) map["limit"] = QString::number(limit); - return ws::get( map ); -} - -QNetworkReply* -Artist::getInfo() const -{ - QMap map = params("getInfo"); - if (!lastfm::ws::Username.isEmpty()) map["username"] = lastfm::ws::Username; - if (!lastfm::ws::SessionKey.isEmpty()) map["sk"] = lastfm::ws::SessionKey; - return ws::get( map ); -} - - -QNetworkReply* -Artist::getTags() const -{ - return ws::get( params("getTags") ); -} - -QNetworkReply* -Artist::getTopTags() const -{ - return ws::get( params("getTopTags") ); -} - - -QNetworkReply* -Artist::getTopTracks() const -{ - return ws::get( params("getTopTracks") ); -} - - -QNetworkReply* -Artist::getSimilar( int limit ) const -{ - QMap map = params("getSimilar"); - if ( limit != -1 ) map["limit"] = QString::number( limit ); - return ws::get( map ); -} - - -QNetworkReply* -Artist::search( int limit ) const -{ - QMap map = params("search"); - if (limit > 0) map["limit"] = QString::number(limit); - return ws::get(map); -} - - -QMap /* static */ -Artist::getSimilar( QNetworkReply* r ) -{ - QMap artists; - try - { - XmlQuery lfm = r->readAll(); - foreach (XmlQuery e, lfm.children( "artist" )) - { - // convert floating percentage to int in range 0 to 10,000 - int const match = e["match"].text().toFloat() * 100; - artists.insertMulti( match, e["name"].text() ); - } - } - catch (ws::ParseError& e) - { - qWarning() << e.what(); - } - return artists; -} - - -QStringList /* static */ -Artist::getTopTracks( QNetworkReply* r ) -{ - QStringList tracks; - try - { - XmlQuery lfm = r->readAll(); - foreach (XmlQuery e, lfm.children( "track" )) - { - tracks << e["name"].text(); - } - } - catch (ws::ParseError& e) - { - qWarning() << e.what(); - } - return tracks; -} - - -QList /* static */ -Artist::list( QNetworkReply* r ) -{ - QList artists; - try { - XmlQuery lfm = r->readAll(); - foreach (XmlQuery xq, lfm.children( "artist" )) { - Artist artist( xq ); - artists += artist; - } - } - catch (ws::ParseError& e) - { - qWarning() << e.what(); - } - return artists; -} - - -Artist -Artist::getInfo( QNetworkReply* r ) -{ - try { - XmlQuery lfm = r->readAll(); - Artist artist = lfm["artist"]["name"].text(); - artist.m_images = images( lfm["artist"] ); - return artist; - } - catch (ws::ParseError& e) - { - qWarning() << e.what(); - return Artist(); - } -} - - -QNetworkReply* -Artist::addTags( const QStringList& tags ) const -{ - if (tags.isEmpty()) - return 0; - QMap map = params("addTags"); - map["tags"] = tags.join( QChar(',') ); - return ws::post(map); -} diff --git a/thirdparty/liblastfm2/src/types/Artist.h b/thirdparty/liblastfm2/src/types/Artist.h deleted file mode 100644 index f84fcce39..000000000 --- a/thirdparty/liblastfm2/src/types/Artist.h +++ /dev/null @@ -1,105 +0,0 @@ -/* - Copyright 2009-2010 Last.fm Ltd. - - Primarily authored by Max Howell, Jono Cole, Doug Mansell and Michael Coffey - - This file is part of liblastfm. - - liblastfm is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - liblastfm is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with liblastfm. If not, see . -*/ -#ifndef LASTFM_ARTIST_H -#define LASTFM_ARTIST_H - -#include -#include -#include - -#include -#include - - -namespace lastfm -{ - class LASTFM_DLLEXPORT Artist : public AbstractType - { - private: - QString m_name; - QList m_images; - - public: - Artist() : AbstractType() - {} - - Artist( const QString& name ) : AbstractType(), m_name( name ) - {} - - Artist( const class XmlQuery& xml ); - - /** will be QUrl() unless you got this back from a getInfo or something call */ - QUrl imageUrl( ImageSize size = Large, bool square = false ) const; - - bool isNull() const { return m_name.isEmpty(); } - - /** the url for this artist's page at www.last.fm */ - QUrl www() const; - - Artist& operator=( const Artist& that ) { m_name = that.name(); m_images = that.m_images; return *this; } - bool operator==( const Artist& that ) const { return m_name == that.m_name; } - bool operator!=( const Artist& that ) const { return m_name != that.m_name; } - bool operator<( const Artist& that ) const { return m_name < that.m_name; } - - operator QString() const - { - /** if no artist name is set, return the musicbrainz unknown identifier - * in case some part of the GUI tries to display it anyway. Note isNull - * returns false still. So you should have queried that! */ - return m_name.isEmpty() ? "[unknown]" : m_name; - } - - QString toString() const { return name(); } - QString name() const { return QString(*this); } - - QDomElement toDomElement( QDomDocument& ) const { return QDomElement(); } - - QNetworkReply* share( const QStringList& recipients, const QString& message = "", bool isPublic = true ) const; - - QNetworkReply* getEvents(int limit = 0) const; - QNetworkReply* getInfo() const; - static Artist getInfo( QNetworkReply* ); - - QNetworkReply* getSimilar( int limit = -1 ) const; - /** The match percentage is returned from last.fm as a 4 significant - * figure floating point value. So we multply it by 100 to make an - * integer in the range of 0 to 10,000. This is possible confusing - * for you, but I felt it best not to lose any precision, and floats - * aren't much fun. */ - static QMap getSimilar( QNetworkReply* ); - - /** use Tag::list to get the tag list out of the finished reply */ - QNetworkReply* getTags() const; - QNetworkReply* getTopTags() const; - - QNetworkReply* getTopTracks() const; - static QStringList getTopTracks( QNetworkReply* ); - - /** Last.fm dictates that you may submit at most 10 of these */ - QNetworkReply* addTags( const QStringList& ) const; - - QNetworkReply* search( int limit = -1 ) const; - static QList list( QNetworkReply* ); - - QMap params( const QString& method ) const; - }; -} - -#endif diff --git a/thirdparty/liblastfm2/src/types/FingerprintId.cpp b/thirdparty/liblastfm2/src/types/FingerprintId.cpp deleted file mode 100644 index b201534a0..000000000 --- a/thirdparty/liblastfm2/src/types/FingerprintId.cpp +++ /dev/null @@ -1,55 +0,0 @@ -/* - Copyright 2009 Last.fm Ltd. - - Primarily authored by Max Howell, Jono Cole and Doug Mansell - - This file is part of liblastfm. - - liblastfm is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - liblastfm is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with liblastfm. If not, see . -*/ -#include "FingerprintId.h" -#include "../ws/ws.h" -#include -#include - - -QNetworkReply* -lastfm::FingerprintId::getSuggestions() const -{ - if (isNull()) return 0; - - QUrl const url( "http://ws.audioscrobbler.com/fingerprint/" + QString(*this) + ".xml" ); - QNetworkRequest const request( url ); - return lastfm::nam()->get( request ); -} - - -QMap //static -lastfm::FingerprintId::getSuggestions( QNetworkReply* reply ) -{ - QDomDocument xml; - xml.setContent( reply->readAll() ); - QDomNodeList nodes = xml.documentElement().elementsByTagName( "track" ); - - QMap tracks; - for (int x = 0; x < nodes.count(); ++x) - { - QDomElement const e = nodes.at(x).toElement(); - - MutableTrack t; - t.setTitle( e.firstChildElement( "title" ).text() ); - t.setArtist( e.firstChildElement( "artist" ).text() ); - tracks.insert( e.attribute( "confidence", "0.0" ).toFloat(), t ); - } - return tracks; -} diff --git a/thirdparty/liblastfm2/src/types/FingerprintId.h b/thirdparty/liblastfm2/src/types/FingerprintId.h deleted file mode 100644 index 5028c7736..000000000 --- a/thirdparty/liblastfm2/src/types/FingerprintId.h +++ /dev/null @@ -1,62 +0,0 @@ -/* - Copyright 2009 Last.fm Ltd. - - Primarily authored by Max Howell, Jono Cole and Doug Mansell - - This file is part of liblastfm. - - liblastfm is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - liblastfm is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with liblastfm. If not, see . -*/ -#ifndef LASTFM_FINGERPRINT_ID_H -#define LASTFM_FINGERPRINT_ID_H - -#include -#include - -namespace lastfm -{ - class LASTFM_DLLEXPORT FingerprintId - { - int id; - - public: - FingerprintId() : id( -1 ) - {} - - FingerprintId( uint i ) : id( i ) - {} - - bool isNull() const { return id == -1; } - - /** we query Last.fm for suggested metadata, how awesome is that? - * @returns null if isNull() */ - QNetworkReply* getSuggestions() const; - static QMap getSuggestions( QNetworkReply* ); - - /** -1 if you need to generate it */ - operator int() const { return id; } - /** isEmpty() if you need to generate it */ - operator QString() const { return id == -1 ? "" : QString::number( id ); } - }; -} - - -inline QDebug operator<<( QDebug d, lastfm::FingerprintId id) -{ - if (id.isNull()) - return d << "(null)"; - else - return d << int(id); -} - -#endif diff --git a/thirdparty/liblastfm2/src/types/Mbid.cpp b/thirdparty/liblastfm2/src/types/Mbid.cpp deleted file mode 100644 index 1ce1d90c5..000000000 --- a/thirdparty/liblastfm2/src/types/Mbid.cpp +++ /dev/null @@ -1,36 +0,0 @@ -/* - Copyright 2009 Last.fm Ltd. - - Primarily authored by Max Howell, Jono Cole and Doug Mansell - - This file is part of liblastfm. - - liblastfm is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - liblastfm is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with liblastfm. If not, see . -*/ -#include "Mbid.h" -#include "mbid_mp3.c" -#include - -namespace lastfm -{ - Mbid //static - Mbid::fromLocalFile( const QString& path ) - { - char out[MBID_BUFFER_SIZE]; - QByteArray const bytes = QFile::encodeName( path ); - int const r = getMP3_MBID( bytes.data(), out ); - Mbid mbid; - if (r == 0) mbid.id = QString::fromLatin1( out ); - return mbid; - } -} diff --git a/thirdparty/liblastfm2/src/types/Mbid.h b/thirdparty/liblastfm2/src/types/Mbid.h deleted file mode 100644 index 071d4d1fc..000000000 --- a/thirdparty/liblastfm2/src/types/Mbid.h +++ /dev/null @@ -1,45 +0,0 @@ -/* - Copyright 2009 Last.fm Ltd. - - Primarily authored by Max Howell, Jono Cole and Doug Mansell - - This file is part of liblastfm. - - liblastfm is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - liblastfm is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with liblastfm. If not, see . -*/ -#ifndef LASTFM_MBID_H -#define LASTFM_MBID_H - -#include -#include - -namespace lastfm -{ - class LASTFM_DLLEXPORT Mbid - { - QString id; - - public: - explicit Mbid( const QString& p = "" ) : id( p ) - {} - - bool isNull() const { return id.isNull() || id.isEmpty(); } - operator QString() const { return id; } - - /** if this is not an mp3 file you will be wasting time, as it won't work - * but we will do what you say anyway because you are the boss */ - static Mbid fromLocalFile( const QString& path ); - }; -} - -#endif diff --git a/thirdparty/liblastfm2/src/types/Playlist.cpp b/thirdparty/liblastfm2/src/types/Playlist.cpp deleted file mode 100644 index 807da1c6a..000000000 --- a/thirdparty/liblastfm2/src/types/Playlist.cpp +++ /dev/null @@ -1,63 +0,0 @@ -/* - Copyright 2009 Last.fm Ltd. - - Primarily authored by Max Howell, Jono Cole and Doug Mansell - - This file is part of liblastfm. - - liblastfm is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - liblastfm is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with liblastfm. If not, see . -*/ -#include "Playlist.h" -#include "Track.h" -#include "../ws/ws.h" - - -QNetworkReply* -lastfm::Playlist::addTrack( const Track& t ) const -{ - QMap map; - map["method"] = "playlist.addTrack"; - map["playlistID"] = m_id; - map["artist"] = t.artist(); - map["track"] = t.title(); - return lastfm::ws::post(map); -} - - -QNetworkReply* -lastfm::Playlist::fetch() const -{ - return fetch( QUrl("lastfm://playlist/" + QString::number( m_id )) ); -} - - -QNetworkReply* //static -lastfm::Playlist::fetch( const QUrl& url ) -{ - QMap map; - map["method"] = "playlist.fetch"; - map["playlistURL"] = url.toString(); - return lastfm::ws::get(map); -} - - -QNetworkReply* //static -lastfm::Playlist::create( const QString& title, const QString& description /*=""*/ ) -{ - QMap map; - map["method"] = "playlist.create"; - map["title"] = title; - if (description.size()) - map["description"] = description; - return lastfm::ws::post(map); -} diff --git a/thirdparty/liblastfm2/src/types/Playlist.h b/thirdparty/liblastfm2/src/types/Playlist.h deleted file mode 100644 index 89ee42ce6..000000000 --- a/thirdparty/liblastfm2/src/types/Playlist.h +++ /dev/null @@ -1,51 +0,0 @@ -/* - Copyright 2009 Last.fm Ltd. - - Primarily authored by Max Howell, Jono Cole and Doug Mansell - - This file is part of liblastfm. - - liblastfm is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - liblastfm is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with liblastfm. If not, see . -*/ -#ifndef LASTFM_PLAYLIST_H -#define LASTFM_PLAYLIST_H - -#include -#include -#include -#include - -namespace lastfm -{ - class LASTFM_DLLEXPORT Playlist - { - int m_id; - - Playlist() : m_id( -1 ) - {} - - public: - Playlist( int id ) : m_id( id ) - {} - - int id() const { return m_id; } - - QNetworkReply* addTrack( const Track& ) const; - QNetworkReply* fetch() const; - - static QNetworkReply* create( const QString& title, const QString& description = "" ); - static QNetworkReply* fetch( const QUrl& url ); - }; -} - -#endif diff --git a/thirdparty/liblastfm2/src/types/Tag.cpp b/thirdparty/liblastfm2/src/types/Tag.cpp deleted file mode 100644 index 675a147c7..000000000 --- a/thirdparty/liblastfm2/src/types/Tag.cpp +++ /dev/null @@ -1,77 +0,0 @@ -/* - Copyright 2009 Last.fm Ltd. - - Primarily authored by Max Howell, Jono Cole and Doug Mansell - - This file is part of liblastfm. - - liblastfm is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - liblastfm is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with liblastfm. If not, see . -*/ -#include "Tag.h" -#include "User.h" -#include "../core/UrlBuilder.h" -#include "../core/XmlQuery.h" -#include "../ws/ws.h" -using lastfm::Tag; -using lastfm::User; - - -QUrl -Tag::www() const -{ - return UrlBuilder( "tag" ).slash( m_name ).url(); -} - - -QUrl -Tag::www( const User& user ) const -{ - return UrlBuilder( "user" ).slash( user.name() ).slash( "tags" ).slash( Tag::name() ).url(); -} - - -QNetworkReply* -Tag::search() const -{ - QMap map; - map["method"] = "tag.search"; - map["tag"] = m_name; - return ws::get(map); -} - -//static -QNetworkReply* -Tag::getTopTags() -{ - QMap map; - map["method"] = "tag.getTopTags"; - return ws::get(map); -} - -QMap //static -Tag::list( QNetworkReply* r ) -{ - QMap tags; - try { - foreach (XmlQuery xq, XmlQuery( r->readAll() ).children("tag")) - // we toLower always as otherwise it is ugly mixed case, as first - // ever tag decides case, and Last.fm is case insensitive about it - // anyway - tags.insertMulti( xq["count"].text().toInt(), xq["name"].text().toLower() ); - } - catch (ws::ParseError& e) - { - qWarning() << e.what(); - } - return tags; -} diff --git a/thirdparty/liblastfm2/src/types/Tag.h b/thirdparty/liblastfm2/src/types/Tag.h deleted file mode 100644 index 917faf1df..000000000 --- a/thirdparty/liblastfm2/src/types/Tag.h +++ /dev/null @@ -1,63 +0,0 @@ -/* - Copyright 2009 Last.fm Ltd. - - Primarily authored by Max Howell, Jono Cole and Doug Mansell - - This file is part of liblastfm. - - liblastfm is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - liblastfm is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with liblastfm. If not, see . -*/ -#ifndef LASTFM_TAG_H -#define LASTFM_TAG_H - -#include -#include -#include -#include - -namespace lastfm -{ - class LASTFM_DLLEXPORT Tag - { - QString m_name; - - public: - Tag( const QString& name ) : m_name( name ) - {} - - operator QString() const { return m_name; } - QString name() const { return m_name; } - - lastfm::Tag operator=( const Tag& that ) const { return Tag( that.name() ); } - bool operator<( const Tag& that ) const { return this->m_name < that.m_name; } - - /** the global tag page at www.last.fm */ - QUrl www() const; - /** the tag page for user @p user at www.last.fm */ - QUrl www( const class User& user ) const; - /** pass the finished QNetworkReply to Tag::list() */ - class QNetworkReply* search() const; - - /** the top global tags on Last.fm, sorted by popularity (number of times used) */ - static class QNetworkReply* getTopTags(); - - /** the integer is the weighting, not all list type return requests - * have a weighting, so the int may just be zero, if you don't care - * about the weight just do this: - * QStringList tags = Tag::list( reply ).values(); - */ - static QMap list( QNetworkReply* ); - }; -} - -#endif diff --git a/thirdparty/liblastfm2/src/types/Tasteometer.cpp b/thirdparty/liblastfm2/src/types/Tasteometer.cpp deleted file mode 100644 index 5ec0e58a2..000000000 --- a/thirdparty/liblastfm2/src/types/Tasteometer.cpp +++ /dev/null @@ -1,20 +0,0 @@ -#include "Tasteometer.h" - -#include "lastfm.h" - -lastfm::Tasteometer::Tasteometer() -{ -} - - -QNetworkReply* -lastfm::Tasteometer::compare( const User& left, const User& right ) -{ - QMap map; - map["method"] = "Tasteometer.compare"; - map["type1"] = "user"; - map["value1"] = left.name(); - map["type2"] = "user"; - map["value2"] = right.name(); - return lastfm::ws::get( map ); -} diff --git a/thirdparty/liblastfm2/src/types/Tasteometer.h b/thirdparty/liblastfm2/src/types/Tasteometer.h deleted file mode 100644 index ef691b8f6..000000000 --- a/thirdparty/liblastfm2/src/types/Tasteometer.h +++ /dev/null @@ -1,18 +0,0 @@ -#ifndef TASTEOMETER_H -#define TASTEOMETER_H - -#include - -namespace lastfm -{ - class LASTFM_DLLEXPORT Tasteometer - { - public: - Tasteometer(); - - public: - static QNetworkReply* compare( const User& left, const User& right ); - }; -} - -#endif // TASTEOMETER_H diff --git a/thirdparty/liblastfm2/src/types/Track.cpp b/thirdparty/liblastfm2/src/types/Track.cpp deleted file mode 100644 index 10cc41230..000000000 --- a/thirdparty/liblastfm2/src/types/Track.cpp +++ /dev/null @@ -1,653 +0,0 @@ -/* - Copyright 2009 Last.fm Ltd. - - Primarily authored by Max Howell, Jono Cole and Doug Mansell - - This file is part of liblastfm. - - liblastfm is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - liblastfm is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with liblastfm. If not, see . -*/ - -#include -#include -#include - -#include "Track.h" -#include "User.h" -#include "../core/UrlBuilder.h" -#include "../core/XmlQuery.h" -#include "../ws/ws.h" - - -lastfm::TrackContext::TrackContext() - :m_type( Unknown ) -{ - -} - -lastfm::TrackContext::TrackContext( const QString& type, const QList& values ) - :m_type( getType( type ) ), m_values( values ) -{ -} - -lastfm::TrackContext::Type -lastfm::TrackContext::getType( const QString& typeString ) -{ - Type type = Unknown; - - if ( typeString == "artist" ) - type = Artist; - else if ( typeString == "user" ) - type = User; - else if ( typeString == "neighbour" ) - type = Neighbour; - else if ( typeString == "friend" ) - type = Friend; - - return type; -} - -lastfm::TrackContext::Type -lastfm::TrackContext::type() const -{ - return m_type; -} - - -QList -lastfm::TrackContext::values() const -{ - return m_values; -} - - -lastfm::TrackData::TrackData() - : trackNumber( 0 ), - duration( 0 ), - source( Track::Unknown ), - rating( 0 ), - fpid( -1 ), - loved( false ), - scrobbleStatus( Track::Null ), - scrobbleError( Track::None ), - null( false ) -{} - -lastfm::Track::Track() - :AbstractType() -{ - d = new TrackData; - d->null = true; -} - -lastfm::Track::Track( const QDomElement& e ) - :AbstractType() -{ - d = new TrackData; - - if (e.isNull()) { d->null = true; return; } - - // XML response may have changed - QDomNode artistName = e.namedItem( "artist" ).namedItem( "name" ); - if( artistName.isNull() ) { - d->artist = e.namedItem( "artist" ).toElement().text(); - } else { - d->artist = artistName.toElement().text(); - - } - // XML response may have changed - QDomNode trackTitle = e.namedItem( "name" ); - if( trackTitle.isNull() ) - d->title = e.namedItem( "track" ).toElement().text(); - else - d->title = trackTitle.toElement().text(); - - - d->albumArtist = e.namedItem( "albumArtist" ).toElement().text(); - d->album = e.namedItem( "album" ).toElement().text(); - d->correctedArtist = e.namedItem( "correctedArtist" ).toElement().text(); - d->correctedAlbumArtist = e.namedItem( "correctedAlbumArtist" ).toElement().text(); - d->correctedAlbum = e.namedItem( "correctedAlbum" ).toElement().text(); - d->correctedTitle = e.namedItem( "correctedTrack" ).toElement().text(); - d->trackNumber = 0; - d->duration = e.namedItem( "duration" ).toElement().text().toInt(); - d->url = e.namedItem( "url" ).toElement().text(); - d->rating = e.namedItem( "rating" ).toElement().text().toUInt(); - d->source = e.namedItem( "source" ).toElement().text().toInt(); //defaults to 0, or lastfm::Track::Unknown - d->time = QDateTime::fromTime_t( e.namedItem( "timestamp" ).toElement().text().toUInt() ); - d->loved = e.namedItem( "loved" ).toElement().text().toInt(); - d->scrobbleStatus = e.namedItem( "scrobbleStatus" ).toElement().text().toInt(); - d->scrobbleError = e.namedItem( "scrobbleError" ).toElement().text().toInt(); - - for (QDomElement image(e.firstChildElement("image")) ; !image.isNull() ; image = e.nextSiblingElement("image")) - { - d->m_images[static_cast(image.attribute("size").toInt())] = image.text(); - } - - QDomNodeList nodes = e.namedItem( "extras" ).childNodes(); - for (int i = 0; i < nodes.count(); ++i) - { - QDomNode n = nodes.at(i); - QString key = n.nodeName(); - d->extras[key] = n.toElement().text(); - } -} - -void -lastfm::TrackData::onLoveFinished() -{ - try - { - XmlQuery lfm = static_cast(sender())->readAll(); - if ( lfm.attribute( "status" ) == "ok") - loved = true; - - } - catch (...) - { - } - emit loveToggled( loved ); -} - - -void -lastfm::TrackData::onUnloveFinished() -{ - try - { - XmlQuery lfm = static_cast(sender())->readAll(); - if ( lfm.attribute( "status" ) == "ok") - loved = false; - } - catch (...) - { - } - - emit loveToggled( loved ); -} - -void -lastfm::TrackData::onGotInfo() -{ - const QByteArray data = static_cast(sender())->readAll(); - - try - { - lastfm::XmlQuery lfm( data ); - - QString imageUrl = lfm["track"]["image size=small"].text(); - if ( !imageUrl.isEmpty() ) m_images[lastfm::Small] = imageUrl; - imageUrl = lfm["track"]["image size=medium"].text(); - if ( !imageUrl.isEmpty() ) m_images[lastfm::Medium] = imageUrl; - imageUrl = lfm["track"]["image size=large"].text(); - if ( !imageUrl.isEmpty() ) m_images[lastfm::Large] = imageUrl; - imageUrl = lfm["track"]["image size=extralarge"].text(); - if ( !imageUrl.isEmpty() ) m_images[lastfm::ExtraLarge] = imageUrl; - imageUrl = lfm["track"]["image size=mega"].text(); - if ( !imageUrl.isEmpty() ) m_images[lastfm::Mega] = imageUrl; - - loved = lfm["track"]["userloved"].text().toInt(); - - emit gotInfo( data ); - emit loveToggled( loved ); - } - catch (...) - { - emit gotInfo( data ); - } - - // you should connect everytime you call getInfo - disconnect( this, SIGNAL(gotInfo(const QByteArray&)), 0, 0); -} - - -QDomElement -lastfm::Track::toDomElement( QDomDocument& xml ) const -{ - QDomElement item = xml.createElement( "track" ); - - #define makeElement( tagname, getter ) { \ - QString v = getter; \ - if (!v.isEmpty()) \ - { \ - QDomElement e = xml.createElement( tagname ); \ - e.appendChild( xml.createTextNode( v ) ); \ - item.appendChild( e ); \ - } \ - } - - makeElement( "artist", d->artist ); - makeElement( "albumArtist", d->albumArtist ); - makeElement( "album", d->album ); - makeElement( "track", d->title ); - makeElement( "correctedArtist", d->correctedArtist ); - makeElement( "correctedAlbumArtist", d->correctedAlbumArtist ); - makeElement( "correctedAlbum", d->correctedAlbum ); - makeElement( "correctedTrack", d->correctedTitle ); - makeElement( "duration", QString::number( d->duration ) ); - makeElement( "timestamp", QString::number( d->time.toTime_t() ) ); - makeElement( "url", d->url.toString() ); - makeElement( "source", QString::number( d->source ) ); - makeElement( "rating", QString::number(d->rating) ); - makeElement( "fpId", QString::number(d->fpid) ); - makeElement( "mbId", mbid() ); - makeElement( "loved", QString::number( isLoved() ) ); - makeElement( "scrobbleStatus", QString::number( scrobbleStatus() ) ); - makeElement( "scrobbleError", QString::number( scrobbleError() ) ); - - // put the images urls in the dom - QMapIterator imageIter( d->m_images ); - while (imageIter.hasNext()) { - QDomElement e = xml.createElement( "image" ); - e.appendChild( xml.createTextNode( imageIter.next().value().toString() ) ); - e.setAttribute( "size", imageIter.key() ); - item.appendChild( e ); - } - - // add the extras to the dom - QDomElement extras = xml.createElement( "extras" ); - QMapIterator extrasIter( d->extras ); - while (extrasIter.hasNext()) { - QDomElement e = xml.createElement( extrasIter.next().key() ); - e.appendChild( xml.createTextNode( extrasIter.value() ) ); - extras.appendChild( e ); - } - item.appendChild( extras ); - - return item; -} - - -bool -lastfm::Track::corrected() const -{ - // If any of the corrected string have been set and they are different - // from the initial strings then this track has been corrected. - return ( (!d->correctedTitle.isEmpty() && (d->correctedTitle != d->title)) - || (!d->correctedAlbum.isEmpty() && (d->correctedAlbum != d->album)) - || (!d->correctedArtist.isEmpty() && (d->correctedArtist != d->artist)) - || (!d->correctedAlbumArtist.isEmpty() && (d->correctedAlbumArtist != d->albumArtist))); -} - -lastfm::Artist -lastfm::Track::artist( Corrections corrected ) const -{ - if ( corrected == Corrected && !d->correctedArtist.isEmpty() ) - return Artist( d->correctedArtist ); - - return Artist( d->artist ); -} - -lastfm::Artist -lastfm::Track::albumArtist( Corrections corrected ) const -{ - if ( corrected == Corrected && !d->correctedAlbumArtist.isEmpty() ) - return Artist( d->correctedAlbumArtist ); - - return Artist( d->albumArtist ); -} - -lastfm::Album -lastfm::Track::album( Corrections corrected ) const -{ - if ( corrected == Corrected && !d->correctedAlbum.isEmpty() ) - return Album( artist( corrected ), d->correctedAlbum ); - - return Album( artist( corrected ), d->album ); -} - -QString -lastfm::Track::title( Corrections corrected ) const -{ - /** if no title is set, return the musicbrainz unknown identifier - * in case some part of the GUI tries to display it anyway. Note isNull - * returns false still. So you should have queried this! */ - - if ( corrected == Corrected && !d->correctedTitle.isEmpty() ) - return d->correctedTitle; - - return d->title.isEmpty() ? "[unknown]" : d->title; -} - - -QUrl -lastfm::Track::imageUrl( lastfm::ImageSize size, bool square ) const -{ - if( !square ) return d->m_images.value( size ); - - QUrl url = d->m_images.value( size ); - QRegExp re( "/serve/(\\d*)s?/" ); - return QUrl( url.toString().replace( re, "/serve/\\1s/" )); -} - - -QString -lastfm::Track::toString( const QChar& separator, Corrections corrections ) const -{ - if ( d->artist.isEmpty() ) - { - if ( d->title.isEmpty() ) - return QFileInfo( d->url.path() ).fileName(); - else - return title( corrections ); - } - - if ( d->title.isEmpty() ) - return artist( corrections ); - - return artist( corrections ) + ' ' + separator + ' ' + title( corrections ); -} - - -QString //static -lastfm::Track::durationString( int const duration ) -{ - QTime t = QTime().addSecs( duration ); - if (duration < 60*60) - return t.toString( "m:ss" ); - else - return t.toString( "hh:mm:ss" ); -} - - -QNetworkReply* -lastfm::Track::share( const QStringList& recipients, const QString& message, bool isPublic ) const -{ - QMap map = params("share"); - map["recipient"] = recipients.join(","); - map["public"] = isPublic ? "1" : "0"; - if (message.size()) map["message"] = message; - return ws::post(map); -} - - -void -lastfm::Track::invalidateGetInfo() -{ - // invalidate the track.getInfo cache - QAbstractNetworkCache* cache = lastfm::nam()->cache(); - if ( cache ) - { - QMap map = params("getInfo", true); - if (!lastfm::ws::Username.isEmpty()) map["username"] = lastfm::ws::Username; - if (!lastfm::ws::SessionKey.isEmpty()) map["sk"] = lastfm::ws::SessionKey; - cache->remove( lastfm::ws::url( map ) ); - } -} - - -void -lastfm::MutableTrack::setFromLfm( const XmlQuery& lfm ) -{ - QString imageUrl = lfm["track"]["image size=small"].text(); - if ( !imageUrl.isEmpty() ) d->m_images[lastfm::Small] = imageUrl; - imageUrl = lfm["track"]["image size=medium"].text(); - if ( !imageUrl.isEmpty() ) d->m_images[lastfm::Medium] = imageUrl; - imageUrl = lfm["track"]["image size=large"].text(); - if ( !imageUrl.isEmpty() ) d->m_images[lastfm::Large] = imageUrl; - imageUrl = lfm["track"]["image size=extralarge"].text(); - if ( !imageUrl.isEmpty() ) d->m_images[lastfm::ExtraLarge] = imageUrl; - imageUrl = lfm["track"]["image size=mega"].text(); - if ( !imageUrl.isEmpty() ) d->m_images[lastfm::Mega] = imageUrl; - - d->loved = lfm["track"]["userloved"].text().toInt(); - - d->forceLoveToggled( d->loved ); -} - -void -lastfm::MutableTrack::setImageUrl( lastfm::ImageSize size, const QString& url ) -{ - d->m_images[size] = url; -} - - -void -lastfm::MutableTrack::love() -{ - QNetworkReply* reply = ws::post(params("love")); - QObject::connect( reply, SIGNAL(finished()), signalProxy(), SLOT(onLoveFinished())); - - invalidateGetInfo(); -} - - -void -lastfm::MutableTrack::unlove() -{ - QNetworkReply* reply = ws::post(params("unlove")); - QObject::connect( reply, SIGNAL(finished()), signalProxy(), SLOT(onUnloveFinished())); - - invalidateGetInfo(); -} - -QNetworkReply* -lastfm::MutableTrack::ban() -{ - d->extras["rating"] = "B"; - return ws::post(params("ban")); -} - - -QMap -lastfm::Track::params( const QString& method, bool use_mbid ) const -{ - QMap map; - map["method"] = "Track."+method; - if (d->mbid.size() && use_mbid) - map["mbid"] = d->mbid; - else { - map["artist"] = d->artist; - map["track"] = d->title; - } - return map; -} - - -QNetworkReply* -lastfm::Track::getSimilar( int limit ) const -{ - QMap map = params("getSimilar"); - if ( limit != -1 ) map["limit"] = QString::number( limit ); - map["autocorrect"] = "1"; - return ws::get( map ); -} - - -QMap > /* static */ -lastfm::Track::getSimilar( QNetworkReply* r ) -{ - QMap > tracks; - try - { - QByteArray b = r->readAll(); - XmlQuery lfm = b; - foreach (XmlQuery e, lfm.children( "track" )) - { - QPair< QString, QString > track; - track.first = e["name"].text(); - - XmlQuery artist = e.children( "artist" ).first(); - track.second = artist["name"].text(); - - // convert floating percentage to int in range 0 to 10,000 - int const match = e["match"].text().toFloat() * 100; - tracks.insertMulti( match, track ); - } - } - catch (ws::ParseError& e) - { - qWarning() << e.what(); - } - - return tracks; -} - - -QNetworkReply* -lastfm::Track::getTopTags() const -{ - return ws::get( params("getTopTags", true) ); -} - - -QNetworkReply* -lastfm::Track::getTopFans() const -{ - return ws::get( params("getTopFans", true) ); -} - - -QNetworkReply* -lastfm::Track::getTags() const -{ - return ws::get( params("getTags", true) ); -} - -void -lastfm::Track::getInfo() const -{ - QMap map = params("getInfo", true); - if (!lastfm::ws::Username.isEmpty()) map["username"] = lastfm::ws::Username; - if (!lastfm::ws::SessionKey.isEmpty()) map["sk"] = lastfm::ws::SessionKey; - QObject::connect( ws::get( map ), SIGNAL(finished()), d.data(), SLOT(onGotInfo())); -} - - -QNetworkReply* -lastfm::Track::getBuyLinks( const QString& country ) const -{ - QMap map = params( "getBuyLinks", true ); - map["country"] = country; - return ws::get( map ); -} - - -QNetworkReply* -lastfm::Track::addTags( const QStringList& tags ) const -{ - if (tags.isEmpty()) - return 0; - QMap map = params("addTags"); - map["tags"] = tags.join( QChar(',') ); - return ws::post(map); -} - - -QNetworkReply* -lastfm::Track::removeTag( const QString& tag ) const -{ - if (tag.isEmpty()) - return 0; - QMap map = params( "removeTag" ); - map["tags"] = tag; - return ws::post(map); -} - - -QNetworkReply* -lastfm::Track::updateNowPlaying() const -{ - return updateNowPlaying(duration()); -} - -QNetworkReply* -lastfm::Track::updateNowPlaying( int duration ) const -{ - QMap map = params("updateNowPlaying"); - map["duration"] = QString::number( duration ); - if ( !album().isNull() ) map["album"] = album(); - map["context"] = extra("playerId"); - - qDebug() << map; - - return ws::post(map); -} - -QNetworkReply* -lastfm::Track::removeNowPlaying() const -{ - QMap map; - map["method"] = "track.removeNowPlaying"; - - qDebug() << map; - - return ws::post(map); -} - - -QNetworkReply* -lastfm::Track::scrobble() const -{ - QMap map = params("scrobble"); - map["duration"] = QString::number( d->duration ); - map["timestamp"] = QString::number( d->time.toTime_t() ); - map["context"] = extra("playerId"); - map["albumArtist"] = d->albumArtist; - if ( !d->album.isEmpty() ) map["album"] = d->album; - - qDebug() << map; - - return ws::post(map); -} - -QNetworkReply* -lastfm::Track::scrobble(const QList& tracks) -{ - QMap map; - map["method"] = "track.scrobble"; - - for ( int i(0) ; i < tracks.count() ; ++i ) - { - map["duration[" + QString::number(i) + "]"] = QString::number( tracks[i].duration() ); - map["timestamp[" + QString::number(i) + "]"] = QString::number( tracks[i].timestamp().toTime_t() ); - map["track[" + QString::number(i) + "]"] = tracks[i].title(); - map["context[" + QString::number(i) + "]"] = tracks[i].extra("playerId"); - if ( !tracks[i].album().isNull() ) map["album[" + QString::number(i) + "]"] = tracks[i].album(); - map["artist[" + QString::number(i) + "]"] = tracks[i].artist(); - map["albumArtist[" + QString::number(i) + "]"] = tracks[i].albumArtist(); - if ( !tracks[i].mbid().isNull() ) map["mbid[" + QString::number(i) + "]"] = tracks[i].mbid(); - } - - qDebug() << map; - - return ws::post(map); -} - - -QUrl -lastfm::Track::www() const -{ - return UrlBuilder( "music" ).slash( artist( Corrected ) ).slash( album( Corrected ).isNull() ? QString("_") : album( Corrected )).slash( title( Corrected ) ).url(); -} - - -bool -lastfm::Track::isMp3() const -{ - //FIXME really we should check the file header? - return d->url.scheme() == "file" && - d->url.path().endsWith( ".mp3", Qt::CaseInsensitive ); -} - -void -lastfm::MutableTrack::setCorrections( QString title, QString album, QString artist, QString albumArtist ) -{ - d->correctedTitle = title; - d->correctedAlbum = album; - d->correctedArtist = artist; - d->correctedAlbumArtist = albumArtist; - - d->forceCorrected( toString() ); -} - diff --git a/thirdparty/liblastfm2/src/types/Track.h b/thirdparty/liblastfm2/src/types/Track.h deleted file mode 100644 index 4fa0c7043..000000000 --- a/thirdparty/liblastfm2/src/types/Track.h +++ /dev/null @@ -1,367 +0,0 @@ -/* - Copyright 2009-2010 Last.fm Ltd. - - Primarily authored by Max Howell, Jono Cole, Doug Mansell and Michael Coffey - - This file is part of liblastfm. - - liblastfm is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - liblastfm is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with liblastfm. If not, see . -*/ -#ifndef LASTFM_TRACK_H -#define LASTFM_TRACK_H - -#include -#include -#include -#include -#include -#include -#include -#include -#include - - -namespace lastfm { - -class LASTFM_DLLEXPORT TrackContext -{ -public: - enum Type - { - Unknown, - User, - Friend, - Neighbour, - Artist - }; - - TrackContext(); - TrackContext( const QString& type, const QList& values ); - - Type type() const; - QList values() const; -private: - static Type getType( const QString& type ); - -private: - Type m_type; - QList m_values; -}; - -class TrackData : public QObject, public QSharedData -{ - Q_OBJECT - - friend class Track; - friend class MutableTrack; -public: - TrackData(); - -public: - QString artist; - QString albumArtist; - QString album; - QString title; - QString correctedArtist; - QString correctedAlbumArtist; - QString correctedAlbum; - QString correctedTitle; - TrackContext context; - uint trackNumber; - uint duration; - short source; - short rating; - QString mbid; /// musicbrainz id - uint fpid; - QUrl url; - QDateTime time; /// the time the track was started at - bool loved; - QMap m_images; - short scrobbleStatus; - short scrobbleError; - QString scrobbleErrorText; - - //FIXME I hate this, but is used for radio trackauth etc. - QMap extras; - - bool null; - -private: - void forceLoveToggled( bool love ) { emit loveToggled( love );} - void forceScrobbleStatusChanged() { emit scrobbleStatusChanged(); } - void forceCorrected( QString correction ) { emit corrected( correction ); } - -private slots: - void onLoveFinished(); - void onUnloveFinished(); - void onGotInfo(); - -signals: - void loveToggled( bool love ); - void loveFinished(); - void unlovedFinished(); - void gotInfo( const QByteArray& ); - void scrobbleStatusChanged(); - void corrected( QString correction ); -}; - - -/** Our track type. It's quite good, you may want to use it as your track type - * in general. It is explicitly shared. Which means when you make a copy, they - * both point to the same data still. This is like Qt's implicitly shared - * classes, eg. QString, however if you mod a copy of a QString, the copy - * detaches first, so then you have two copies. Our Track object doesn't - * detach, which is very handy for our usage in the client, but perhaps not - * what you want. If you need a deep copy for eg. work in a thread, call - * clone(). */ -class LASTFM_DLLEXPORT Track : public AbstractType -{ -public: - friend class TrackSignalProxy; - - enum Source - { - // DO NOT UNDER ANY CIRCUMSTANCES CHANGE THE ORDER OR VALUES OF THIS ENUM! - // you will cause broken settings and b0rked scrobbler cache submissions - - Unknown = 0, - LastFmRadio, - Player, - MediaDevice, - NonPersonalisedBroadcast, // eg Shoutcast, BBC Radio 1, etc. - PersonalisedRecommendation, // eg Pandora, but not Last.fm - }; - - enum ScrobbleStatus - { - Null = 0, - Cached, - Submitted, - Error - }; - - enum Corrections - { - Original = 0, - Corrected - }; - - enum ScrobbleError - { - None = 0, - FilteredArtistName = 113, - FilteredTrackName = 114, - FilteredAlbumName = 115, - FilteredTimestamp = 116, - ExceededMaxDailyScrobbles = 118, - InvalidStreamAuth = 119 - }; - - Track(); - explicit Track( const QDomElement& ); - - /** this track and that track point to the same object, so they are the same - * in fact. This doesn't do a deep data comparison. So even if all the - * fields are the same it will return false if they aren't in fact spawned - * from the same initial Track object */ - bool sameObject( const Track& that ) - { - return (this->d == that.d); - } - - bool operator==( const Track& that ) const - { - return ( this->title() == that.title() && - this->album() == that.album() && - this->artist() == that.artist()); - } - bool operator!=( const Track& that ) const - { - return !operator==( that ); - } - - QObject* signalProxy() const { return d.data(); } - - /** only a Track() is null */ - bool isNull() const { return d->null; } - - bool corrected() const; - - Artist artist( Corrections corrected = Original ) const; - Artist albumArtist( Corrections corrected = Original ) const; - Album album( Corrections corrected = Original ) const; - QString title( Corrections corrected = Original ) const; - - uint trackNumber() const { return d->trackNumber; } - uint duration() const { return d->duration; } /// in seconds - Mbid mbid() const { return Mbid(d->mbid); } - QUrl url() const { return d->url; } - QDateTime timestamp() const { return d->time; } - Source source() const { return static_cast(d->source); } - uint fingerprintId() const { return d->fpid; } - bool isLoved() const { return d->loved; } - QUrl imageUrl( lastfm::ImageSize size, bool square ) const; - - QString durationString() const { return durationString( d->duration ); } - static QString durationString( int seconds ); - - ScrobbleStatus scrobbleStatus() const { return static_cast(d->scrobbleStatus); } - ScrobbleError scrobbleError() const { return static_cast(d->scrobbleError); } - QString scrobbleErrorText() const { return d->scrobbleErrorText; } - - /** default separator is an en-dash */ - QString toString() const { return toString( Corrected ); } - QString toString( Corrections corrections ) const { return toString( QChar(8211), corrections );} - QString toString( const QChar& separator, Corrections corrections = Original ) const; - /** the standard representation of this object as an XML node */ - QDomElement toDomElement( class QDomDocument& ) const; - - TrackContext context() const { return d->context; } - - QString extra( const QString& key ) const{ return d->extras[ key ]; } - - bool operator<( const Track &that ) const - { - return this->d->time < that.d->time; - } - - bool isMp3() const; - - operator QVariant() const { return QVariant::fromValue( *this ); } - -//////////// lastfm::Ws - - /** See last.fm/api Track section */ - QNetworkReply* share( const QStringList& recipients, const QString& message = "", bool isPublic = true ) const; - - QNetworkReply* getSimilar( int limit = -1 ) const; - /** The match percentage is returned from last.fm as a 4 significant - * figure floating point value. So we multply it by 100 to make an - * integer in the range of 0 to 10,000. This is possible confusing - * for you, but I felt it best not to lose any precision, and floats - * aren't much fun. */ - static QMap > getSimilar( QNetworkReply* ); - - /** you can get any QNetworkReply TagList using Tag::list( QNetworkReply* ) */ - QNetworkReply* getTags() const; // for the logged in user - QNetworkReply* getTopTags() const; - QNetworkReply* getTopFans() const; - void getInfo() const; - QNetworkReply* getBuyLinks( const QString& country ) const; - - /** you can only add 10 tags, we submit everything you give us, but the - * docs state 10 only. Will return 0 if the list is empty. */ - QNetworkReply* addTags( const QStringList& ) const; - /** will return 0 if the string is "" */ - QNetworkReply* removeTag( const QString& ) const; - - /** scrobble the track */ - QNetworkReply* updateNowPlaying() const; - QNetworkReply* updateNowPlaying( int duration ) const; - QNetworkReply* removeNowPlaying() const; - QNetworkReply* scrobble() const; - static QNetworkReply* scrobble(const QList& tracks); - - /** the url for this track's page at last.fm */ - QUrl www() const; - -protected: - QExplicitlySharedDataPointer d; - QMap params( const QString& method, bool use_mbid = false ) const; - void invalidateGetInfo(); -private: - Track( TrackData* that_d ) : d( that_d ) - {} -}; - - - -/** This class allows you to change Track objects, it is easy to use: - * MutableTrack( some_track_object ).setTitle( "Arse" ); - * - * We have a separate MutableTrack class because in our usage, tracks - * only get mutated once, and then after that, very rarely. This pattern - * encourages such usage, which is generally sensible. You can feel more - * comfortable that the data hasn't accidently changed behind your back. - */ -class LASTFM_DLLEXPORT MutableTrack : public Track -{ -public: - MutableTrack() - { - d->null = false; - } - - /** NOTE that passing a Track() to this ctor will automatically make it non - * null. Which may not be what you want. So be careful - * Rationale: this is the most maintainable way to do it - */ - MutableTrack( const Track& that ) : Track( that ) - { - d->null = false; - } - - void setFromLfm( const XmlQuery& lfm ); - void setImageUrl( lastfm::ImageSize size, const QString& url ); - - void setArtist( QString artist ) { d->artist = artist.trimmed(); } - void setAlbumArtist( QString albumArtist ) { d->albumArtist = albumArtist.trimmed(); } - void setAlbum( QString album ) { d->album = album.trimmed(); } - void setTitle( QString title ) { d->title = title.trimmed(); } - void setCorrections( QString title, QString album, QString artist, QString albumArtist ); - void setTrackNumber( uint n ) { d->trackNumber = n; } - void setDuration( uint duration ) { d->duration = duration; } - void setUrl( QUrl url ) { d->url = url; } - void setSource( Source s ) { d->source = s; } - void setLoved( bool loved ) { d->loved = loved; } - - void setMbid( Mbid id ) { d->mbid = id; } - void setFingerprintId( uint id ) { d->fpid = id; } - - void setScrobbleStatus( ScrobbleStatus scrobbleStatus ) - { - d->scrobbleStatus = scrobbleStatus; - d->forceScrobbleStatusChanged(); - } - void setScrobbleError( ScrobbleError scrobbleError ) { d->scrobbleError = scrobbleError; } - void setScrobbleErrorText( const QString& scrobbleErrorText ) { d->scrobbleErrorText = scrobbleErrorText; } - - /** you also must scrobble this track for the love to become permenant */ - void love(); - void unlove(); - QNetworkReply* ban(); - - void stamp() { d->time = QDateTime::currentDateTime(); } - - void setExtra( const QString& key, const QString& value ) { d->extras[key] = value; } - void removeExtra( QString key ) { d->extras.remove( key ); } - void setTimeStamp( const QDateTime& dt ) { d->time = dt; } - - void setContext( TrackContext context ) { d->context = context;} -}; - - -} //namespace lastfm - - -inline QDebug operator<<( QDebug d, const lastfm::Track& t ) -{ - return !t.isNull() - ? d << t.toString( '-' ) << t.url() - : d << "Null Track object"; -} - - -Q_DECLARE_METATYPE( lastfm::Track ); - -#endif //LASTFM_TRACK_H diff --git a/thirdparty/liblastfm2/src/types/User.cpp b/thirdparty/liblastfm2/src/types/User.cpp deleted file mode 100644 index c19bf46ce..000000000 --- a/thirdparty/liblastfm2/src/types/User.cpp +++ /dev/null @@ -1,317 +0,0 @@ -/* - Copyright 2009 Last.fm Ltd. - - Primarily authored by Max Howell, Jono Cole and Doug Mansell - - This file is part of liblastfm. - - liblastfm is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - liblastfm is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with liblastfm. If not, see . -*/ -#include "User.h" -#include "Track.h" -#include "../core/UrlBuilder.h" -#include "../core/XmlQuery.h" -#include -#include -#include - -using lastfm::User; -using lastfm::UserList; -using lastfm::UserDetails; -using lastfm::XmlQuery; -using lastfm::ImageSize; - -User::User( const XmlQuery& xml ) - :AbstractType(), m_match( -1.0f ) -{ - m_name = xml["name"].text(); - m_images << xml["image size=small"].text() - << xml["image size=medium"].text() - << xml["image size=large"].text(); - m_realName = xml["realname"].text(); -} - - -QUrl -User::imageUrl( ImageSize size, bool square ) const -{ - if( !square ) return m_images.value( size ); - - QUrl url = m_images.value( size ); - QRegExp re( "/serve/(\\d*)s?/" ); - return QUrl( url.toString().replace( re, "/serve/\\1s/" )); -} - - -QMap -User::params(const QString& method) const -{ - QMap map; - map["method"] = "user."+method; - map["user"] = m_name; - return map; -} - - -QNetworkReply* -User::getFriends( bool recentTracks, int limit, int page ) const -{ - QMap map = params( "getFriends" ); - map["limit"] = QString::number( limit ); - map["page"] = QString::number( page ); - if ( recentTracks ) map["recenttracks"] = "1"; - return ws::get( map ); -} - - -QNetworkReply* -User::getFriendsListeningNow( int limit, int page ) const -{ - QMap map = params( "getFriendsListeningNow" ); - map["limit"] = QString::number( limit ); - map["page"] = QString::number( page ); - return ws::get( map ); -} - - -QNetworkReply* -User::getTopTags() const -{ - return ws::get( params( "getTopTags" ) ); -} - - -QNetworkReply* -User::getTopArtists( QString period, int limit, int page ) const -{ - QMap map = params( "getTopArtists" ); - map["period"] = period; - map["limit"] = QString::number( limit ); - map["page"] = QString::number( page ); - return ws::get( map ); -} - - -QNetworkReply* -User::getRecentArtists() const -{ - return ws::get( params( "getRecentArtists" ) ); -} - - -QNetworkReply* -User::getRecentTracks( int limit , int page ) const -{ - QMap map = params( "getRecentTracks" ); - map["limit"] = QString::number( limit ); - map["page"] = QString::number( page ); - - QAbstractNetworkCache* cache = lastfm::nam()->cache(); - if ( cache ) - cache->remove( lastfm::ws::url( map ) ); - - return ws::get( map ); -} - -QNetworkReply* -User::getRecentStations( int limit, int page ) const -{ - QMap map = params( "getRecentStations" ); - map["limit"] = QString::number( limit ); - map["page"] = QString::number( page ); - return ws::get( map ); -} - - -QNetworkReply* -User::getRecommendedArtists( int limit, int page ) const -{ - QMap map = params( "getRecommendedArtists" ); - map["limit"] = QString::number( limit ); - map["page"] = QString::number( page ); - return ws::get( map ); -} - - -QNetworkReply* -User::getNeighbours( int limit, int page ) const -{ - QMap map = params( "getNeighbours" ); - map["limit"] = QString::number( limit ); - map["page"] = QString::number( page ); - return ws::get( map ); -} - - -QNetworkReply* -User::getPlaylists() const -{ - return ws::get( params( "getPlaylists" ) ); -} - - -UserList //static -User::list( QNetworkReply* r ) -{ - UserList users; - try { - XmlQuery lfm = r->readAll(); - foreach (XmlQuery e, lfm.children( "user" )) - { - User u( e ); - users += u; - } - - users.total = lfm["friends"].attribute("total").toInt(); - users.page = lfm["friends"].attribute("page").toInt(); - users.perPage = lfm["friends"].attribute("perPage").toInt(); - users.totalPages = lfm["friends"].attribute("totalPages").toInt(); - } - catch (ws::ParseError& e) - { - qWarning() << e.what(); - } - return users; -} - - -QNetworkReply* //static -UserDetails::getInfo( const QString& username ) -{ - QMap map; - map["method"] = "user.getInfo"; - map["user"] = username; - return ws::post( map ); -} - - - - -/* -QNetworkReply* //static -UserDetails::getRecommendedArtists() -{ - QMap map; - map["method"] = "user.getRecommendedArtists"; - return ws::post( map ); -} -*/ - -QUrl -User::www() const -{ - return UrlBuilder( "user" ).slash( m_name ).url(); -} - -UserDetails::UserDetails() - : User() - , m_age( 0 ) - , m_scrobbles( 0 ) - , m_registered( QDateTime() ) - , m_isSubscriber( false ) - , m_canBootstrap( false ) -{} - -UserDetails::UserDetails( QNetworkReply* reply ) -{ - try - { - XmlQuery user = XmlQuery( reply->readAll() )["user"]; - m_age = user["age"].text().toUInt(); - m_scrobbles = user["playcount"].text().toUInt(); - m_registered = QDateTime::fromTime_t(user["registered"].attribute("unixtime").toUInt()); - m_country = user["country"].text(); - m_isSubscriber = ( user["subscriber"].text() == "1" ); - m_canBootstrap = ( user["bootstrap"].text() == "1" ); - m_gender = user["gender"].text(); - m_realName = user["realname"].text(); - m_name = user["name"].text(); - m_images << user["image size=small"].text() - << user["image size=medium"].text() - << user["image size=large"].text(); - } - catch (ws::ParseError& e) - { - qWarning() << e.what(); - } -} - - -QString -UserDetails::getInfoString() const -{ - QString text; - - text = QObject::tr("%1").arg( m_realName.isEmpty() ? m_name : m_realName ); - if ( m_age ) text.append( QObject::tr(", %1").arg( m_age ) ); - if ( m_gender.known() ) text.append( QObject::tr(", %1").arg( m_gender.toString() ) ); - if ( !m_country.isEmpty() ) text.append( QObject::tr(", %1").arg( m_country ) ); - if ( m_scrobbles ) text.append( QObject::tr(", %L1 scrobbles").arg( m_scrobbles ) ); - - return text; -} - -void -UserDetails::setScrobbleCount( quint32 scrobbleCount ) -{ - m_scrobbles = scrobbleCount; -} - - -void -UserDetails::setDateRegistered( const QDateTime& date ) -{ - m_registered = date; -} - -void -UserDetails::setImages( const QList& images ) -{ - m_images = images; -} - -void -UserDetails::setRealName( const QString& realName ) -{ - m_realName = realName; -} -void -UserDetails::setAge( unsigned short age ) -{ - m_age = age; -} - -void -UserDetails::setIsSubscriber( bool subscriber ) -{ - m_isSubscriber = subscriber; -} - -void -UserDetails::setCanBootstrap( bool canBootstrap ) -{ - m_canBootstrap = canBootstrap; -} - -void -UserDetails::setGender( const QString& s ) -{ - m_gender = Gender( s ); -} - -void -UserDetails::setCountry( const QString& country ) -{ - m_country = country; -} - diff --git a/thirdparty/liblastfm2/src/types/User.h b/thirdparty/liblastfm2/src/types/User.h deleted file mode 100644 index 4c8adf08d..000000000 --- a/thirdparty/liblastfm2/src/types/User.h +++ /dev/null @@ -1,184 +0,0 @@ -/* - Copyright 2009-2010 Last.fm Ltd. - - Primarily authored by Max Howell, Jono Cole, Doug Mansell and Michael Coffey - - This file is part of liblastfm. - - liblastfm is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - liblastfm is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with liblastfm. If not, see . -*/ -#ifndef LASTFM_USER_H -#define LASTFM_USER_H - -#include -#include -#include - -#include -#include - -namespace lastfm -{ - class UserList; - - class LASTFM_DLLEXPORT User : public AbstractType - { - public: - User() : AbstractType(), m_name( lastfm::ws::Username ), m_match( -1.0f ) - {} - - User( const QString& name ) : AbstractType(), m_name( name ), m_match( -1.0f ) - {} - - User( const class XmlQuery& xml ); - - lastfm::User& operator=( const lastfm::User& that ) { m_name = that.name(); m_images = that.m_images; m_realName = that.m_realName; m_match = that.m_match; return *this; } - bool operator==(const lastfm::User& that) const { return m_name == that.m_name; } - bool operator<(const lastfm::User& that) const { return m_name < that.m_name; } - - operator QString() const { return m_name; } - QString name() const { return m_name; } - void setName( const QString& name ){ m_name = name; } - - /** use Tag::list() on the response to get a WeightedStringList */ - QNetworkReply* getTopTags() const; - - /** use User::list() on the response to get a QList */ - QNetworkReply* getFriends( bool recentTracks = false, int limit = 50, int page = 1 ) const; - QNetworkReply* getFriendsListeningNow( int limit = 50, int page = 1 ) const; - QNetworkReply* getNeighbours( int limit = 50, int page = 1 ) const; - - QNetworkReply* getPlaylists() const; - QNetworkReply* getTopArtists( QString period = "overall", int limit = 50, int page = 1 ) const; - QNetworkReply* getRecentTracks( int limit = 50, int page = 1 ) const; - QNetworkReply* getRecentArtists() const; - QNetworkReply* getRecentStations( int limit = 10, int page = 1 ) const; - QNetworkReply* getRecommendedArtists( int limit = 50, int page = 1 ) const; - - static UserList list( QNetworkReply* ); - - QString toString() const { return name(); } - QDomElement toDomElement( QDomDocument& ) const { return QDomElement(); } - - ////// - QUrl imageUrl( ImageSize size = Large, bool square = false ) const; - - QString realName() const { return m_realName; } - - /** the user's profile page at www.last.fm */ - QUrl www() const; - - /** Returns the match between the logged in user and the user which this - * object represents (if < 0.0f then not set) */ - float match() const { return m_match; } - - protected: - QString m_name; - - QList m_images; - - float m_match; - - QString m_realName; - - QMap params( const QString& method ) const; - }; - - class LASTFM_DLLEXPORT Gender - { - QString s; - - public: - Gender() :s(/*confused!*/){} - - Gender( const QString& ss ) :s( ss.toLower() ) - {} - - bool known() const { return male() || female(); } - bool male() const { return s == "m"; } - bool female() const { return s == "f"; } - - QString toString() const - { - QString result; - - if (male()) - result = QObject::tr( "m" ); - else if (female()) - result = QObject::tr( "f" ); - else - result = QObject::tr( "n" ); // as in neuter - - return result; - } - }; - - - /** The Extended User contains extra information about a user's account */ - class LASTFM_DLLEXPORT UserDetails : public User - { - public: - UserDetails(); - /** User details */ - UserDetails( QNetworkReply* ); - - /** you can only get information about the any user */ - static QNetworkReply* getInfo( const QString& username = lastfm::ws::Username ); - - /** a verbose string, eg. "A man with 36,153 scrobbles" */ - QString getInfoString() const; - - bool isSubscriber() const{ return m_isSubscriber; } - bool canBootstrap() const{ return m_canBootstrap; } - quint32 scrobbleCount() const{ return m_scrobbles; } - QDateTime dateRegistered() const { return m_registered; } - Gender gender() const { return m_gender; } - QString country() const { return m_country; } - - void setScrobbleCount( quint32 scrobblesCount ); - void setDateRegistered( const QDateTime& date ); - void setImages( const QList& images ); - void setRealName( const QString& realName ); - void setAge( unsigned short age ); - void setIsSubscriber( bool subscriber ); - void setCanBootstrap( bool canBootstrap ); - void setGender( const QString& s ); - void setCountry( const QString& country ); - - - // pass the result to Artist::list(), if you want the other data - // you have to parse the lfm() yourself members - // http://www.last.fm/api/show?service=388 - // static QNetworkReply* getRecommendedArtists(); - - protected: - Gender m_gender; - unsigned short m_age; - unsigned int m_scrobbles; - QDateTime m_registered; - QString m_country; - bool m_isSubscriber; - bool m_canBootstrap; - }; - - class LASTFM_DLLEXPORT UserList : public QList - { - public: - int total; - int page; - int perPage; - int totalPages; - }; -} - -#endif diff --git a/thirdparty/liblastfm2/src/types/Xspf.cpp b/thirdparty/liblastfm2/src/types/Xspf.cpp deleted file mode 100644 index e9a3175b3..000000000 --- a/thirdparty/liblastfm2/src/types/Xspf.cpp +++ /dev/null @@ -1,75 +0,0 @@ -/* - Copyright 2009 Last.fm Ltd. - - Primarily authored by Max Howell, Jono Cole and Doug Mansell - - This file is part of liblastfm. - - liblastfm is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - liblastfm is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with liblastfm. If not, see . -*/ - -#include -#include - -#include "../core/XmlQuery.h" - -#include "Xspf.h" - - -lastfm::Xspf::Xspf( const QDomElement& playlist_node, QObject* parent ) - :QObject( parent ) -{ - XmlQuery e( playlist_node ); - - int expirySeconds = e["link rel=http://www.last.fm/expiry"].text().toInt(); - QTimer::singleShot( expirySeconds * 1000, this, SLOT(onExpired())); - - m_title = e["title"].text(); - - //FIXME should we use UnicornUtils::urlDecode()? - //The title is url encoded, has + instead of space characters - //and has a + at the begining. So it needs cleaning up: - m_title.replace( '+', ' ' ); - m_title = QUrl::fromPercentEncoding( m_title.toAscii()); - m_title = m_title.trimmed(); - - foreach (XmlQuery e, e["trackList"].children( "track" )) - { - MutableTrack t; - t.setUrl( e["location"].text() ); - t.setExtra( "trackauth", e["extension"]["trackauth"].text() ); - t.setTitle( e["title"].text() ); - t.setArtist( e["creator"].text() ); - t.setAlbum( e["album"].text() ); - t.setDuration( e["duration"].text().toInt() / 1000 ); - t.setLoved( e["extension"]["loved"].text() == "1" ); - t.setSource( Track::LastFmRadio ); - - QList contexts; - QDomNodeList contextsNodeList = QDomElement(e["extension"]["context"]).childNodes(); - - for ( int i = 0 ; i < contextsNodeList.count() ; ++i ) - contexts.append( contextsNodeList.item(i).toElement().text() ); - - if ( contexts.count() > 0 ) - t.setContext( TrackContext( contextsNodeList.item(0).toElement().tagName(), contexts ) ); - - m_tracks << t; // outside try block since location is enough basically - } -} - -void -lastfm::Xspf::onExpired() -{ - emit expired(); -} diff --git a/thirdparty/liblastfm2/src/types/Xspf.h b/thirdparty/liblastfm2/src/types/Xspf.h deleted file mode 100644 index 66046b931..000000000 --- a/thirdparty/liblastfm2/src/types/Xspf.h +++ /dev/null @@ -1,52 +0,0 @@ -/* - Copyright 2009 Last.fm Ltd. - - Primarily authored by Max Howell, Jono Cole and Doug Mansell - - This file is part of liblastfm. - - liblastfm is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - liblastfm is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with liblastfm. If not, see . -*/ -#ifndef LASTFM_XSPF_H -#define LASTFM_XSPF_H - -#include -#include - -namespace lastfm -{ - class LASTFM_DLLEXPORT Xspf : public QObject - { - Q_OBJECT - public: - /** pass in the playlist node! */ - Xspf( const class QDomElement& playlist_node, QObject* parent ); - - QString title() const{ return m_title; } - - bool isEmpty() const { return m_tracks.isEmpty(); } - Track takeFirst() { return m_tracks.takeFirst(); } - - signals: - void expired(); - - private slots: - void onExpired(); - - private: - QList m_tracks; - QString m_title; - }; -} - -#endif diff --git a/thirdparty/liblastfm2/src/types/mbid_mp3.c b/thirdparty/liblastfm2/src/types/mbid_mp3.c deleted file mode 100644 index ab494a32f..000000000 --- a/thirdparty/liblastfm2/src/types/mbid_mp3.c +++ /dev/null @@ -1,181 +0,0 @@ -/* -* LICENSE -* -* Copyright (c) 2006, David Nicolson -* All rights reserved. -* -* Redistribution and use in source and binary forms, with or without -* modification, are permitted provided that the following conditions -* are met: -* -* 1. Redistributions of source code must retain the above copyright -* notice, this list of conditions and the following disclaimer. -* 2. Redistributions in binary form must reproduce the above copyright -* notice, this list of conditions and the following disclaimer in the -* documentation and/or other materials provided with the distribution. -* 3. Neither the name of the author nor the names of its contributors -* may be used to endorse or promote products derived from this software -* without specific prior written permission. -* -* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT UNLESS REQUIRED BY -* LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER OR CONTRIBUTOR -* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, -* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT -* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, PROFITS; OR -* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, -* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE -* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, -* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ - -#ifndef __MBID_MP3_H -#define __MBID_MP3_H - -#define MBID_BUFFER_SIZE 37 - -// ----------------------------------------------------------------------------- - -void mfile(size_t length, char ret[], FILE *fp, int *s) { - size_t bytes = fread(ret,1,length,fp); - - if (bytes != length) { - *s = 0; - } -} - -// ----------------------------------------------------------------------------- - -int to_synch_safe(char bytes[]) { - return ((int)bytes[0] << 21) + ((int)bytes[1] << 14) + ((int)bytes[2] << 7) + (int)bytes[3]; -} - -int to_integer(char bytes[]) { - size_t size = 0; - uint i; - for (i=0; i < sizeof(bytes); i++) { - size = size * 256 + ((int)bytes[i] & 0x000000FF); - } - return static_cast(size); -} - -// ----------------------------------------------------------------------------- - -int getMP3_MBID(const char *path, char mbid[MBID_BUFFER_SIZE]) -{ - FILE *fp; - static int s = 1; - char head[3]; - char version[2]; - char flag[1]; - char size[4]; - char size_extended[4]; - int tag_size = 0; - int extended_size = 0; - char frame[4]; - char frame_header[4]; - int frame_size; - int version_major, version_minor; - - if (path == NULL) { - //debug("Received null path\n"); - return -1; - } - - fp = fopen(path,"rb"); - if (fp == NULL) { - //debug("Failed to open music file: %s\n",path); - return -1; - } - - while (s) { - mfile(3,head,fp,&s); - if (!strncmp(head,"ID3",3) == 0) { - //debug("No ID3v2 tag found: %s\n",path); - break; - } - - mfile(2,version,fp,&s); - version_major = (int)version[0]; - version_minor = (int)version[1]; - if (version_major == 2) { - //debug("ID3v2.2.0 does not support MBIDs: %s\n",path); - break; - } - if (version_major != 3 && version_major != 4) { - //debug("Unsupported ID3 version: v2.%d.%d\n",version_major,version_minor); - break; - } - - mfile(1,flag,fp,&s); - if ((unsigned int)flag[0] & 0x00000040) { - //debug("Extended header found\n"); - if (version[0] == 4) { - mfile(4,size_extended,fp,&s); - extended_size = to_synch_safe(size_extended); - } else { - mfile(4,size_extended,fp,&s); - extended_size = to_integer(size_extended); - } - //debug("Extended header size: %d\n",extended_size); - fseek(fp,extended_size,SEEK_CUR); - } - - mfile(4,size,fp,&s); - tag_size = to_synch_safe(size); - //debug("Tag size: %d\n",tag_size); - - while (s) { - if (ftell(fp) > tag_size || ftell(fp) > 1048576) { - break; - } - - mfile(4,frame,fp,&s); - if (frame[0] == 0x00) { - break; - } - if (version_major == 4) { - mfile(4,frame_header,fp,&s); - frame_size = to_synch_safe(frame_header); - } else { - mfile(4,frame_header,fp,&s); - frame_size = to_integer(frame_header); - } - - fseek(fp,2,SEEK_CUR); - //debug("Reading %d bytes from frame %s\n",frame_size,frame); - - if (strncmp(frame,"UFID",4) == 0) { - //char frame_data[frame_size]; - char frame_data[59]; - mfile(59,frame_data,fp,&s); - if (frame_size >= 59 && strncmp(frame_data,"http://musicbrainz.org",22) == 0) { - char *tmbid = frame_data; - tmbid = frame_data + 23; - strncpy(mbid,tmbid,MBID_BUFFER_SIZE-1); - mbid[MBID_BUFFER_SIZE-1] = 0x00; - fclose(fp); - return 0; - } - } else { - fseek(fp,frame_size,SEEK_CUR); - } - } - break; - } - - if (fp) { - fclose(fp); - } - //if (!s) { - // debug("Failed to read music file: %s\n",path); - //} - return -1; - -} - -#endif - -// ----------------------------------------------------------------------------- diff --git a/thirdparty/liblastfm2/src/ws/InternetConnectionMonitor.cpp b/thirdparty/liblastfm2/src/ws/InternetConnectionMonitor.cpp deleted file mode 100644 index 0fe9b9394..000000000 --- a/thirdparty/liblastfm2/src/ws/InternetConnectionMonitor.cpp +++ /dev/null @@ -1,117 +0,0 @@ -/* - Copyright 2009 Last.fm Ltd. - - Primarily authored by Max Howell, Jono Cole and Doug Mansell - - This file is part of liblastfm. - - liblastfm is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - liblastfm is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with liblastfm. If not, see . -*/ - -#include "InternetConnectionMonitor.h" -#include "linux/LNetworkConnectionMonitor.h" -#include "mac/MNetworkConnectionMonitor.h" -#include "win/WNetworkConnectionMonitor.h" -#include "NetworkConnectionMonitor.h" -#include "ws.h" - -lastfm::InternetConnectionMonitor::InternetConnectionMonitor( QObject *parent ) - : QObject( parent ) - , m_up( true ) -{ - m_networkMonitor = createNetworkConnectionMonitor(); - - if ( m_networkMonitor ) - { - connect( m_networkMonitor, SIGNAL( networkUp() ), this, SLOT( onNetworkUp() ) ); - connect( m_networkMonitor, SIGNAL( networkDown() ), this, SLOT( onNetworkDown() ) ); - } - - connect( lastfm::nam(), SIGNAL( finished( QNetworkReply* ) ), this, SLOT( onFinished( QNetworkReply* ) ) ); -} - -void -lastfm::InternetConnectionMonitor::onFinished( QNetworkReply* reply ) -{ - if( reply->attribute( QNetworkRequest::SourceIsFromCacheAttribute).toBool() ) return; - - switch( reply->error() ) - { - case QNetworkReply::NoError: - if ( !m_up ) - { - m_up = true; - emit up(); - emit connectivityChanged( m_up ); - qDebug() << "Internet connection is reachable :)"; - } - break; - case QNetworkReply::HostNotFoundError: - case QNetworkReply::TimeoutError: - case QNetworkReply::ProxyConnectionRefusedError: - case QNetworkReply::ProxyConnectionClosedError: - case QNetworkReply::ProxyNotFoundError: - case QNetworkReply::ProxyTimeoutError: - case QNetworkReply::ProxyAuthenticationRequiredError: - if ( m_up ) - { - m_up = false; - emit down(); - emit connectivityChanged( m_up ); - } - break; - default: - break; - } -} - -void -lastfm::InternetConnectionMonitor::onNetworkUp() -{ -#ifdef Q_OS_MAC - // We don't need to check on mac as the - // check is done as part of the reach api - m_up = true; - emit up(); - emit connectivityChanged( m_up ); - qDebug() << "Internet connection is reachable :)"; -#else - qDebug() << "Network seems to be up again. Let's try if there's internet connection!"; - lastfm::nam()->head( QNetworkRequest( QUrl( tr( "http://www.last.fm/" ) ) ) ); -#endif -} - -void -lastfm::InternetConnectionMonitor::onNetworkDown() -{ - qDebug() << "Internet is unreachable :("; - m_up = false; - emit down(); - emit connectivityChanged( m_up ); -} - -NetworkConnectionMonitor* -lastfm::InternetConnectionMonitor::createNetworkConnectionMonitor() -{ - NetworkConnectionMonitor* ncm = 0; - -#ifdef Q_WS_X11 - ncm = new LNetworkConnectionMonitor( this ); -#elif defined(Q_WS_WIN) - ncm = new WNetworkConnectionMonitor( this ); -#elif defined(Q_WS_MAC) - ncm = new MNetworkConnectionMonitor( this ); -#endif - - return ncm; -} diff --git a/thirdparty/liblastfm2/src/ws/InternetConnectionMonitor.h b/thirdparty/liblastfm2/src/ws/InternetConnectionMonitor.h deleted file mode 100644 index 3f770125c..000000000 --- a/thirdparty/liblastfm2/src/ws/InternetConnectionMonitor.h +++ /dev/null @@ -1,80 +0,0 @@ -/* - Copyright 2009 Last.fm Ltd. - - Primarily authored by Max Howell, Jono Cole and Doug Mansell - - This file is part of liblastfm. - - liblastfm is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - liblastfm is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with liblastfm. If not, see . -*/ - -#ifndef LASTFM_CONNECTION_MONITOR_H -#define LASTFM_CONNECTION_MONITOR_H - -#include -#include - -class NetworkConnectionMonitor; - -#ifdef Q_WS_X11 -class LNetworkConnectionMonitor; -#endif - -namespace lastfm { - -class LASTFM_DLLEXPORT InternetConnectionMonitor : public QObject -{ - Q_OBJECT - enum NMState - { - Unknown, - Asleep, - Connecting, - Connected, - Disconnected - }; - -public: - /** if internet is unavailable you will get a down() signal soon, otherwise - * you won't get a signal until the net goes down */ - InternetConnectionMonitor( QObject *parent = 0 ); - - bool isDown() const { return !m_up; } - bool isUp() const { return m_up; } - - NetworkConnectionMonitor* createNetworkConnectionMonitor(); - -signals: - /** yay! internet has returned */ - void up( const QString& connectionName = "" ); - - /** we think the internet is unavailable, but well, still try, but show - * an unhappy face in the statusbar or something */ - void down( const QString& connectionName = "" ); - - /** emitted after the above */ - void connectivityChanged( bool ); - -private slots: - void onFinished( QNetworkReply* reply ); - void onNetworkUp(); - void onNetworkDown(); - -private: - bool m_up; - NetworkConnectionMonitor* m_networkMonitor; -}; - -} //namespace lastfm - -#endif diff --git a/thirdparty/liblastfm2/src/ws/NetworkAccessManager.cpp b/thirdparty/liblastfm2/src/ws/NetworkAccessManager.cpp deleted file mode 100644 index 16ac5e78e..000000000 --- a/thirdparty/liblastfm2/src/ws/NetworkAccessManager.cpp +++ /dev/null @@ -1,159 +0,0 @@ -/* - Copyright 2009 Last.fm Ltd. - - Primarily authored by Max Howell, Jono Cole and Doug Mansell - - This file is part of liblastfm. - - liblastfm is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - liblastfm is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with liblastfm. If not, see . -*/ -#include "NetworkAccessManager.h" -#include "InternetConnectionMonitor.h" -#include -#include -#include -#include -#ifdef WIN32 -#include "win/IeSettings.h" -#include "win/Pac.h" -#endif -#ifdef __APPLE__ -#include "mac/ProxyDict.h" -#endif - - -static struct NetworkAccessManagerInit -{ - // We do this upfront because then our Firehose QTcpSocket will have a proxy - // set by default. As well as any plain QNetworkAcessManager stuff, and the - // scrobbler - // In theory we should do this every request in case the configuration - // changes but that is fairly unlikely use case, init? Maybe we should - // anyway.. - - NetworkAccessManagerInit() - { - #ifdef WIN32 - IeSettings s; - // if it's autodetect, we determine the proxy everytime in proxy() - // we don't really want to do a PAC lookup here, as it times out - // at two seconds, so that hangs startup - if (!s.fAutoDetect && s.lpszProxy) - { - QUrl url( QString::fromUtf16((const unsigned short*)s.lpszProxy) ); - QNetworkProxy proxy( QNetworkProxy::HttpProxy ); - proxy.setHostName( url.host() ); - proxy.setPort( url.port() ); - QNetworkProxy::setApplicationProxy( proxy ); - } - #endif - #ifdef __APPLE__ - ProxyDict dict; - if (dict.isProxyEnabled()) - { - QNetworkProxy proxy( QNetworkProxy::HttpProxy ); - proxy.setHostName( dict.host ); - proxy.setPort( dict.port ); - - QNetworkProxy::setApplicationProxy( proxy ); - } - #endif - } -} init; - - -namespace lastfm -{ - LASTFM_DLLEXPORT QByteArray UserAgent; -} - - -lastfm::NetworkAccessManager::NetworkAccessManager( QObject* parent ) - : QNetworkAccessManager( parent ) - #ifdef WIN32 - , m_pac( 0 ) - , m_monitor( 0 ) - #endif -{ - // can't be done in above init, as applicationName() won't be set - if (lastfm::UserAgent.isEmpty()) - { - QByteArray name = QCoreApplication::applicationName().toUtf8(); - QByteArray version = QCoreApplication::applicationVersion().toUtf8(); - if (version.size()) version.prepend( ' ' ); - lastfm::UserAgent = name + version + " (" + lastfm::platform() + ")"; - } -} - - -lastfm::NetworkAccessManager::~NetworkAccessManager() -{ -#ifdef WIN32 - delete m_pac; -#endif -} - - -QNetworkProxy -lastfm::NetworkAccessManager::proxy( const QNetworkRequest& request ) -{ - Q_UNUSED( request ); - -#ifdef WIN32 - IeSettings s; - if (s.fAutoDetect) - { - if (!m_pac) { - m_pac = new Pac; - if ( !m_monitor ) - { - m_monitor = new InternetConnectionMonitor( this ); - connect( m_monitor, SIGNAL( connectivityChanged( bool ) ), SLOT( onConnectivityChanged( bool ) ) ); - } - } - return m_pac->resolve( request, s.lpszAutoConfigUrl ); - } -#endif - - return QNetworkProxy::applicationProxy(); -} - - -QNetworkReply* -lastfm::NetworkAccessManager::createRequest( Operation op, const QNetworkRequest& request_, QIODevice* outgoingData ) -{ - QNetworkRequest request = request_; - - request.setAttribute( QNetworkRequest::CacheLoadControlAttribute, QNetworkRequest::PreferCache ); - request.setRawHeader( "User-Agent", lastfm::UserAgent ); - -#ifdef WIN32 - // PAC proxies can vary by domain, so we have to check everytime :( - QNetworkProxy proxy = this->proxy( request ); - if (proxy.type() != QNetworkProxy::NoProxy) - QNetworkAccessManager::setProxy( proxy ); -#endif - - return QNetworkAccessManager::createRequest( op, request, outgoingData ); -} - - -void -lastfm::NetworkAccessManager::onConnectivityChanged( bool up ) -{ - Q_UNUSED( up ); - -#ifdef WIN32 - if (up && m_pac) m_pac->resetFailedState(); -#endif -} diff --git a/thirdparty/liblastfm2/src/ws/NetworkAccessManager.h b/thirdparty/liblastfm2/src/ws/NetworkAccessManager.h deleted file mode 100644 index a3022ce25..000000000 --- a/thirdparty/liblastfm2/src/ws/NetworkAccessManager.h +++ /dev/null @@ -1,66 +0,0 @@ -/* - Copyright 2009 Last.fm Ltd. - - Primarily authored by Max Howell, Jono Cole and Doug Mansell - - This file is part of liblastfm. - - liblastfm is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - liblastfm is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with liblastfm. If not, see . -*/ -#ifndef LASTFM_WS_ACCESS_MANAGER_H -#define LASTFM_WS_ACCESS_MANAGER_H - -#include -#include -#include -#include - - -namespace lastfm { - -/** Sets useragent and proxy. Auto detecting the proxy where possible. */ -class LASTFM_DLLEXPORT NetworkAccessManager : public QNetworkAccessManager -{ - Q_OBJECT - -#ifdef Q_WS_WIN - class Pac *m_pac; - class InternetConnectionMonitor* m_monitor; -#endif - -public: - NetworkAccessManager( QObject *parent = 0 ); - ~NetworkAccessManager(); - - /** PAC allows different proxy configurations depending on the request - * URL and even UserAgent! Thus we allow you to pass that in, we - * automatically configure the proxy for every request through - * WsAccessManager */ - QNetworkProxy proxy( const QNetworkRequest& = QNetworkRequest() ); - -protected: - virtual QNetworkReply* createRequest( Operation, const QNetworkRequest&, QIODevice* outgoingdata = 0 ); - -private slots: - void onConnectivityChanged( bool ); - -private: - /** this function calls QNetworkAccessManager::setProxy, and thus - * configures the proxy correctly for the next request created by - * createRequest. This is necessary due */ - void applyProxy( const QNetworkRequest& ); -}; - -} //namespace lastfm - -#endif diff --git a/thirdparty/liblastfm2/src/ws/NetworkConnectionMonitor.cpp b/thirdparty/liblastfm2/src/ws/NetworkConnectionMonitor.cpp deleted file mode 100644 index b4a62732b..000000000 --- a/thirdparty/liblastfm2/src/ws/NetworkConnectionMonitor.cpp +++ /dev/null @@ -1,51 +0,0 @@ -/* - Copyright 2010 Last.fm Ltd. - - Primarily authored by Max Howell, Jono Cole and Doug Mansell - - This file is part of liblastfm. - - liblastfm is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - liblastfm is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with liblastfm. If not, see . -*/ - -#include "NetworkConnectionMonitor.h" - -NetworkConnectionMonitor::NetworkConnectionMonitor( QObject* /*parent*/ ) - : m_connected( true ) -{ -} - -NetworkConnectionMonitor::~NetworkConnectionMonitor() -{ -} - -bool -NetworkConnectionMonitor::isConnected() const -{ - return m_connected; -} - -void -NetworkConnectionMonitor::setConnected( bool connected ) -{ - if ( m_connected != connected ) - { - m_connected = connected; - - if ( connected ) - emit networkUp(); - else - emit networkDown(); - } -} - diff --git a/thirdparty/liblastfm2/src/ws/NetworkConnectionMonitor.h b/thirdparty/liblastfm2/src/ws/NetworkConnectionMonitor.h deleted file mode 100644 index a21cf73e3..000000000 --- a/thirdparty/liblastfm2/src/ws/NetworkConnectionMonitor.h +++ /dev/null @@ -1,46 +0,0 @@ -/* - Copyright 2010 Last.fm Ltd. - - Primarily authored by Jono Cole, Michael Coffey, and William Viana - - This file is part of liblastfm. - - liblastfm is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - liblastfm is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with liblastfm. If not, see . -*/ - -#ifndef NETWORK_CONNECTION_MONITOR_H -#define NETWORK_CONNECTION_MONITOR_H - -#include -#include - -class LASTFM_DLLEXPORT NetworkConnectionMonitor : public QObject -{ - Q_OBJECT -public: - NetworkConnectionMonitor( QObject *parent = 0 ); - ~NetworkConnectionMonitor(); - bool isConnected() const; - -signals: - void networkUp(); - void networkDown(); - -protected: - void setConnected( bool connected ); - -private: - bool m_connected; -}; - -#endif // NETWORK_CONNECTION_MONITOR_H diff --git a/thirdparty/liblastfm2/src/ws/linux/LNetworkConnectionMonitor.h b/thirdparty/liblastfm2/src/ws/linux/LNetworkConnectionMonitor.h deleted file mode 100644 index 9f7895bed..000000000 --- a/thirdparty/liblastfm2/src/ws/linux/LNetworkConnectionMonitor.h +++ /dev/null @@ -1,54 +0,0 @@ -/* - Copyright 2010 Last.fm Ltd. - - Primarily authored by Max Howell, Jono Cole and Doug Mansell - - This file is part of liblastfm. - - liblastfm is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - liblastfm is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with liblastfm. If not, see . -*/ - - -#ifndef LNETWORK_CONNECTION_MONITOR_H -#define LNETWORK_CONNECTION_MONITOR_H - -#include "../NetworkConnectionMonitor.h" -#include -#include - -class QDBusConnection; -class QDBusInterface; - -class LNetworkConnectionMonitor : public NetworkConnectionMonitor -{ - Q_OBJECT - - enum NMState - { - Unknown=1, - Asleep, - Connected, - Disconnected - }; - -public: - LNetworkConnectionMonitor( QObject* parent = 0 ); - ~LNetworkConnectionMonitor(); -private slots: - void onStateChange( uint newState ); -private: - QDBusInterface* m_nmInterface; -}; - -#endif // LNETWORK_CONNECTION_MONITOR_H - diff --git a/thirdparty/liblastfm2/src/ws/linux/LNetworkConnectionMonitor_linux.cpp b/thirdparty/liblastfm2/src/ws/linux/LNetworkConnectionMonitor_linux.cpp deleted file mode 100644 index d8dea9dd6..000000000 --- a/thirdparty/liblastfm2/src/ws/linux/LNetworkConnectionMonitor_linux.cpp +++ /dev/null @@ -1,86 +0,0 @@ -/* - Copyright 2010 Last.fm Ltd. - - Primarily authored by Max Howell, Jono Cole and Doug Mansell - - This file is part of liblastfm. - - liblastfm is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - liblastfm is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with liblastfm. If not, see . -*/ - - -#include "LNetworkConnectionMonitor.h" - -#include -#include -#include - -LNetworkConnectionMonitor::LNetworkConnectionMonitor( QObject* parent ) : - NetworkConnectionMonitor( parent ) -{ - m_nmInterface = new QDBusInterface( QString( "org.freedesktop.NetworkManager" ), - QString( "/org/freedesktop/NetworkManager" ), - QString( "org.freedesktop.NetworkManager" ), - QDBusConnection::systemBus(), - this ); - - //get current connection state - QDBusInterface* dbusInterface = new QDBusInterface( QString( "org.freedesktop.NetworkManager" ), - QString( "/org/freedesktop/NetworkManager" ), - QString( "org.freedesktop.DBus.Properties" ), - QDBusConnection::systemBus(), - this ); - - QDBusReply reply = dbusInterface->call( "Get", "org.freedesktop.NetworkManager", "state" ); - if ( reply.isValid() ) - { - if ( reply.value() == Connected ) - { - setConnected( true ); - } - else if ( reply.value() == Disconnected ) - { - setConnected( false ); - } - } - else - { - qDebug() << "Error: " << reply.error(); - } - delete dbusInterface; - - //connect network manager signals - connect( m_nmInterface, SIGNAL( StateChange( uint ) ), this, SLOT( onStateChange( uint ) ) ); - -} - -LNetworkConnectionMonitor::~LNetworkConnectionMonitor() -{ - delete m_nmInterface; -} - - -void -LNetworkConnectionMonitor::onStateChange( uint newState ) -{ - qDebug() << "Networkmanager state change!"; - - if ( newState == Disconnected ) - { - setConnected( false ); - } - else if ( newState == Connected ) - { - setConnected( true ); - } -} diff --git a/thirdparty/liblastfm2/src/ws/mac/MNetworkConnectionMonitor.h b/thirdparty/liblastfm2/src/ws/mac/MNetworkConnectionMonitor.h deleted file mode 100644 index 96aca0767..000000000 --- a/thirdparty/liblastfm2/src/ws/mac/MNetworkConnectionMonitor.h +++ /dev/null @@ -1,52 +0,0 @@ -/* - Copyright 2009 Last.fm Ltd. - - Primarily authored by Jono Cole and Michael Coffey - - This file is part of liblastfm. - - liblastfm is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - liblastfm is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with liblastfm. If not, see . -*/ - -#ifndef MNETWORK_CONNECTION_MONITOR_H -#define MNETWORK_CONNECTION_MONITOR_H - -#include "../NetworkConnectionMonitor.h" -#include -#include - -#ifdef Q_WS_MAC -#include //TODO remove -#include -#endif - -class __SCNetworkReachability; - -class MNetworkConnectionMonitor : public NetworkConnectionMonitor -{ - Q_OBJECT -public: - MNetworkConnectionMonitor( QObject* parent = 0 ); - ~MNetworkConnectionMonitor(); -private slots: - -private: -#ifdef Q_WS_MAC - static void callback( SCNetworkReachabilityRef target, - SCNetworkConnectionFlags flags, - void *info ); -#endif -}; - -#endif // MNETWORK_CONNECTION_MONITOR_H - diff --git a/thirdparty/liblastfm2/src/ws/mac/MNetworkConnectionMonitor_mac.cpp b/thirdparty/liblastfm2/src/ws/mac/MNetworkConnectionMonitor_mac.cpp deleted file mode 100644 index fd966a4ec..000000000 --- a/thirdparty/liblastfm2/src/ws/mac/MNetworkConnectionMonitor_mac.cpp +++ /dev/null @@ -1,70 +0,0 @@ -/* - Copyright 2009 Last.fm Ltd. - - Primarily authored by Jono Cole and Michael Coffey - - This file is part of liblastfm. - - liblastfm is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - liblastfm is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with liblastfm. If not, see . -*/ - -#include "MNetworkConnectionMonitor.h" - -#include -#include - -#include "../ws.h" - -MNetworkConnectionMonitor* context = 0; - -MNetworkConnectionMonitor::MNetworkConnectionMonitor( QObject* parent ) : - NetworkConnectionMonitor( parent ) -{ - context = this; - - SCNetworkReachabilityRef ref = SCNetworkReachabilityCreateWithName( NULL, LASTFM_WS_HOSTNAME ); - SCNetworkReachabilityScheduleWithRunLoop( ref, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode ); - SCNetworkReachabilitySetCallback( ref, callback, NULL ); - CFRelease( ref ); -} - -MNetworkConnectionMonitor::~MNetworkConnectionMonitor() -{ -} - - -void -MNetworkConnectionMonitor::callback( SCNetworkReachabilityRef target, - SCNetworkConnectionFlags flags, - void * ) -{ - static bool up = true; - - // I couldn't find any diffinitive usage examples for these flags - // so I had to guess, since I can't test, eg. dial up :( - - bool b; - if (flags & kSCNetworkFlagsConnectionRequired) - b = false; - else - b = flags & (kSCNetworkFlagsReachable | kSCNetworkFlagsTransientConnection | kSCNetworkFlagsConnectionAutomatic); - - // basically, avoids telling everyone that we're up already on startup - if (up == b) - return; - - up = b; - - context->setConnected(b); -} - diff --git a/thirdparty/liblastfm2/src/ws/mac/ProxyDict.h b/thirdparty/liblastfm2/src/ws/mac/ProxyDict.h deleted file mode 100644 index 2d873f88a..000000000 --- a/thirdparty/liblastfm2/src/ws/mac/ProxyDict.h +++ /dev/null @@ -1,75 +0,0 @@ -/* - Copyright 2009 Last.fm Ltd. - - Primarily authored by Max Howell, Jono Cole and Doug Mansell - - This file is part of liblastfm. - - liblastfm is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - liblastfm is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with liblastfm. If not, see . -*/ -#include - - -struct ProxyDict -{ - ProxyDict(); - - int port; - QString host; - - bool isProxyEnabled() const { return port > 0 && host.size(); } -}; - - -inline ProxyDict::ProxyDict() : port( 0 ) -{ - // Get the dictionary. - CFDictionaryRef proxyDict = SCDynamicStoreCopyProxies( NULL ); - bool result = (proxyDict != NULL); - - // Get the enable flag. This isn't a CFBoolean, but a CFNumber. - CFNumberRef enableNum; - int enable; - if (result) { - enableNum = (CFNumberRef) CFDictionaryGetValue( proxyDict, kSCPropNetProxiesHTTPEnable ); - result = (enableNum != NULL) && (CFGetTypeID(enableNum) == CFNumberGetTypeID()); - } - if (result) - result = CFNumberGetValue( enableNum, kCFNumberIntType, &enable ) && (enable != 0); - - // Get the proxy host. DNS names must be in ASCII. If you - // put a non-ASCII character in the "Secure Web Proxy" - // field in the Network preferences panel, the CFStringGetCString - // function will fail and this function will return false. - CFStringRef hostStr; - if (result) { - hostStr = (CFStringRef) CFDictionaryGetValue( proxyDict, kSCPropNetProxiesHTTPProxy ); - result = (hostStr != NULL) && (CFGetTypeID(hostStr) == CFStringGetTypeID()); - } - if (result) - host = lastfm::CFStringToQString( hostStr ); - - // get the proxy port - CFNumberRef portNum; - - if (result) { - portNum = (CFNumberRef) CFDictionaryGetValue( proxyDict, kSCPropNetProxiesHTTPPort ); - result = (portNum != NULL) && (CFGetTypeID(portNum) == CFNumberGetTypeID()); - } - if (result) - result = CFNumberGetValue( portNum, kCFNumberIntType, &port ); - - // clean up. - if (proxyDict != NULL) - CFRelease( proxyDict ); -} diff --git a/thirdparty/liblastfm2/src/ws/win/ComSetup.h b/thirdparty/liblastfm2/src/ws/win/ComSetup.h deleted file mode 100644 index ce8685428..000000000 --- a/thirdparty/liblastfm2/src/ws/win/ComSetup.h +++ /dev/null @@ -1,64 +0,0 @@ -/* - Copyright 2009 Last.fm Ltd. - - Primarily authored by Max Howell, Jono Cole and Doug Mansell - - This file is part of liblastfm. - - liblastfm is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - liblastfm is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with liblastfm. If not, see . -*/ -#ifndef _WIN32_WINNT -// bring in CoInitializeSecurity from objbase.h -#define _WIN32_WINNT 0x0400 -#endif - -#include -#include "winable.h" -//#include -//#include - - -/** @brief WsConnectionMonitor needs Com to work as early as possible so we do this - * @author - */ -class ComSetup -{ -public: - ComSetup() - { - HRESULT hr = CoInitialize(0); - m_bComInitialised = SUCCEEDED(hr); - //_ASSERT(m_bComInitialised); - if (m_bComInitialised) { - setupSecurity(); - } - } - - void setupSecurity() - { - //CSecurityDescriptor sd; - //sd.InitializeFromThreadToken(); - //HRESULT hr = CoInitializeSecurity(sd, -1, NULL, NULL, RPC_C_AUTHN_LEVEL_PKT, RPC_C_IMP_LEVEL_IMPERSONATE, NULL, EOAC_NONE, NULL); - //_ASSERT(SUCCEEDED(hr)); - } - - ~ComSetup() - { - if (m_bComInitialised) { - CoUninitialize(); - } - } - -private: - bool m_bComInitialised; -}; diff --git a/thirdparty/liblastfm2/src/ws/win/IeSettings.h b/thirdparty/liblastfm2/src/ws/win/IeSettings.h deleted file mode 100644 index 414ce6507..000000000 --- a/thirdparty/liblastfm2/src/ws/win/IeSettings.h +++ /dev/null @@ -1,43 +0,0 @@ -/* - Copyright 2009 Last.fm Ltd. - - Primarily authored by Max Howell, Jono Cole and Doug Mansell - - This file is part of liblastfm. - - liblastfm is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - liblastfm is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with liblastfm. If not, see . -*/ -#include -#include - - -/** @brief memory managing wrapper for WINHTTP_CURRENT_USER_IE_PROXY_CONFIG - * @author - */ -struct IeSettings : WINHTTP_CURRENT_USER_IE_PROXY_CONFIG -{ -/* IeSettings() - { - if (!WinHttpGetIEProxyConfigForCurrentUser(this)) { - fAutoDetect = FALSE; - lpszAutoConfigUrl = lpszProxy = lpszProxyBypass = 0; - } - } - - ~IeSettings() - { - if (lpszAutoConfigUrl) GlobalFree(lpszAutoConfigUrl); - if (lpszProxy) GlobalFree(lpszProxy); - if (lpszProxyBypass) GlobalFree(lpszProxyBypass); - }*/ -}; diff --git a/thirdparty/liblastfm2/src/ws/win/NdisEvents.cpp b/thirdparty/liblastfm2/src/ws/win/NdisEvents.cpp deleted file mode 100644 index 64eda9b36..000000000 --- a/thirdparty/liblastfm2/src/ws/win/NdisEvents.cpp +++ /dev/null @@ -1,87 +0,0 @@ -/* - Copyright 2009 Last.fm Ltd. - - Primarily authored by Max Howell, Jono Cole and Doug Mansell - - This file is part of liblastfm. - - liblastfm is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - liblastfm is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with liblastfm. If not, see . -*/ -#include "NdisEvents.h" -#include "WmiSink.h" - -// see http://msdn.microsoft.com/en-us/magazine/cc301850.aspx for -// more about Ndis and wmi and getting these events - -// Link to wbemuuid.lib to resolve IWbemObjectSink and IWbemClassObject -// interface definitions. - -NdisEvents::NdisEvents() - : m_pSink(0) -{} - -NdisEvents::~NdisEvents() -{ -// if (m_pSink) -// m_pSink->disconnect(); -// if (m_pServices && m_pSink) -// m_pServices->CancelAsyncCall(m_pSink); - // and reference counting will take care of the WmiSink object -} - -HRESULT -NdisEvents::registerForNdisEvents() -{ - HRESULT hr = 0; // m_pLocator.CoCreateInstance(CLSID_WbemLocator); - if (FAILED(hr)) - return hr; - - // Connect to the root\wmi namespace with the current user. - hr = 0; /*m_pLocator->ConnectServer(CComBSTR("ROOT\\WMI"), // strNetworkResource - NULL, // strUser - NULL, // strPassword - NULL, // strLocale - 0, // lSecurityFlags - CComBSTR(""), // strAuthority - NULL, // pCtx - &m_pServices - );*/ - if (FAILED(hr)) - return hr; - -// m_pSink = new WmiSink(this); - - ////////////////////////// - - // other notifications we're not interested in right now include... - // MSNdis_NotifyAdapterArrival \DEVICE\ - // MSNdis_NotifyAdapterRemoval - // MSNdis_StatusLinkSpeedChange - // MSNdis_NotifyVcArrival - // MSNdis_NotifyVcRemoval - // MSNdis_StatusResetStart - // MSNdis_StatusResetEnd - // MSNdis_StatusProtocolBind - // MSNdis_StatusProtocolUnbind - // MSNdis_StatusMediaSpecificIndication - -/* CComBSTR wql("WQL"); - CComBSTR query("SELECT * FROM MSNdis_StatusMediaDisconnect"); - hr = m_pServices->ExecNotificationQueryAsync(wql, query, 0, 0, m_pSink); - - query = "SELECT * FROM MSNdis_StatusMediaConnect"; - hr = m_pServices->ExecNotificationQueryAsync(wql, query, 0, 0, m_pSink);*/ - - return S_OK; -} - diff --git a/thirdparty/liblastfm2/src/ws/win/NdisEvents.h b/thirdparty/liblastfm2/src/ws/win/NdisEvents.h deleted file mode 100644 index 9d3fa0735..000000000 --- a/thirdparty/liblastfm2/src/ws/win/NdisEvents.h +++ /dev/null @@ -1,44 +0,0 @@ -/* - Copyright 2009 Last.fm Ltd. - - Primarily authored by Max Howell, Jono Cole and Doug Mansell - - This file is part of liblastfm. - - liblastfm is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - liblastfm is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with liblastfm. If not, see . -*/ -#ifndef NDIS_EVENTS_H -#define NDIS_EVENTS_H - -#include -//#include -//#include - -class NdisEvents -{ -public: - NdisEvents(); - ~NdisEvents(); - HRESULT registerForNdisEvents(); - - virtual void onConnectionUp(BSTR name) = 0; - virtual void onConnectionDown(BSTR name) = 0; - -private: -// CComPtr m_pLocator; -// CComPtr m_pServices; - class WmiSink *m_pSink; -}; - -#endif - diff --git a/thirdparty/liblastfm2/src/ws/win/Pac.cpp b/thirdparty/liblastfm2/src/ws/win/Pac.cpp deleted file mode 100644 index 9a73468a9..000000000 --- a/thirdparty/liblastfm2/src/ws/win/Pac.cpp +++ /dev/null @@ -1,129 +0,0 @@ -/* - Copyright 2009 Last.fm Ltd. - - Primarily authored by Max Howell, Jono Cole and Doug Mansell - - This file is part of liblastfm. - - liblastfm is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - liblastfm is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with liblastfm. If not, see . -*/ -#include "Pac.h" -#include -#include -#include -#include -//#include -//#include - - -static bool -parsePacServer(const QString &s, QNetworkProxy &p) -{ - // remove optional leading "scheme=" portion - int start = s.indexOf('='); - QUrl url(s.mid(start+1), QUrl::TolerantMode); - - if (url.isValid()) - { - p.setHostName(url.host()); - p.setPort(url.port()); - return true; - } - return false; -} - - -static QList -parsePacResult(const QString &pacResult) -{ - // msdn says: "The proxy server list contains one or more of the - // following strings separated by semicolons or whitespace." - // ([=]["://"][":"]) - - QList result; - QStringList proxies = pacResult.split(QRegExp("[\\s;]"), QString::SkipEmptyParts); - foreach(const QString &s, proxies) - { - QNetworkProxy proxy( QNetworkProxy::HttpProxy ); - if (parsePacServer(s, proxy)) - { - result << proxy; - } - } - return result; -} - - -//////////////// - - -lastfm::Pac::Pac() - : m_bFailed( false ) - , m_hSession( 0 ) -{} - -lastfm::Pac::~Pac() -{ -/* if (m_hSession) - WinHttpCloseHandle(m_hSession);*/ -} - -QNetworkProxy -lastfm::Pac::resolve(const QNetworkRequest &request, const wchar_t* pacUrl) -{ - QNetworkProxy out; - if (m_bFailed) return out; - - if (!m_hSession) - { - QByteArray user_agent = request.rawHeader("user-agent"); - //m_hSession = WinHttpOpen(CA2W(user_agent), WINHTTP_ACCESS_TYPE_NO_PROXY, 0, 0, WINHTTP_FLAG_ASYNC); - } - if (m_hSession) - { - WINHTTP_PROXY_INFO info; - WINHTTP_AUTOPROXY_OPTIONS opts; - memset(&opts, 0, sizeof(opts)); - if (pacUrl) - { - // opts.dwFlags = WINHTTP_AUTOPROXY_CONFIG_URL; - // opts.lpszAutoConfigUrl = pacUrl; - } - else - { - // opts.dwFlags = WINHTTP_AUTOPROXY_AUTO_DETECT; - // opts.dwAutoDetectFlags = WINHTTP_AUTO_DETECT_TYPE_DHCP | WINHTTP_AUTO_DETECT_TYPE_DNS_A; - } - opts.fAutoLogonIfChallenged = TRUE; - -/* if (WinHttpGetProxyForUrl(m_hSession, (const WCHAR*)request.url().toString().utf16(), &opts, &info)) { - if (info.lpszProxy) - { - QList proxies = parsePacResult(QString::fromUtf16((const ushort*)info.lpszProxy)); - if (!proxies.empty()) - { - out = proxies.at(0); - } - GlobalFree((void*)info.lpszProxy); - } - if (info.lpszProxyBypass) - { - GlobalFree((void*)info.lpszProxyBypass); - } - } else { - m_bFailed = true; - }*/ - } - - return out; -} diff --git a/thirdparty/liblastfm2/src/ws/win/Pac.h b/thirdparty/liblastfm2/src/ws/win/Pac.h deleted file mode 100644 index 075d128f6..000000000 --- a/thirdparty/liblastfm2/src/ws/win/Pac.h +++ /dev/null @@ -1,52 +0,0 @@ -/* - Copyright 2009 Last.fm Ltd. - - Primarily authored by Max Howell, Jono Cole and Doug Mansell - - This file is part of liblastfm. - - liblastfm is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - liblastfm is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with liblastfm. If not, see . -*/ -#ifndef WS_AUTOPROXY_H -#define WS_AUTOPROXY_H - -#include -#include -#include -class QNetworkRequest; - -namespace lastfm -{ - /** @brief simple wrapper to do per url automatic proxy detection - * @author - */ - class Pac - { - HINTERNET m_hSession; - bool m_bFailed; - - public: - Pac(); - ~Pac(); - - QNetworkProxy resolve( const QNetworkRequest& url, const wchar_t* pacUrl ); - - void resetFailedState() { m_bFailed = false; } - - private: - Pac( const Pac& ); //undefined - Pac operator=( const Pac& ); //undefined - }; -} - -#endif \ No newline at end of file diff --git a/thirdparty/liblastfm2/src/ws/win/WNetworkConnectionMonitor.h b/thirdparty/liblastfm2/src/ws/win/WNetworkConnectionMonitor.h deleted file mode 100755 index 26fb58cdd..000000000 --- a/thirdparty/liblastfm2/src/ws/win/WNetworkConnectionMonitor.h +++ /dev/null @@ -1,44 +0,0 @@ -/* - Copyright 2010 Last.fm Ltd. - - Primarily authored by Jono Cole, Michael Coffey, and William Viana - - This file is part of liblastfm. - - liblastfm is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - liblastfm is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with liblastfm. If not, see . -*/ - -#ifndef WNETWORK_CONNECTION_MONITOR_H -#define WNETWORK_CONNECTION_MONITOR_H - -#include "../NetworkConnectionMonitor.h" -#include -#include - -namespace lastfm { class NdisEventsProxy; } - -class WNetworkConnectionMonitor : public NetworkConnectionMonitor -{ - Q_OBJECT -public: - friend class lastfm::NdisEventsProxy; - - WNetworkConnectionMonitor( QObject* parent = 0 ); - ~WNetworkConnectionMonitor(); - -private: - lastfm::NdisEventsProxy* m_ndisEventsProxy; -}; - -#endif // WNETWORK_CONNECTION_MONITOR_H - diff --git a/thirdparty/liblastfm2/src/ws/win/WNetworkConnectionMonitor_win.cpp b/thirdparty/liblastfm2/src/ws/win/WNetworkConnectionMonitor_win.cpp deleted file mode 100755 index 09fd97cc5..000000000 --- a/thirdparty/liblastfm2/src/ws/win/WNetworkConnectionMonitor_win.cpp +++ /dev/null @@ -1,67 +0,0 @@ -/* - Copyright 2010 Last.fm Ltd. - - Primarily authored by Jono Cole, Michael Coffey, and William Viana - - This file is part of liblastfm. - - liblastfm is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - liblastfm is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with liblastfm. If not, see . -*/ - -#include "WNetworkConnectionMonitor.h" - -// WsAccessManager needs special init (on Windows), and it needs to be done -// early, so be careful about moving this -#include "../win/ComSetup.h" //must be first header or compile fail results! -#include "../win/NdisEvents.h" -static ComSetup com_setup; - -namespace lastfm { - -// bounce NdisEvents signals through here so we don't have to expose the -// NdisEvents interface in InternetConnectionMonitor :) -class NdisEventsProxy : public NdisEvents -{ -public: - NdisEventsProxy(WNetworkConnectionMonitor* icm) - :m_icm(icm) - { - } - - // WmiSink callbacks: - void onConnectionUp( BSTR /*name*/ ) - { - m_icm->setConnected( true ); - } - - void onConnectionDown( BSTR /*name*/ ) - { - m_icm->setConnected( false ); - } - - WNetworkConnectionMonitor* m_icm; -}; - -} - -WNetworkConnectionMonitor::WNetworkConnectionMonitor( QObject* parent ) : - NetworkConnectionMonitor( parent ) -{ - m_ndisEventsProxy = new lastfm::NdisEventsProxy( this ); - m_ndisEventsProxy->registerForNdisEvents(); -} - -WNetworkConnectionMonitor::~WNetworkConnectionMonitor() -{ - delete m_ndisEventsProxy; -} diff --git a/thirdparty/liblastfm2/src/ws/win/WmiSink.cpp b/thirdparty/liblastfm2/src/ws/win/WmiSink.cpp deleted file mode 100644 index 3d564266c..000000000 --- a/thirdparty/liblastfm2/src/ws/win/WmiSink.cpp +++ /dev/null @@ -1,202 +0,0 @@ -/* - Copyright 2009 Last.fm Ltd. - - Primarily authored by Max Howell, Jono Cole and Doug Mansell - - This file is part of liblastfm. - - liblastfm is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - liblastfm is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with liblastfm. If not, see . -*/ -#include "WmiSink.h" -#include "NdisEvents.h" - - -WmiSink::WmiSink(NdisEvents *callback) - : m_cRef(1) - , m_callback(callback) -{} - -WmiSink::~WmiSink() -{} - -void -WmiSink::disconnect() -{ - m_callback = 0; -} - -STDMETHODIMP -WmiSink::QueryInterface(REFIID riid, LPVOID * ppv) -{ - *ppv = 0; - - if (IID_IUnknown==riid || IID_IWbemObjectSink == riid) - { - *ppv = (IWbemObjectSink *) this; - AddRef(); - return NOERROR; - } - - return E_NOINTERFACE; -} - - -ULONG -WmiSink::AddRef() -{ - return ++m_cRef; -} - -ULONG -WmiSink::Release() -{ - if (0 != --m_cRef) - return m_cRef; - - delete this; - return 0; -} - -// This method receives notification objects. -HRESULT -WmiSink::Indicate(long lObjectCount, IWbemClassObject** ppObjArray) -{ - // For each object in the array, extract the object and display the - // information in the object. - for (long i=0; iGet(L"InstanceName", 0, &vt, NULL, NULL); - ppObjArray[i]->Get(L"__Class", 0, &vtClass, NULL, NULL); - - if (!wcscmp (vtClass.bstrVal, L"MSNdis_StatusMediaDisconnect")) - { - if (m_callback) m_callback->onConnectionDown(vt.bstrVal); - } - else if (!wcscmp (vtClass.bstrVal, L"MSNdis_StatusMediaConnect")) - { - if (m_callback) m_callback->onConnectionUp(vt.bstrVal); - } - // notifications we aren't interested in right now: - // - //else if (!wcscmp (vtClass.bstrVal, L"MSNdis_NotifyAdapterRemoval")) - //{ - // bstrLog = (_bstr_t) vt.bstrVal; - // VariantClear (&vt); - // ppObjArray[i]->Get (L"DeviceName", 0, &vt, NULL, NULL); - // bstrLog += (_bstr_t) _T(": ") + (_bstr_t) vt.bstrVal + (_bstr_t) _T(" has been removed"); - // displayDlg.LogEvent (bstrLog); - //} - //else if (!wcscmp (vtClass.bstrVal, L"MSNdis_NotifyAdapterArrival")) - //{ - // bstrLog = (_bstr_t) vt.bstrVal; - // VariantClear (&vt); - // ppObjArray[i]->Get(L"DeviceName", 0, &vt, NULL, NULL); - // bstrLog += (_bstr_t) _T(": ") + (_bstr_t) vt.bstrVal + (_bstr_t) _T(" has been added"); - // displayDlg.LogEvent (bstrLog); - //} - //else if (!wcscmp (vtClass.bstrVal, L"MSNdis_StatusResetStart")) - //{ - // bstrLog = (_bstr_t) vt.bstrVal + (_bstr_t) _T(" has begun a reset"); - // displayDlg.LogEvent (bstrLog); - //} - //else if (!wcscmp (vtClass.bstrVal, L"MSNdis_StatusResetEnd")) - //{ - // bstrLog = (_bstr_t) vt.bstrVal + (_bstr_t) _T(" has finished a reset"); - // displayDlg.LogEvent (bstrLog); - //} - //else if (!wcscmp (vtClass.bstrVal, L"MSNdis_NotifyVcArrival")) - //{ - // bstrLog = (_bstr_t) _T("VC arrival: ") + (_bstr_t) vt.bstrVal; - // displayDlg.LogEvent (bstrLog); - //} - //else if (!wcscmp (vtClass.bstrVal, L"MSNdis_NotifyVcRemoval")) - //{ - // bstrLog = (_bstr_t) _T("VC removal: ") + (_bstr_t) vt.bstrVal; - // displayDlg.LogEvent (bstrLog); - //} - //else if (!wcscmp (vtClass.bstrVal, L"MSNdis_StatusMediaSpecificIndication")) - //{ - // ATLTRACE (_T("Media specific indication: %s\n"), (TCHAR *) (_bstr_t) vt.bstrVal); - // VariantClear (&vt); - // ppObjArray[i]->Get (L"NdisStatusMediaSpecificIndication", 0, &vt, NULL, NULL); - // LONG lLowerBound, lUpperBound, j; - // UCHAR ch; - // SafeArrayGetLBound (V_ARRAY (&vt), 1, &lLowerBound); - // SafeArrayGetUBound (V_ARRAY (&vt), 1, &lUpperBound); - // ATLTRACE (" "); - // for (j = lLowerBound; j<= lUpperBound; j++ ) - // { - // SafeArrayGetElement (V_ARRAY (&vt), &j, &ch); - // ATLTRACE (_T("%4i"), ch); - - // if (((j - lLowerBound) % 8 == 7) && (j <= lUpperBound)) - // ATLTRACE (_T("\n")); - // } - //} - //else if (!wcscmp (vtClass.bstrVal, L"MSNdis_StatusProtocolBind")) - //{ - // bstrLog = (_bstr_t) vt.bstrVal; - // VariantClear (&vt); - // ppObjArray[i]->Get (L"Transport", 0, &vt, NULL, NULL); - // bstrLog += (_bstr_t) _T(" is now bound to ") + (_bstr_t) vt.bstrVal; - // displayDlg.LogEvent (bstrLog); - //} - //else if (!wcscmp (vtClass.bstrVal, L"MSNdis_StatusProtocolBind")) - //{ - // bstrLog = (_bstr_t) vt.bstrVal; - // VariantClear (&vt); - // ppObjArray[i]->Get(L"Transport", 0, &vt, NULL, NULL); - // bstrLog += (_bstr_t) _T(" was unbound from ") + (_bstr_t) vt.bstrVal; - // displayDlg.LogEvent (bstrLog); - //} - //else if (!wcscmp (vtClass.bstrVal, L"MSNdis_StatusLinkSpeedChange")) - //{ - // IWbemClassObject* pWMIObj=NULL; - // bstrLog = (_bstr_t) _T("Link speed change ") + (_bstr_t) vt.bstrVal; - // VariantClear (&vt); - // ppObjArray[i]->Get (L"NdisStatusLinkSpeedChange", 0, &vt, NULL, NULL); - // if SUCCEEDED (vt.punkVal->QueryInterface (IID_IWbemClassObject, (void**)&pWMIObj)) - // { - // TCHAR szNum[50]; - // pWMIObj->Get (L"Inbound", 0, &vt2, NULL, NULL); - // _stprintf (szNum, _T(" Inbound = %u "), vt2.lVal); - // bstrLog += (_bstr_t) szNum; - // VariantClear (&vt2); - // pWMIObj->Get (L"Outbound", 0, &vt2, NULL, NULL); - // _stprintf (szNum, _T(" Outbound = %u "), vt2.lVal); - // bstrLog += (_bstr_t) szNum; - // VariantClear (&vt2); - // pWMIObj->Release (); - // pWMIObj = NULL; - // } - // displayDlg.LogEvent (bstrLog); - //} - - VariantClear (&vtClass); - VariantClear (&vt); - } - return WBEM_NO_ERROR; -} - - -// Misc. status codes sent by sink. -HRESULT -WmiSink::SetStatus(long lFlags, HRESULT hResult, BSTR strParam, IWbemClassObject __RPC_FAR *pObjParam) -{ - lFlags; - hResult; - strParam; - pObjParam; - return WBEM_NO_ERROR; -} diff --git a/thirdparty/liblastfm2/src/ws/win/WmiSink.h b/thirdparty/liblastfm2/src/ws/win/WmiSink.h deleted file mode 100644 index 74319eb6a..000000000 --- a/thirdparty/liblastfm2/src/ws/win/WmiSink.h +++ /dev/null @@ -1,49 +0,0 @@ -/* - Copyright 2009 Last.fm Ltd. - - Primarily authored by Max Howell, Jono Cole and Doug Mansell - - This file is part of liblastfm. - - liblastfm is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - liblastfm is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with liblastfm. If not, see . -*/ -#ifndef WMISINK_WIN_H -#define WMISINK_WIN_H - -#include "wbemcli.h" - -// Sink object for WMI NDIS notifications -class WmiSink : public IWbemObjectSink -{ - UINT m_cRef; - -public: - WmiSink(class NdisEvents *callback); - ~WmiSink(); - - // IUnknown members - STDMETHODIMP QueryInterface(REFIID, LPVOID *); - STDMETHODIMP_(ULONG) AddRef(void); - STDMETHODIMP_(ULONG) Release(void); - - // IWbemObjectSink - STDMETHODIMP Indicate(long, IWbemClassObject**); - STDMETHODIMP SetStatus(long, HRESULT, BSTR, IWbemClassObject *); - - void disconnect(); - -private: - class NdisEvents *m_callback; -}; - -#endif \ No newline at end of file diff --git a/thirdparty/liblastfm2/src/ws/ws.cpp b/thirdparty/liblastfm2/src/ws/ws.cpp deleted file mode 100644 index b2ad56860..000000000 --- a/thirdparty/liblastfm2/src/ws/ws.cpp +++ /dev/null @@ -1,237 +0,0 @@ -/* - Copyright 2009 Last.fm Ltd. - - Primarily authored by Max Howell, Jono Cole and Doug Mansell - - This file is part of liblastfm. - - liblastfm is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - liblastfm is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with liblastfm. If not, see . -*/ -#include "ws.h" -#include "../core/misc.h" -#include "NetworkAccessManager.h" -#include -#include -#include -#include -#include -#include -#include -#include - -static QMap< QThread*, QNetworkAccessManager* > threadNamHash; -static QSet< QThread* > ourNamSet; -static QMutex namAccessMutex; - -QString -lastfm::ws::host() -{ - QStringList const args = QCoreApplication::arguments(); - if (args.contains( "--debug")) - return "ws.staging.audioscrobbler.com"; - - int const n = args.indexOf( "--host" ); - if (n != -1 && args.count() > n+1) - return args[n+1]; - - return LASTFM_WS_HOSTNAME; -} - -static QUrl baseUrl() -{ - QUrl url; - url.setScheme( "http" ); - url.setHost( lastfm::ws::host() ); - url.setEncodedPath( "/2.0/" ); - return url; -} - -static QString iso639() -{ - return QLocale().name().left( 2 ).toLower(); -} - -void autograph( QMap& params ) -{ - params["api_key"] = lastfm::ws::ApiKey; - params["lang"] = iso639(); -} - -static void sign( QMap& params, bool sk = true ) -{ - autograph( params ); - // it's allowed for sk to be null if we this is an auth call for instance - if (sk && lastfm::ws::SessionKey.size()) - params["sk"] = lastfm::ws::SessionKey; - - QString s; - QMapIterator i( params ); - while (i.hasNext()) { - i.next(); - s += i.key() + i.value(); - } - s += lastfm::ws::SharedSecret; - - params["api_sig"] = lastfm::md5( s.toUtf8() ); -} - - -QUrl -lastfm::ws::url( QMap params ) -{ - sign( params ); - QUrl url = ::baseUrl(); - // Qt setQueryItems doesn't encode a bunch of stuff, so we do it manually - QMapIterator i( params ); - while (i.hasNext()) { - i.next(); - QByteArray const key = QUrl::toPercentEncoding( i.key() ); - QByteArray const value = QUrl::toPercentEncoding( i.value() ); - url.addEncodedQueryItem( key, value ); - } - - return url; -} - - -QNetworkReply* -lastfm::ws::get( QMap params ) -{ - return nam()->get( QNetworkRequest( url( params ) ) ); -} - - -QNetworkReply* -lastfm::ws::post( QMap params, bool sk ) -{ - sign( params, sk ); - QByteArray query; - QMapIterator i( params ); - while (i.hasNext()) { - i.next(); - query += QUrl::toPercentEncoding( i.key() ) - + '=' - + QUrl::toPercentEncoding( i.value() ) - + '&'; - } - - QNetworkRequest req( baseUrl() ); - req.setHeader( QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded" ); - return nam()->post( req, query ); -} - - -QNetworkAccessManager* -lastfm::nam() -{ - QMutexLocker l( &namAccessMutex ); - QThread* thread = QThread::currentThread(); - if ( !threadNamHash.contains( thread ) ) - { - NetworkAccessManager* newNam = new NetworkAccessManager(); - threadNamHash[thread] = newNam; - ourNamSet.insert( thread ); - return newNam; - } - return threadNamHash[thread]; -} - - -void -lastfm::setNetworkAccessManager( QNetworkAccessManager* nam ) -{ - if ( !nam ) - return; - - QMutexLocker l( &namAccessMutex ); - QThread* thread = QThread::currentThread(); - QNetworkAccessManager* oldNam = 0; - if ( threadNamHash.contains( thread ) && ourNamSet.contains( thread ) ) - oldNam = threadNamHash[thread]; - - if ( oldNam == nam ) - { - // If we're being passed back our own NAM, assume they want to - // ensure that we don't delete it out from under them - ourNamSet.remove( thread ); - return; - } - - threadNamHash[thread] = nam; - ourNamSet.remove( thread ); - - if ( oldNam ) - delete oldNam; -} - - -/** This useful function, fromHttpDate, comes from QNetworkHeadersPrivate - * in qnetworkrequest.cpp. Qt copyright and license apply. */ -static QDateTime QByteArrayToHttpDate(const QByteArray &value) -{ - // HTTP dates have three possible formats: - // RFC 1123/822 - ddd, dd MMM yyyy hh:mm:ss "GMT" - // RFC 850 - dddd, dd-MMM-yy hh:mm:ss "GMT" - // ANSI C's asctime - ddd MMM d hh:mm:ss yyyy - // We only handle them exactly. If they deviate, we bail out. - - int pos = value.indexOf(','); - QDateTime dt; - if (pos == -1) { - // no comma -> asctime(3) format - dt = QDateTime::fromString(QString::fromLatin1(value), Qt::TextDate); - } else { - // eat the weekday, the comma and the space following it - QString sansWeekday = QString::fromLatin1(value.constData() + pos + 2); - - QLocale c = QLocale::c(); - if (pos == 3) - // must be RFC 1123 date - dt = c.toDateTime(sansWeekday, QLatin1String("dd MMM yyyy hh:mm:ss 'GMT")); - else - // must be RFC 850 date - dt = c.toDateTime(sansWeekday, QLatin1String("dd-MMM-yy hh:mm:ss 'GMT'")); - } - - if (dt.isValid()) - dt.setTimeSpec(Qt::UTC); - return dt; -} - - -QDateTime -lastfm::ws::expires( QNetworkReply* reply ) -{ - return QByteArrayToHttpDate( reply->rawHeader( "Expires" ) ); -} - - -namespace lastfm -{ - namespace ws - { - QString SessionKey; - QString Username; - - /** we leave these unset as you can't use the webservices without them - * so lets make the programmer aware of it during testing by crashing */ - const char* SharedSecret; - const char* ApiKey; - - /** if this is found set to "" we conjure ourselves a suitable one */ - const char* UserAgent = 0; - } -} - - -QDebug operator<<( QDebug, lastfm::ws::Error ); diff --git a/thirdparty/liblastfm2/src/ws/ws.h b/thirdparty/liblastfm2/src/ws/ws.h deleted file mode 100644 index b9bb90e0c..000000000 --- a/thirdparty/liblastfm2/src/ws/ws.h +++ /dev/null @@ -1,149 +0,0 @@ -/* - Copyright 2009 Last.fm Ltd. - - Primarily authored by Max Howell, Jono Cole and Doug Mansell - - This file is part of liblastfm. - - liblastfm is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - liblastfm is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with liblastfm. If not, see . -*/ -#ifndef LASTFM_WS_H -#define LASTFM_WS_H - -#include -#include -#include -#include -#include - -#ifdef Q_CC_MSVC -// ms admits its lousy compiler doesn't care about throw declarations -#pragma warning( disable : 4290 ) -#endif - - -namespace lastfm -{ - /** if you don't set one, we create our own, our own is pretty good - * for instance, it auto detects proxy settings on windows and mac - * We take ownership of the NAM, do not delete it out from underneath us! - * So don't keep any other pointers to this around in case you accidently - * call delete on them :P */ - LASTFM_DLLEXPORT void setNetworkAccessManager( QNetworkAccessManager* nam ); - LASTFM_DLLEXPORT QNetworkAccessManager* nam(); - - namespace ws - { - /** both of these are provided when you register at http://last.fm/api */ - LASTFM_DLLEXPORT extern const char* SharedSecret; - LASTFM_DLLEXPORT extern const char* ApiKey; - - /** you need to set this for scrobbling to work (for now) - * Also the AuthenticatedUser class uses it */ - LASTFM_DLLEXPORT extern QString Username; - - /** Some webservices require authentication. See the following - * documentation: - * http://www.last.fm/api/authentication - * http://www.last.fm/api/desktopauth - * You have to authenticate and then assign to SessionKey, liblastfm does - * not do that for you. Also we do not store this. You should store this! - * You only need to authenticate once, and that key lasts forever! - */ - LASTFM_DLLEXPORT extern QString SessionKey; - - enum Error - { - NoError = 1, // because last.fm error numbers start at 2 - - /** numbers follow those at http://last.fm/api/ */ - InvalidService = 2, - InvalidMethod, - AuthenticationFailed, - InvalidFormat, - InvalidParameters, - InvalidResourceSpecified, - OperationFailed, - InvalidSessionKey, - InvalidApiKey, - ServiceOffline, - SubscribersOnly, - - Reserved13, - Reserved14, - Reserved15, - - /** Last.fm sucks. - * There may be an error in networkError(), or this may just be some - * internal error completing your request. - * Advise the user to try again in a _few_minutes_. - * For some cases, you may want to try again yourself, at this point - * in the API you will have to. Eventually we will discourage this and - * do it for you, as we don't want to strain Last.fm's servers - */ - TryAgainLater = 16, - - Reserved17, - Reserved18, - Reserved19, - - NotEnoughContent = 20, - NotEnoughMembers, - NotEnoughFans, - NotEnoughNeighbours, - - /** Last.fm fucked up, or something mangled the response on its way */ - MalformedResponse = 100, - - /** call QNetworkReply::error() as it's nothing to do with us */ - UnknownError - }; - - LASTFM_DLLEXPORT QString host(); - - /** the map needs a method entry, as per http://last.fm/api */ - LASTFM_DLLEXPORT QUrl url( QMap ); - LASTFM_DLLEXPORT QNetworkReply* get( QMap ); - /** generates api sig, includes api key, and posts, don't add the api - * key yourself as well--it'll break */ - LASTFM_DLLEXPORT QNetworkReply* post( QMap, bool sessionKey = true ); - - - class ParseError : public std::runtime_error - { - Error e; - QString m_message; - public: - explicit ParseError( Error e, QString message ) - :std::runtime_error("lastfm::ws::Error"), e(e), m_message(message) - {} - Error enumValue() const { return e; } - QString message() const { return m_message; } - - ~ParseError() throw() {;} - }; - - /** returns the expiry date of this HTTP response */ - LASTFM_DLLEXPORT QDateTime expires( QNetworkReply* ); - } -} - - -inline QDebug operator<<( QDebug d, QNetworkReply::NetworkError e ) -{ - return d << lastfm::qMetaEnumString( e, "NetworkError" ); -} - -#define LASTFM_WS_HOSTNAME "ws.audioscrobbler.com" - -#endif diff --git a/thirdparty/liblastfm2/tests/TestTrack.h b/thirdparty/liblastfm2/tests/TestTrack.h deleted file mode 100644 index c771a45e9..000000000 --- a/thirdparty/liblastfm2/tests/TestTrack.h +++ /dev/null @@ -1,35 +0,0 @@ -/* - This software is in the public domain, furnished "as is", without technical - support, and with no warranty, express or implied, as to its usefulness for - any purpose. -*/ -#include -#include -using lastfm::Track; - -class TestTrack : public QObject -{ - Q_OBJECT - - Track example() - { - lastfm::MutableTrack t; - t.setTitle( "Test Title" ); - t.setArtist( "Test Artist" ); - t.setAlbum( "Test Album" ); - return t; - } - -private slots: - void testClone() - { - Track original = example(); - Track copy = original; - - #define TEST( x ) QVERIFY( original.x == copy.x ) - TEST( title() ); - TEST( artist() ); - TEST( album() ); - #undef TEST - } -}; diff --git a/thirdparty/liblastfm2/tests/TestUrlBuilder.h b/thirdparty/liblastfm2/tests/TestUrlBuilder.h deleted file mode 100644 index 909d10e37..000000000 --- a/thirdparty/liblastfm2/tests/TestUrlBuilder.h +++ /dev/null @@ -1,80 +0,0 @@ -/* - This software is in the public domain, furnished "as is", without technical - support, and with no warranty, express or implied, as to its usefulness for - any purpose. -*/ -#include -#include -#include -#include -#include - -static inline int getResponseCode( const QUrl& url ) -{ - QNetworkAccessManager nam; - QNetworkReply* reply = nam.head( QNetworkRequest(url) ); - - QEventLoop loop; - loop.connect( reply, SIGNAL(finished()), SLOT(quit()) ); - loop.exec(); - - int const code = reply->attribute( QNetworkRequest::HttpStatusCodeAttribute ).toInt(); - - if (reply->error() != QNetworkReply::NoError) - qDebug() << url << lastfm::qMetaEnumString( reply->error(), "NetworkError" ) << code; - - return code; -} - - -class TestUrlBuilder : public QObject -{ - Q_OBJECT - -private slots: - void encode() /** @author */ - { - QFETCH( QString, input ); - QFETCH( QString, output ); - QCOMPARE( lastfm::UrlBuilder::encode( input ), output.toAscii() ); - } - - void encode_data() /** @author */ - { - QTest::addColumn("input"); - QTest::addColumn("output"); - - QTest::newRow( "ascii" ) << "Metallica" << "Metallica"; - QTest::newRow( "ascii alphanumeric" ) << "Apollo 440" << "Apollo+440"; - QTest::newRow( "ascii with symbols" ) << "some track [original version]" << "some+track+%5Boriginal+version%5D"; - QTest::newRow( "ascii with last.fm-special symbols" ) << "Survivalism [Revision #1]" << "Survivalism%2B%255BRevision%2B%25231%255D"; - } - - void no404() /** @author */ - { - QFETCH( QString, artist ); - QFETCH( QString, track ); - - QUrl url = lastfm::UrlBuilder( "music" ).slash( artist ).slash( "_" ).slash( track ).url(); - - QCOMPARE( getResponseCode( url ), 200 ); - } - - void no404_data() /** @author */ - { - QTest::addColumn("artist"); - QTest::addColumn("track"); - - #define NEW_ROW( x, y ) QTest::newRow( x " - " y ) << x << y; - NEW_ROW( "Air", "Radio #1" ); - NEW_ROW( "Pink Floyd", "Speak to Me / Breathe" ); - NEW_ROW( "Radiohead", "2 + 2 = 5" ); - NEW_ROW( "Above & Beyond", "World On Fire (Maor Levi Remix)" ); - #undef NEW_ROW - } - - void test404() /** @author */ - { - QCOMPARE( getResponseCode( QUrl("http://www.last.fm/404") ), 404 ); - } -}; diff --git a/thirdparty/liblastfm2/tests/main.cpp b/thirdparty/liblastfm2/tests/main.cpp deleted file mode 100644 index 5995bffa2..000000000 --- a/thirdparty/liblastfm2/tests/main.cpp +++ /dev/null @@ -1,22 +0,0 @@ -/* - This software is in the public domain, furnished "as is", without technical - support, and with no warranty, express or implied, as to its usefulness for - any purpose. -*/ -#include -#include -#include "TestTrack.h" -#include "TestUrlBuilder.h" - -int main( int argc, char** argv) -{ - QCoreApplication app( argc, argv ); - - #define TEST( Type ) { \ - Type o; \ - if (int r = QTest::qExec( &o, argc, argv ) != 0) return r; } - - TEST( TestTrack ); - TEST( TestUrlBuilder ); - return 0; -} diff --git a/thirdparty/liblastfm2/tests/tests.pro b/thirdparty/liblastfm2/tests/tests.pro deleted file mode 100644 index da65f1cde..000000000 --- a/thirdparty/liblastfm2/tests/tests.pro +++ /dev/null @@ -1,4 +0,0 @@ -QT = core testlib network xml -LIBS += -llastfm -L$$DESTDIR -SOURCES = main.cpp -HEADERS = TestTrack.h TestUrlBuilder.h \ No newline at end of file