diff -Nru liblastfm-0.4.0~really0.3.3/admin/findsrc.rb liblastfm-1.0.1/admin/findsrc.rb --- liblastfm-0.4.0~really0.3.3/admin/findsrc.rb 2010-09-25 17:30:01.000000000 +0000 +++ liblastfm-1.0.1/admin/findsrc.rb 1970-01-01 00:00:00.000000000 +0000 @@ -1,33 +0,0 @@ -#!/usr/bin/ruby -require 'find' -require "#{File.dirname __FILE__}/platform" - -def findsrc dir='.' - excludes = ['.svn','.git','_include','tests','_build'] - case Platform::IMPL - when :macosx then excludes<<'win' - when :mswin, :cygwin then excludes<<'mac' - else excludes<<'win'<<'mac' - end - - Find.find dir do |path| - next if path == dir # oddly neccessary - path.sub! %r[^\./], '' - if File.directory? path - Find.prune if excludes.include? File.basename(path) - #don't recurse into dirs with pro files in - Find.prune if Dir["#{path}/*.pro"].length > 0 and $findsrc_prune_pro - elsif File.file? path - case Platform::IMPL - when :macosx then next if /_mac\.cpp$/.match path - when :mswin, :cygwin then next if /_win\.cpp$/.match path - end - yield( path, File.extname( path ) ) unless File.basename(path) == 'EXAMPLE.cpp' - end - end -end - -if $0 == __FILE__ - extnames=ARGV.collect {|extname| ".#{extname}"} - findsrc {|path,extname| puts path if extnames.include? extname} -end \ No newline at end of file diff -Nru liblastfm-0.4.0~really0.3.3/admin/lastfm.h.rb liblastfm-1.0.1/admin/lastfm.h.rb --- liblastfm-0.4.0~really0.3.3/admin/lastfm.h.rb 2010-09-25 17:30:01.000000000 +0000 +++ liblastfm-1.0.1/admin/lastfm.h.rb 1970-01-01 00:00:00.000000000 +0000 @@ -1,5 +0,0 @@ -#!/usr/bin/ruby -f = File.new(ARGV[0], "w") -Dir["_include/lastfm/*"].each do |h| - f.write %Q{#include "lastfm/#{File.basename h}"\n} -end \ No newline at end of file diff -Nru liblastfm-0.4.0~really0.3.3/admin/Makefile.rb liblastfm-1.0.1/admin/Makefile.rb --- liblastfm-0.4.0~really0.3.3/admin/Makefile.rb 2010-09-25 17:30:01.000000000 +0000 +++ liblastfm-1.0.1/admin/Makefile.rb 1970-01-01 00:00:00.000000000 +0000 @@ -1,161 +0,0 @@ -#!/usr/bin/ruby -# tool to look through a qmake pro file and find what headers are to be -# installed it then figures out the classes in each of those files -# and then creates the directory _include and creates files named after the -# class names in there which #include the file that contains the class - -cwd = File.dirname( __FILE__ ) -require 'find' -require "#{cwd}/platform.rb" - - -######################################################################### defs -case Platform::IMPL - when :mswin - ruby='ruby -rfileutils -e' - CP="#{ruby} 'FileUtils.copy_file ARGV[0], ARGV[1]' --" - LN=CP - RM=ruby+' "FileUtils.rm ARGV[0], :force => true" --' - RM_RF="#{ruby} 'FileUtils.rm_rf ARGV[0]' --" - MKDIR="#{ruby} 'FileUtils.mkpath ARGV[0]' --" - ORDERONLY='' - else - CP='cp' - LN=CP #'ln -sf' oddly doesn't work, the target is always remade - RM='rm -f' - RM_RF='rm -rf' - MKDIR='mkdir -p' - ORDERONLY='|' -end - -def penis( path ) - yielded = false - File.open( path ).each_line do |line| - matches = /(class|struct)\s*LASTFM_DLLEXPORT\s*([a-zA-Z0-9]+)/.match( line ) - unless matches.nil? - yield path, matches[2] - yielded = true - end - end - # just copy it without adjustment if there were no exported classes - # HACK we yield ws.h twice due to ParseError - yield path, File.basename( path ) if path =~ /ws.h$/ or not yielded -end - - -######################################################################### main -INSTALL_PREFIX=ENV['LFM_PREFIX'] -abort("Environment variable LFM_PREFIX not defined") if INSTALL_PREFIX.nil? -$install_headers='' -$headers='' - -puts <<-EOS -.PHONY: all -all: headers __src __fingerprint __demos __tests - -.PHONY: __src -__src: src/Makefile - cd src && $(MAKE) -.PHONY: __fingerprint -__fingerprint: src/fingerprint/Makefile __src - cd src/fingerprint && $(MAKE) -.PHONY: __tests -__tests: tests/Makefile __src - cd tests && $(MAKE) -.PHONY: __demos -__demos: demos/Makefile __src - cd demos && $(MAKE) - -src/Makefile: - cd src && #{ENV['LFM_QMAKE']} -src/fingerprint/Makefile: - cd src/fingerprint && #{ENV['LFM_QMAKE']} -tests/Makefile: - cd tests && #{ENV['LFM_QMAKE']} -demos/Makefile: - cd demos && #{ENV['LFM_QMAKE']} - -.PHONY: clean -clean: - #{RM_RF} _include - #{RM_RF} src/_build - #{RM_RF} src/fingerprint/_build - #{RM_RF} demos/_build - #{RM_RF} tests/_build - #{RM} src/Makefile - #{RM} src/fingerprint/Makefile - #{RM} tests/Makefile - #{RM} demos/Makefile - #{RM_RF} _bin - -.PHONY: distclean -distclean: clean - #{RM} .qmake.env - #{RM} src/_files.qmake - #{RM} src/_version.h - #{RM} src/fingerprint/_files.qmake - #{RM} src/fingerprint/_version.h - #{RM} Makefile - -EOS - -begin - lhd='_include/lastfm' - ihd="$(DESTDIR)#{INSTALL_PREFIX}/include/lastfm" - ARGV.each do |header| - penis "src/#{header}" do |path, classname| - puts "#{lhd}/#{classname}: #{path} #{ORDERONLY} #{lhd}" - puts " #{LN} #{path} $@" - puts "#{ihd}/#{classname}: #{path} #{ORDERONLY} #{ihd}" - puts " #{CP} #{path} $@" - puts - $headers+=" #{lhd}/#{classname}" - $install_headers+=" #{ihd}/#{classname}" - end - end -end - -puts <<-EOS -_include/lastfm: - #{MKDIR} $@ -$(DESTDIR)#{INSTALL_PREFIX}/include/lastfm: - #{MKDIR} $@ - -_include/lastfm.h: #{$headers} #{ORDERONLY} _include/lastfm - ruby admin/lastfm.h.rb $@ -$(DESTDIR)#{INSTALL_PREFIX}/include/lastfm.h: _include/lastfm.h #{ORDERONLY} $(DESTDIR)#{INSTALL_PREFIX}/include/lastfm - #{CP} _include/lastfm.h $@ - -.PHONY: headers -headers: #{$headers} _include/lastfm.h - -.PHONY: install -install: #{$install_headers} $(DESTDIR)#{INSTALL_PREFIX}/include/lastfm.h -EOS - -if Platform::IMPL == :macosx - # qmake doesn't do the install_name_tool steps, so we have to do everything - dst="$(DESTDIR)#{INSTALL_PREFIX}/lib" - v=ENV['LFM_VERSION'] - vmajor=v[0..0] - puts " mkdir -p #{dst}" - ['liblastfm', 'liblastfm_fingerprint'].each do |base| - puts " cp _bin/#{base}.#{v}.dylib '#{dst}'" - puts " cd '#{dst}' && ln -s #{base}.#{v}.dylib #{base}.dylib" - puts " cd '#{dst}' && ln -s #{base}.#{v}.dylib #{base}.#{vmajor}.dylib" - puts " install_name_tool -id '#{dst}/#{base}.#{vmajor}.dylib' '#{dst}/#{base}.#{vmajor}.dylib'" - end - ext="#{vmajor}.dylib" - puts " install_name_tool -change liblastfm.#{ext} #{dst}/liblastfm.#{ext} #{dst}/liblastfm_fingerprint.#{ext}" -else - puts %Q[ cd src && $(MAKE) install "INSTALL_ROOT=$(DESTDIR)#{INSTALL_PREFIX}"] - puts %Q[ cd src/fingerprint && $(MAKE) install "INSTALL_ROOT=$(DESTDIR)#{INSTALL_PREFIX}"] -end - -BASENAME='liblastfm-'+ENV['LFM_VERSION'] -puts <<-EOS - -.PHONY: dist -dist: - git archive --prefix=#{BASENAME}/ HEAD | bzip2 > #{BASENAME}.tar.bz2 -EOS \ No newline at end of file diff -Nru liblastfm-0.4.0~really0.3.3/admin/platform.rb liblastfm-1.0.1/admin/platform.rb --- liblastfm-0.4.0~really0.3.3/admin/platform.rb 2010-09-25 17:30:01.000000000 +0000 +++ liblastfm-1.0.1/admin/platform.rb 1970-01-01 00:00:00.000000000 +0000 @@ -1,101 +0,0 @@ -# -# platform.rb: naive platform detection for Ruby -# author: Matt Mower -# - -# == Platform -# -# Platform is a simple module which parses the Ruby constant -# RUBY_PLATFORM and works out the OS, it's implementation, -# and the architecture it's running on. -# -# The motivation for writing this was coming across a case where -# -# +if RUBY_PLATFORM =~ /win/+ -# -# didn't behave as expected (i.e. on powerpc-darwin-8.1.0) -# -# It is hoped that providing a library for parsing the platform -# means that we can cover all the cases and have something which -# works reliably 99% of the time. -# -# Please report any anomalies or new combinations to the author(s). -# -# == Use -# -# require "platform" -# -# defines -# -# Platform::OS (:unix,:win32,:vms,:os2) -# Platform::IMPL (:macosx,:linux,:mswin) -# Platform::ARCH (:powerpc,:x86,:alpha) -# -# if an unknown configuration is encountered any (or all) of -# these constant may have the value :unknown. -# -# To display the combination for your setup run -# -# ruby platform.rb -# -module Platform - - if RUBY_PLATFORM =~ /darwin/i - OS = :unix - IMPL = :macosx - elsif RUBY_PLATFORM =~ /linux/i - OS = :unix - IMPL = :linux - elsif RUBY_PLATFORM =~ /freebsd/i - OS = :unix - IMPL = :freebsd - elsif RUBY_PLATFORM =~ /netbsd/i - OS = :unix - IMPL = :netbsd - elsif RUBY_PLATFORM =~ /mswin/i - OS = :win32 - IMPL = :mswin - elsif RUBY_PLATFORM =~ /cygwin/i - OS = :unix - IMPL = :cygwin - elsif RUBY_PLATFORM =~ /mingw/i - OS = :win32 - IMPL = :mingw - elsif RUBY_PLATFORM =~ /bccwin/i - OS = :win32 - IMPL = :bccwin - elsif RUBY_PLATFORM =~ /wince/i - OS = :win32 - IMPL = :wince - elsif RUBY_PLATFORM =~ /vms/i - OS = :vms - IMPL = :vms - elsif RUBY_PLATFORM =~ /os2/i - OS = :os2 - IMPL = :os2 # maybe there is some better choice here? - else - OS = :unknown - IMPL = :unknown - end - - # whither AIX, SOLARIS, and the other unixen? - - if RUBY_PLATFORM =~ /(i\d86)/i - ARCH = :x86 - elsif RUBY_PLATFORM =~ /ia64/i - ARCH = :ia64 - elsif RUBY_PLATFORM =~ /powerpc/i - ARCH = :powerpc - elsif RUBY_PLATFORM =~ /alpha/i - ARCH = :alpha - else - ARCH = :unknown - end - - # What about AMD, Turion, Motorola, etc..? - -end - -if __FILE__ == $0 - puts "Platform OS=#{Platform::OS}, IMPL=#{Platform::IMPL}, ARCH=#{Platform::ARCH}" -end diff -Nru liblastfm-0.4.0~really0.3.3/admin/qpp liblastfm-1.0.1/admin/qpp --- liblastfm-0.4.0~really0.3.3/admin/qpp 2010-09-25 17:30:01.000000000 +0000 +++ liblastfm-1.0.1/admin/qpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,42 +0,0 @@ -#!/usr/bin/ruby -# Creates a qmake .pro file for all valid SOURCES, HEADERS, FORMS and -# RESOURCES under each argument to ARGV as directories - -cwd=File.dirname __FILE__ -require 'find' -require "#{cwd}/findsrc" - -sources = Array.new -headers = Array.new -forms = Array.new -resources = Array.new - -$findsrc_prune_pro=true - -ARGV.each do |d| - Dir.chdir d do - findsrc do |path,ext| - case ext - when ".h" then headers << path - when ".ui" then forms << path - when ".qrc" then resources << path - when ".cpp" then sources << path - end - end - end -end - -def puts_section section, files - return if files.empty? - print section + " =" - files.each do |filename| - print " \\\n\t" - print filename - end - puts -end - -puts_section "SOURCES", sources -puts_section "HEADERS", headers -puts_section "FORMS", forms -puts_section "RESOURCES", resources diff -Nru liblastfm-0.4.0~really0.3.3/admin/utils.rb liblastfm-1.0.1/admin/utils.rb --- liblastfm-0.4.0~really0.3.3/admin/utils.rb 2010-09-25 17:30:01.000000000 +0000 +++ liblastfm-1.0.1/admin/utils.rb 1970-01-01 00:00:00.000000000 +0000 @@ -1,40 +0,0 @@ -cwd = File.dirname( __FILE__ ) -require "#{cwd}/platform.rb" - -def h(s, n) - case Platform::IMPL - when :mswin - puts '==> '+s - else - puts "\033[0;#{n}m==>\033[0;0;1m #{s} \033[0;0m" - end -end - -def h1 s - h(s, 34) -end - -def h2 s - h(s, 33) - yield -end - -def qmake_env(env, qenv) - env=Array.new(1,env) if env.instance_of? String - values=Array.new - env.each { |x| values << ENV[x] if ENV[x] } - if values.size > 0 - "#{qenv} = #{values.join(' ')}\n" - else - nil - end -end - -class PkgConfigNotFound < RuntimeError; end -class PkgNotFound < RuntimeError; end - -def pkgconfig pkg, prettyname - system "pkg-config --exists '#{pkg}'" - raise PkgConfigNotFound if $? == 127 - raise PkgNotFound.new(prettyname) if $? != 0 -end \ No newline at end of file diff -Nru liblastfm-0.4.0~really0.3.3/admin/which_qmake.rb liblastfm-1.0.1/admin/which_qmake.rb --- liblastfm-0.4.0~really0.3.3/admin/which_qmake.rb 2010-09-25 17:30:01.000000000 +0000 +++ liblastfm-1.0.1/admin/which_qmake.rb 1970-01-01 00:00:00.000000000 +0000 @@ -1,38 +0,0 @@ -require "#{File.dirname __FILE__}/platform.rb" - -class QMakeNotFound < RuntimeError; end -class QMakeTooOld < RuntimeError; end - -def which_qmake - args = '-v' - args += ' 2> /dev/null' unless Platform::IMPL == :mswin - - versions = Hash.new - ['qmake','qmake-qt4'].each do |qmake| - begin - /^Using Qt version (\d\.\d\.\d)(-(.+))?/.match( `#{qmake} #{args}` ) - rescue - end - versions[qmake] = $1 unless $1.nil? - end - - raise QMakeNotFound if versions.empty? - - versions.each do |key, v| - i = 1 - j = 0 - v.split( '.' ).reverse.each {|n| j += (n.to_i * i); i *= 100} - versions[key] = j - end - - versions.sort {|a,b| a[1]<=>b[1]} - - versions.each do |k, v| - if v >= 40400 - return k - end - raise QMakeTooOld - end -end - -puts which_qmake if __FILE__ == $0 \ No newline at end of file diff -Nru liblastfm-0.4.0~really0.3.3/cmake/Modules/FindDBus.cmake liblastfm-1.0.1/cmake/Modules/FindDBus.cmake --- liblastfm-0.4.0~really0.3.3/cmake/Modules/FindDBus.cmake 1970-01-01 00:00:00.000000000 +0000 +++ liblastfm-1.0.1/cmake/Modules/FindDBus.cmake 2012-06-18 10:37:51.000000000 +0000 @@ -0,0 +1,72 @@ +# - Try to find the low-level D-Bus library +# Once done this will define +# +# DBUS_FOUND - system has D-Bus +# DBUS_INCLUDE_DIR - the D-Bus include directory +# DBUS_ARCH_INCLUDE_DIR - the D-Bus architecture-specific include directory +# DBUS_LIBRARIES - the libraries needed to use D-Bus + +# Copyright (c) 2008, Kevin Kofler, +# modeled after FindLibArt.cmake: +# Copyright (c) 2006, Alexander Neundorf, +# +# Redistribution and use is allowed according to the terms of the BSD license. +# For details see the accompanying COPYING-CMAKE-SCRIPTS file. + +if (DBUS_INCLUDE_DIR AND DBUS_ARCH_INCLUDE_DIR AND DBUS_LIBRARIES) + + # in cache already + SET(DBUS_FOUND TRUE) + +else (DBUS_INCLUDE_DIR AND DBUS_ARCH_INCLUDE_DIR AND DBUS_LIBRARIES) + + IF (NOT WIN32) + FIND_PACKAGE(PkgConfig) + IF (PKG_CONFIG_FOUND) + # use pkg-config to get the directories and then use these values + # in the FIND_PATH() and FIND_LIBRARY() calls + pkg_check_modules(_DBUS_PC QUIET dbus-1) + ENDIF (PKG_CONFIG_FOUND) + ENDIF (NOT WIN32) + + FIND_PATH(DBUS_INCLUDE_DIR dbus/dbus.h + ${_DBUS_PC_INCLUDE_DIRS} + /usr/include + /usr/include/dbus-1.0 + /usr/local/include + ) + + FIND_PATH(DBUS_ARCH_INCLUDE_DIR dbus/dbus-arch-deps.h + ${_DBUS_PC_INCLUDE_DIRS} + /usr/lib${LIB_SUFFIX}/include + /usr/lib${LIB_SUFFIX}/dbus-1.0/include + /usr/lib64/include + /usr/lib64/dbus-1.0/include + /usr/lib/include + /usr/lib/dbus-1.0/include + ) + + FIND_LIBRARY(DBUS_LIBRARIES NAMES dbus-1 dbus + PATHS + ${_DBUS_PC_LIBDIR} + ) + + + if (DBUS_INCLUDE_DIR AND DBUS_ARCH_INCLUDE_DIR AND DBUS_LIBRARIES) + set(DBUS_FOUND TRUE) + endif (DBUS_INCLUDE_DIR AND DBUS_ARCH_INCLUDE_DIR AND DBUS_LIBRARIES) + + + if (DBUS_FOUND) + if (NOT DBus_FIND_QUIETLY) + message(STATUS "Found D-Bus: ${DBUS_LIBRARIES}") + endif (NOT DBus_FIND_QUIETLY) + else (DBUS_FOUND) + if (DBus_FIND_REQUIRED) + message(FATAL_ERROR "Could NOT find D-Bus") + endif (DBus_FIND_REQUIRED) + endif (DBUS_FOUND) + + MARK_AS_ADVANCED(DBUS_INCLUDE_DIR DBUS_ARCH_INCLUDE_DIR DBUS_LIBRARIES) + +endif (DBUS_INCLUDE_DIR AND DBUS_ARCH_INCLUDE_DIR AND DBUS_LIBRARIES) diff -Nru liblastfm-0.4.0~really0.3.3/cmake/Modules/FindLibFFTW3.cmake liblastfm-1.0.1/cmake/Modules/FindLibFFTW3.cmake --- liblastfm-0.4.0~really0.3.3/cmake/Modules/FindLibFFTW3.cmake 1970-01-01 00:00:00.000000000 +0000 +++ liblastfm-1.0.1/cmake/Modules/FindLibFFTW3.cmake 2012-06-18 10:37:51.000000000 +0000 @@ -0,0 +1,51 @@ +# 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 + +find_package(PkgConfig) +pkg_check_modules(PC_FFTW3F QUIET fftw) +set(FFTW3F_DEFINITIONS ${PC_FFTW3F_CFLAGS_OTHER}) + +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 + HINTS ${PC_FFTW3F_INCLUDEDIR} ${PC_FFTW3F_INCLUDE_DIRS}) + +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 + HINTS ${PC_FFTW3F_LIBDIR} ${PC_FFTW3F_LIBRARY_DIRS}) + +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 -Nru liblastfm-0.4.0~really0.3.3/cmake/Modules/FindLibSamplerate.cmake liblastfm-1.0.1/cmake/Modules/FindLibSamplerate.cmake --- liblastfm-0.4.0~really0.3.3/cmake/Modules/FindLibSamplerate.cmake 1970-01-01 00:00:00.000000000 +0000 +++ liblastfm-1.0.1/cmake/Modules/FindLibSamplerate.cmake 2012-06-18 10:37:51.000000000 +0000 @@ -0,0 +1,27 @@ +# 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_package(PkgConfig) +pkg_check_modules(PC_LIBSAMPLERATE QUIET libsamplerate) +set(LIBSAMPLERATE_DEFINITIONS ${PC_LIBSAMPLERATE_CFLAGS_OTHER}) + +find_library(LIBSAMPLERATE_LIBRARY NAMES samplerate libsamplerate-0 samplerate-0 + HINTS ${PC_LIBSAMPLERATE_LIBDIR} ${PC_LIBSAMPLERATE_LIBRARY_DIRS}) + +find_path(LIBSAMPLERATE_INCLUDE_DIR samplerate.h + HINTS ${PC_LIBSAMPLERATE_INCLUDEDIR} ${PC_LIBSAMPLERATE_INCLUDE_DIRS}) + +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 -Nru liblastfm-0.4.0~really0.3.3/CMakeLists.txt liblastfm-1.0.1/CMakeLists.txt --- liblastfm-0.4.0~really0.3.3/CMakeLists.txt 1970-01-01 00:00:00.000000000 +0000 +++ liblastfm-1.0.1/CMakeLists.txt 2012-06-18 10:37:51.000000000 +0000 @@ -0,0 +1,54 @@ +cmake_minimum_required(VERSION 2.8.6) +project(liblastfm) + +set(CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake/modules) + +# general settings +set(LASTFM_VERSION 1.0.1) +set(LASTFM_SOVERSION 1) + +# options +option(BUILD_FINGERPRINT "Build the lastfm-fingerprint library" OFF) +option(BUILD_DEMOS "Build the lastfm example programs" OFF) +option(BUILD_TESTS "Build liblastfm tests" ON) + + +# installation dirs +include(GNUInstallDirs) + +#cmake module path +set(CMAKE_MODULE_PATH "${CMAKE_MODULE_PATH}" "${PROJECT_SOURCE_DIR}/cmake/Modules") + +# setup qt stuff +find_package(Qt4 COMPONENTS QtCore QtNetwork QtXml REQUIRED) +set(CMAKE_AUTOMOC TRUE) + +if(CMAKE_COMPILER_IS_GNUCXX) + add_definitions("-fno-operator-names -fvisibility-inlines-hidden -fvisibility=hidden") +endif() +if(UNIX AND NOT APPLE) +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wl,--no-undefined") +endif() + +if(MSVC) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /Zc:wchar_t-") +endif(MSVC) + +# main library +add_subdirectory(src) + +# lastfm_fingerprint library +if(BUILD_FINGERPRINT) + add_subdirectory(src/fingerprint) +endif() + +# demos +if(BUILD_DEMOS) + add_subdirectory(demos) +endif() + +# tests +if(BUILD_TESTS) + enable_testing() + add_subdirectory(tests) +endif() diff -Nru liblastfm-0.4.0~really0.3.3/configure liblastfm-1.0.1/configure --- liblastfm-0.4.0~really0.3.3/configure 2010-09-25 17:30:01.000000000 +0000 +++ liblastfm-1.0.1/configure 1970-01-01 00:00:00.000000000 +0000 @@ -1,126 +0,0 @@ -#!/usr/bin/ruby -if ARGV.include? '--help' - puts "usage: ./configure [--prefix ] [--release] [--no-strip] [--skip-checks]" - exit -end - -cwd = File.dirname( __FILE__ ) -require "#{cwd}/admin/platform.rb" -require "#{cwd}/admin/which_qmake.rb" -require "#{cwd}/admin/utils.rb" - -begin - IO.read("#{cwd}/src/global.h") =~ /LASTFM_VERSION_STRING\s+"((\d\.)*\d)"/ - abort "Couldn't determine our version!" if $1.nil? - LFM_VERSION=$1 - ENV['LFM_VERSION']=LFM_VERSION - - h1 "Configuring liblastfm-#{LFM_VERSION}..." - - unless ARGV.include? '--skip-checks' - $qmake=which_qmake - pkgconfig 'samplerate', 'libsamplerate' - pkgconfig 'fftw3f', 'fftw' - puts 'Using '+`which #{$qmake}` unless Platform::IMPL == :mswin - else - $qmake='qmake' - end - - h2 'Determining installation prefix' do - if ARGV.include? '--prefix' - n=ARGV.index '--prefix' - ENV['LFM_PREFIX'] = ARGV[n+1] - end - ENV['LFM_PREFIX'] = '/usr/local' if ENV['LFM_PREFIX'].nil? - if File.exists? ENV['LFM_PREFIX'] and !File.directory? ENV['LFM_PREFIX'] - abort "Installation prefix exists but isn't a directory: "+ENV['LFM_PREFIX'] - end - puts "Will install to: "+ENV['LFM_PREFIX'] - end - - h1 'Generating Build System' - - h2 'Generating .qmake.env' do - f = File.new("#{cwd}/.qmake.env", 'w') - f.write qmake_env('CC', 'QMAKE_CC') - f.write qmake_env('CXX', 'QMAKE_CXX') - f.write qmake_env('LDFLAGS', 'QMAKE_LFLAGS_RELEASE') - f.write qmake_env(['CFLAGS', 'CPPFLAGS'], 'QMAKE_CFLAGS_RELEASE') - f.write qmake_env(['CXXFLAGS', 'CPPFLAGS'], 'QMAKE_CXXFLAGS_RELEASE') - f.close - end unless Platform::IMPL == :mswin - - h2 "Running qpp..." do - ['src','src/fingerprint'].each do |d| - d="#{cwd}/#{d}" - f=File.new "#{d}/_files.qmake", 'w' - f.write `ruby admin/qpp #{d}` - # on Windows VERSION produces lastfm0.dll, the 0 breaks the build - f.puts "VERSION = #{LFM_VERSION}" unless Platform::IMPL == :mswin - end - end - - h2 "Configuring qmake..." do - args=Array.new - if ARGV.include? '--release' - args << '-config release' - args << '"CONFIG += app_bundle"' if Platform::IMPL == :macosx and ARGV.include? '--bundle' - else - args << '-config debug' - end - if ARGV.include? '--no-strip' - args << '"CONFIG += nostrip"' - end - ENV['LFM_QMAKE'] = "#{$qmake} #{args.join(' ')}" - end - - h2 "Generating Makefile..." do - hs = Array.new - hs << 'global.h' - hs << 'core/UrlBuilder.h' << 'core/XmlQuery.h' << 'core/misc.h' - hs << 'fingerprint/Fingerprint.h' << 'fingerprint/FingerprintableSource.h' - hs << 'radio/RadioStation.h' << 'radio/RadioTuner.h' - hs << 'scrobble/Audioscrobbler.h' << 'scrobble/Scrobble.h' << 'scrobble/ScrobblePoint.h' << 'scrobble/ScrobbleCache.h' - hs << 'types/Track.h types/Mbid.h' << 'types/Artist.h' << 'types/Album.h' << 'types/FingerprintId.h' << 'types/Playlist.h' << 'types/Tag.h' << 'types/User.h types/Xspf.h' - hs << 'ws/ws.h' << 'ws/InternetConnectionMonitor.h' << 'ws/NetworkAccessManager.h' - - File.new("#{cwd}/Makefile", 'w').write `ruby admin/Makefile.rb #{hs.join(' ')}` - end - - case Platform::IMPL - when :mswin then make='nmake' - else make='make' # NOTE only tested with GNU make, sorry :( - end - - puts - puts "Good, your configure is finished! Now type: #{make}" - -rescue QMakeTooOld - puts <<-sput - - Your version of Qt seems to be too old, we require Qt 4.4 or above. - - It is possible you have Qt3 and Qt4 both installed. Locate your Qt4 - installation and ensure it is placed first in the path, eg: - - PATH=/opt/qt4/bin:\$PATH ./configure - - sput - exit 1 -rescue QMakeNotFound - puts "Sorry, qmake was not found, is Qt4 installed?" - exit 2 -rescue PkgNotFound => e - puts <<-sput - - Sorry, we couldn't find #{e}. - You can try to compile anyway by forcing configure to finish: - - ./configure --skip-checks - - sput - exit 3 -rescue PkgConfigNotFound - puts "Sorry, pkg-config could not be found. You should install it!" - exit 4 -end diff -Nru liblastfm-0.4.0~really0.3.3/debian/changelog liblastfm-1.0.1/debian/changelog --- liblastfm-0.4.0~really0.3.3/debian/changelog 2012-06-22 22:01:51.000000000 +0000 +++ liblastfm-1.0.1/debian/changelog 2012-06-22 21:51:56.000000000 +0000 @@ -1,3 +1,51 @@ +liblastfm (1.0.1-0ubuntu1~precise1~ppa1) precise; urgency=low + + * Backport to precise + - Update install files + + -- Rohan Garg Fri, 22 Jun 2012 23:28:52 +0200 + +liblastfm (1.0.1-0ubuntu1~ppa1) quantal; urgency=low + + * New upstream release + - Add ${misc:Depends} to liblastfm-dev + - Bump debhelper build depend to >= 7.0.50~ + + -- Rohan Garg Fri, 22 Jun 2012 23:10:15 +0200 + +liblastfm (1.0.0-0ubuntu4) quantal; urgency=low + + * Multiarch compatible wildcarding + + -- Harald Sitter Tue, 12 Jun 2012 18:14:29 +0200 + +liblastfm (1.0.0-0ubuntu3) quantal; urgency=low + + * Build depend on cmake + + -- Harald Sitter Tue, 12 Jun 2012 17:54:30 +0200 + +liblastfm (1.0.0-0ubuntu2) quantal; urgency=low + + * Drop cdbs' list-missing left overs + + -- Harald Sitter Tue, 12 Jun 2012 17:50:20 +0200 + +liblastfm (1.0.0-0ubuntu1) quantal; urgency=low + + * New upstream release + * Drop Vcs entries from control (was upstream VCS, which is not what the + fields are supposed to be used for) + * Don't run tests as they choose to fail + * Convert do dh7 rules from manual makefile + * Convert do source format 3 and use xz -9 compression on debian.tar. + * Bump lib packages to soversion 1 and fix the wildcards to fail on so + changes + * Don't start synopsis with article + * -dev to depend on libqt4-dev (LP: #796176) + + -- Harald Sitter Tue, 12 Jun 2012 17:12:32 +0200 + liblastfm (0.4.0~really0.3.3-0ubuntu1) maverick; urgency=low * New upstream release 0.3.3. diff -Nru liblastfm-0.4.0~really0.3.3/debian/control liblastfm-1.0.1/debian/control --- liblastfm-0.4.0~really0.3.3/debian/control 2012-06-22 22:01:51.000000000 +0000 +++ liblastfm-1.0.1/debian/control 2012-06-22 21:17:45.000000000 +0000 @@ -2,39 +2,38 @@ Priority: extra Maintainer: Kubuntu Developers XSBC-Original-Maintainer: John Stamp -Build-Depends: debhelper (>= 7), ruby, libqt4-dev, libfftw3-dev, libsamplerate0-dev -Standards-Version: 3.8.2 +Build-Depends: debhelper (>= 7.0.50~), ruby, libqt4-dev, libfftw3-dev, libsamplerate0-dev, cmake +Standards-Version: 3.8.3 Section: libs Homepage: http://www.last.fm/ -Vcs-Browser: http://github.com/jstamp/liblastfm -Vcs-Git: git://github.com/jstamp/liblastfm.git Package: liblastfm-dev Section: libdevel Architecture: any -Depends: liblastfm0 (= ${binary:Version}), liblastfm-fingerprint0 (= ${binary:Version}) -Description: The Last.fm web services library - development files +Depends: liblastfm1 (= ${binary:Version}), liblastfm-fingerprint1 (= ${binary:Version}), + libqt4-dev, ${misc:Depends} +Description: Last.fm web services library - development files liblastfm is a collection of C++/Qt4 libraries provided by Last.fm for use with their web services. . This package contains the development files. Developers working on a new client will need to request an API key. See README for more details. -Package: liblastfm0 +Package: liblastfm1 Section: libs Architecture: any Depends: ${shlibs:Depends}, ${misc:Depends} -Description: The Last.fm web services library +Description: Last.fm web services library liblastfm is a collection of C++/Qt4 libraries provided by Last.fm for use with their web services. . This package contains the base web services library. -Package: liblastfm-fingerprint0 +Package: liblastfm-fingerprint1 Section: libs Architecture: any Depends: ${shlibs:Depends}, ${misc:Depends} -Description: The Last.fm fingerprinting library +Description: Last.fm fingerprinting library liblastfm is a collection of C++/Qt4 libraries provided by Last.fm for use with their web services. . @@ -44,7 +43,8 @@ Package: liblastfm-dbg Architecture: any Section: debug -Depends: liblastfm0 (= ${binary:Version}), liblastfm-fingerprint0 (= ${binary:Version}), ${shlibs:Depends}, ${misc:Depends} +Depends: ${misc:Depends}, + liblastfm1 (= ${binary:Version}), liblastfm-fingerprint1 (= ${binary:Version}) Description: Debugging symbols for the Last.fm web services library liblastfm is a collection of C++/Qt4 libraries provided by Last.fm for use with their web services. diff -Nru liblastfm-0.4.0~really0.3.3/debian/liblastfm0.dirs liblastfm-1.0.1/debian/liblastfm0.dirs --- liblastfm-0.4.0~really0.3.3/debian/liblastfm0.dirs 2012-06-22 22:01:51.000000000 +0000 +++ liblastfm-1.0.1/debian/liblastfm0.dirs 1970-01-01 00:00:00.000000000 +0000 @@ -1 +0,0 @@ -usr/lib diff -Nru liblastfm-0.4.0~really0.3.3/debian/liblastfm0.install liblastfm-1.0.1/debian/liblastfm0.install --- liblastfm-0.4.0~really0.3.3/debian/liblastfm0.install 2012-06-22 22:01:51.000000000 +0000 +++ liblastfm-1.0.1/debian/liblastfm0.install 1970-01-01 00:00:00.000000000 +0000 @@ -1 +0,0 @@ -usr/lib/liblastfm.so.* diff -Nru liblastfm-0.4.0~really0.3.3/debian/liblastfm1.install liblastfm-1.0.1/debian/liblastfm1.install --- liblastfm-0.4.0~really0.3.3/debian/liblastfm1.install 1970-01-01 00:00:00.000000000 +0000 +++ liblastfm-1.0.1/debian/liblastfm1.install 2012-06-22 21:42:44.000000000 +0000 @@ -0,0 +1,2 @@ +usr/lib/liblastfm.so.1.* +usr/lib/liblastfm.so.1 diff -Nru liblastfm-0.4.0~really0.3.3/debian/liblastfm-dev.dirs liblastfm-1.0.1/debian/liblastfm-dev.dirs --- liblastfm-0.4.0~really0.3.3/debian/liblastfm-dev.dirs 2012-06-22 22:01:51.000000000 +0000 +++ liblastfm-1.0.1/debian/liblastfm-dev.dirs 1970-01-01 00:00:00.000000000 +0000 @@ -1,2 +0,0 @@ -usr/lib -usr/include diff -Nru liblastfm-0.4.0~really0.3.3/debian/liblastfm-dev.docs liblastfm-1.0.1/debian/liblastfm-dev.docs --- liblastfm-0.4.0~really0.3.3/debian/liblastfm-dev.docs 2012-06-22 22:01:51.000000000 +0000 +++ liblastfm-1.0.1/debian/liblastfm-dev.docs 2012-06-12 15:27:43.000000000 +0000 @@ -1 +1 @@ -README +README.md diff -Nru liblastfm-0.4.0~really0.3.3/debian/liblastfm-fingerprint0.dirs liblastfm-1.0.1/debian/liblastfm-fingerprint0.dirs --- liblastfm-0.4.0~really0.3.3/debian/liblastfm-fingerprint0.dirs 2012-06-22 22:01:51.000000000 +0000 +++ liblastfm-1.0.1/debian/liblastfm-fingerprint0.dirs 1970-01-01 00:00:00.000000000 +0000 @@ -1 +0,0 @@ -usr/lib diff -Nru liblastfm-0.4.0~really0.3.3/debian/liblastfm-fingerprint0.install liblastfm-1.0.1/debian/liblastfm-fingerprint0.install --- liblastfm-0.4.0~really0.3.3/debian/liblastfm-fingerprint0.install 2012-06-22 22:01:51.000000000 +0000 +++ liblastfm-1.0.1/debian/liblastfm-fingerprint0.install 1970-01-01 00:00:00.000000000 +0000 @@ -1 +0,0 @@ -usr/lib/liblastfm_fingerprint.so.* diff -Nru liblastfm-0.4.0~really0.3.3/debian/liblastfm-fingerprint1.install liblastfm-1.0.1/debian/liblastfm-fingerprint1.install --- liblastfm-0.4.0~really0.3.3/debian/liblastfm-fingerprint1.install 1970-01-01 00:00:00.000000000 +0000 +++ liblastfm-1.0.1/debian/liblastfm-fingerprint1.install 2012-06-22 21:43:42.000000000 +0000 @@ -0,0 +1,2 @@ +usr/lib/liblastfm_fingerprint.so.1.* +usr/lib/liblastfm_fingerprint.so.1 diff -Nru liblastfm-0.4.0~really0.3.3/debian/rules liblastfm-1.0.1/debian/rules --- liblastfm-0.4.0~really0.3.3/debian/rules 2012-06-22 22:01:51.000000000 +0000 +++ liblastfm-1.0.1/debian/rules 2012-06-12 15:41:53.000000000 +0000 @@ -1,76 +1,9 @@ #!/usr/bin/make -f -# -*- makefile -*- -# Uncomment this to turn on verbose mode. -#export DH_VERBOSE=1 +%: + dh $@ --paralell --dbg-package=liblastfm-dbg -version=`ls _bin/lib*.so.* | \ - awk '{if (match($$0,/[0-9]+\.[0-9]+\.[0-9]+$$/)) print substr($$0,RSTART)}'` -major=`ls _bin/lib*.so.* | \ - awk '{if (match($$0,/\.so\.[0-9]+$$/)) print substr($$0,RSTART+4)}'` +override_dh_auto_configure: + dh_auto_configure -- -DBUILD_FINGERPRINT=TRUE -LDFLAGS += "-Wl,--no-undefined -Wl,--as-needed" - -configure: config-stamp -config-stamp: - dh_testdir - ./configure --release --prefix /usr --no-strip - touch $@ - - -build: build-stamp -build-stamp: configure - dh_testdir - - # Add here commands to compile the package. - $(MAKE) headers __src __fingerprint - - touch $@ - -clean: - dh_testdir - dh_testroot - rm -f build-stamp config-stamp - - # Add here commands to clean up after the build process. - [ ! -f Makefile ] || $(MAKE) distclean || true - - dh_clean - -install: build - dh_testdir - dh_testroot - dh_prep - dh_installdirs - - # Add here commands to install the package into debian/tmp - DESTDIR=$(CURDIR)/debian/tmp $(MAKE) install - - -# Build architecture-independent files here. -binary-indep: install -# We have nothing to do by default. - -# Build architecture-dependent files here. -binary-arch: install - dh_testdir - dh_testroot - dh_installchangelogs - dh_installdocs - dh_installexamples - dh_install - dh_installman - dh_link - dh_strip --dbg-package=liblastfm-dbg - dh_compress - dh_fixperms - dh_makeshlibs -pliblastfm0 -V'liblastfm0 (>= 0.4.0~really0.3.3)' - dh_makeshlibs -pliblastfm-fingerprint0 -V'liblastfm-fingerprint0' - dh_installdeb - dh_shlibdeps - dh_gencontrol - dh_md5sums - dh_builddeb - -binary: binary-indep binary-arch -.PHONY: build clean binary-indep binary-arch binary install +.PHONY: override_dh_auto_test diff -Nru liblastfm-0.4.0~really0.3.3/debian/source/format liblastfm-1.0.1/debian/source/format --- liblastfm-0.4.0~really0.3.3/debian/source/format 1970-01-01 00:00:00.000000000 +0000 +++ liblastfm-1.0.1/debian/source/format 2012-06-22 22:01:51.000000000 +0000 @@ -0,0 +1 @@ +3.0 (quilt) diff -Nru liblastfm-0.4.0~really0.3.3/debian/source/options liblastfm-1.0.1/debian/source/options --- liblastfm-0.4.0~really0.3.3/debian/source/options 1970-01-01 00:00:00.000000000 +0000 +++ liblastfm-1.0.1/debian/source/options 2012-06-12 15:29:53.000000000 +0000 @@ -0,0 +1,2 @@ +compression = "xz" +compression-level = 9 diff -Nru liblastfm-0.4.0~really0.3.3/demos/demo1.cpp liblastfm-1.0.1/demos/demo1.cpp --- liblastfm-0.4.0~really0.3.3/demos/demo1.cpp 2010-09-25 17:30:01.000000000 +0000 +++ liblastfm-1.0.1/demos/demo1.cpp 2012-06-18 10:37:51.000000000 +0000 @@ -3,12 +3,18 @@ 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 "Artist.h" +#include "ws.h" + +#include +#include #include #include +#include + class ArtistList : public QListWidget { Q_OBJECT diff -Nru liblastfm-0.4.0~really0.3.3/demos/demo2.cpp liblastfm-1.0.1/demos/demo2.cpp --- liblastfm-0.4.0~really0.3.3/demos/demo2.cpp 2010-09-25 17:30:01.000000000 +0000 +++ liblastfm-1.0.1/demos/demo2.cpp 2012-06-18 10:37:51.000000000 +0000 @@ -3,7 +3,12 @@ support, and with no warranty, express or implied, as to its usefulness for any purpose. */ -#include + +#include "ws.h" +#include "misc.h" +#include "XmlQuery.h" +#include "Artist.h" + #include @@ -34,10 +39,11 @@ 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 = +#warning credentials need to be filled in + 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 @@ -74,8 +80,10 @@ // // // If status is not "ok" then this function throws - lastfm::XmlQuery const lfm = lastfm::ws::parse( reply ); - + lastfm::XmlQuery const lfm; +#warning this code needs to be ported to new api, executable is most likely broken + //= 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(); @@ -91,8 +99,9 @@ ////// because the SessionKey is now set, the AuthenticatedUser class will // work. And we can call authenticated calls - QNetworkReply* reply = lastfm::AuthenticatedUser().getRecommendedArtists(); - + QNetworkReply* reply; +#warning this code needs to be ported to new api, executable is most likely broken + //= lastfm::AuthenticatedUser().getRecommendedArtists(); // again, you shouldn't do this.. ;) QEventLoop loop; loop.connect( reply, SIGNAL(finished()), SLOT(quit()) ); diff -Nru liblastfm-0.4.0~really0.3.3/demos/demo3.cpp liblastfm-1.0.1/demos/demo3.cpp --- liblastfm-0.4.0~really0.3.3/demos/demo3.cpp 2010-09-25 17:30:01.000000000 +0000 +++ liblastfm-1.0.1/demos/demo3.cpp 2012-06-18 10:37:51.000000000 +0000 @@ -3,10 +3,14 @@ support, and with no warranty, express or implied, as to its usefulness for any purpose. */ -#include + +#include "Audioscrobbler.h" +#include "ws.h" +#include "Track.h" + + #include #include -#include "src/_version.h" struct MyCoreApp : QCoreApplication @@ -29,12 +33,11 @@ { // 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 + 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 ); diff -Nru liblastfm-0.4.0~really0.3.3/demos/demos.pro liblastfm-1.0.1/demos/demos.pro --- liblastfm-0.4.0~really0.3.3/demos/demos.pro 2010-09-25 17:30:01.000000000 +0000 +++ liblastfm-1.0.1/demos/demos.pro 1970-01-01 00:00:00.000000000 +0000 @@ -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 -Nru liblastfm-0.4.0~really0.3.3/.qmake.cache liblastfm-1.0.1/.qmake.cache --- liblastfm-0.4.0~really0.3.3/.qmake.cache 2010-09-25 17:30:01.000000000 +0000 +++ liblastfm-1.0.1/.qmake.cache 1970-01-01 00:00:00.000000000 +0000 @@ -1,37 +0,0 @@ -unix:include(.qmake.env) - -win32:ROOT_DIR = $$system( cd ) -else:ROOT_DIR = $$system( pwd ) - -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 -} - -CONFIG( debug, debug|release ):CONFIG -= release -CONFIG( release, release|debug ):CONFIG -= debug -CONFIG -= debug_and_release #never works properly IMO - -*g++* { - # allow use of 'and', 'or', etc. as symbols - QMAKE_CXXFLAGS += -fno-operator-names - QMAKE_CXXFLAGS_RELEASE += -fvisibility-inlines-hidden -fvisibility=hidden -} - -# look better to Linux folks :P -linux:CONFIG += warn_off - -# used to determine if we should statically link the fingerprint library -# used by lastfm-desktop and other projects -CONFIG -= app_bundle \ No newline at end of file diff -Nru liblastfm-0.4.0~really0.3.3/README liblastfm-1.0.1/README --- liblastfm-0.4.0~really0.3.3/README 2010-09-25 17:30:01.000000000 +0000 +++ liblastfm-1.0.1/README 1970-01-01 00:00:00.000000000 +0000 @@ -1,138 +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. - -Max Howell http://twitter.com/mxcl -Jono Cole http://twitter.com/jonocole -Doug Mansell http://twitter.com/dougma - -Fork it: http://github.com/mxcl/liblastfm - - -Dependencies -============ -liblastfm dynamically links to: - -* Qt 4.4 - http://www.qtsoftware.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 - -qt4-mac-devel will take a long time to build. So you may want to install the -Trolltech binary package instead. - -Both MacPorts and Homebrew carry liblastfm now: - - brew install liblastfm - port install liblastfm - -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 mxcl on GitHub. - -Windows -------- -Install Ruby. Install Visual Studio 2005 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 -==================== - ruby configure --release --prefix /usr/local && make && sudo make install - -Packaging liblastfm -------------------- -DESTDIR is supported. - -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 -Nru liblastfm-0.4.0~really0.3.3/README.md liblastfm-1.0.1/README.md --- liblastfm-0.4.0~really0.3.3/README.md 1970-01-01 00:00:00.000000000 +0000 +++ liblastfm-1.0.1/README.md 2012-06-18 10:37:51.000000000 +0000 @@ -0,0 +1,126 @@ +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 -Nru liblastfm-0.4.0~really0.3.3/src/AbstractType.h liblastfm-1.0.1/src/AbstractType.h --- liblastfm-0.4.0~really0.3.3/src/AbstractType.h 1970-01-01 00:00:00.000000000 +0000 +++ liblastfm-1.0.1/src/AbstractType.h 2012-06-18 10:37:51.000000000 +0000 @@ -0,0 +1,51 @@ +/* + 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 LASTFM_ABSTRACTTYPE_H +#define LASTFM_ABSTRACTTYPE_H + +#include +#include + +#include "global.h" + +namespace lastfm +{ + class LASTFM_DLLEXPORT AbstractType + { + public: + enum ImageSize + { + SmallImage, + MediumImage, + LargeImage, /** seemingly 174x174 */ + ExtraLargeImage, + MegaImage + }; + + 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 // LASTFM_ABSTRACTTYPE_H diff -Nru liblastfm-0.4.0~really0.3.3/src/Album.cpp liblastfm-1.0.1/src/Album.cpp --- liblastfm-0.4.0~really0.3.3/src/Album.cpp 1970-01-01 00:00:00.000000000 +0000 +++ liblastfm-1.0.1/src/Album.cpp 2012-06-18 10:37:51.000000000 +0000 @@ -0,0 +1,216 @@ +/* + 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 "UrlBuilder.h" +#include "XmlQuery.h" +#include "ws.h" +#include +#include +#include + +using lastfm::Album; +using lastfm::Artist; +using lastfm::Mbid; + +namespace lastfm +{ + class AlbumPrivate : public QSharedData + { + public: + AlbumPrivate() {} + + Mbid mbid; + Artist artist; + QString title; + QMap images; + }; +} + +Album::Album() + :AbstractType(), d( new lastfm::AlbumPrivate ) +{ +} + +Album::Album( Mbid mbid ) + :AbstractType(), d( new lastfm::AlbumPrivate ) +{ + d->mbid = mbid; +} + +Album::Album( Artist artist, QString title ) + :AbstractType(), d( new lastfm::AlbumPrivate ) +{ + d->artist = artist; + d->title = title; +} + +Album::Album( const Album& other ) + : d( other.d ) +{ +} + +Album::~Album() +{ +} + +QDomElement +Album::toDomElement( QDomDocument& ) const +{ + return QDomElement(); +} + +QUrl +Album::imageUrl( ImageSize size, bool square ) const +{ + if( !square ) return d->images.value( size ); + + QUrl url = d->images.value( size ); + QRegExp re( "/serve/(\\d*)s?/" ); + return QUrl( url.toString().replace( re, "/serve/\\1s/" )); +} + +void +Album::setImageUrl( ImageSize size, const QString& url ) +{ + if ( !url.isEmpty() ) + d->images[size] = url; +} + +bool +Album::operator==( const Album& that ) const +{ + return d->title == that.d->title && d->artist == that.d->artist; +} + +bool +Album::operator!=( const Album& that ) const +{ + return d->title != that.d->title || d->artist != that.d->artist; +} + +Album& +Album::operator=( const Album& that ) +{ + d = that.d; + return *this; +} + +QString +Album::toString() const +{ + return title(); +} + +Album::operator QString() const +{ + return toString(); +} + +QString +Album::title() const +{ + return d->title; +} + +void +Album::setArtist( const QString& artist ) +{ + return d->artist.setName( artist ); +} + +Artist +Album::artist() const +{ + return d->artist; +} + +Mbid +Album::mbid() const +{ + return d->mbid; +} + +bool +Album::isNull() const +{ + return d->title.isEmpty() && d->mbid.isNull(); +} + + +QNetworkReply* +lastfm::Album::getInfo( const QString& username) const +{ + QMap map; + map["method"] = "album.getInfo"; + map["artist"] = d->artist; + map["album"] = d->title; + if (!username.isEmpty()) map["username"] = 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"] = d->artist; + map["album"] = d->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"] = d->artist; + map["album"] = d->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( d->artist ).slash( d->title ).url(); +} + + +QNetworkReply* +lastfm::Album::addTags( const QStringList& tags ) const +{ + if (tags.isEmpty()) + return 0; + + QMap map; + map["method"] = "album.addTags"; + map["artist"] = d->artist; + map["album"] = d->title; + map["tags"] = tags.join( QChar(',') ); + return lastfm::ws::post(map); +} diff -Nru liblastfm-0.4.0~really0.3.3/src/Album.h liblastfm-1.0.1/src/Album.h --- liblastfm-0.4.0~really0.3.3/src/Album.h 1970-01-01 00:00:00.000000000 +0000 +++ liblastfm-1.0.1/src/Album.h 2012-06-18 10:37:51.000000000 +0000 @@ -0,0 +1,78 @@ +/* + 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 "AbstractType.h" + +#include "Artist.h" +#include "Mbid.h" + +namespace lastfm +{ + class LASTFM_DLLEXPORT Album : public AbstractType + { + public: + Album(); + explicit Album( Mbid mbid ); + Album( Artist artist, QString title ); + Album( const Album& album ); + ~Album(); + + QDomElement toDomElement( QDomDocument& ) const; + + virtual QUrl imageUrl( ImageSize size, bool square = false ) const; + void setImageUrl( ImageSize size, const QString& url ); + + void setArtist( const QString& artist ); + + bool operator==( const Album& that ) const; + bool operator!=( const Album& that ) const; + Album& operator=( const Album& that ); + + QString toString() const; + operator QString() const; + QString title() const; + Artist artist() const; + Mbid mbid() const; + + /** artist may have been set, since we allow that in the ctor, but should we handle untitled albums? */ + bool isNull() const; + + /** Album.getInfo WebService */ + QNetworkReply* getInfo( const QString& username = "" ) 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; + + private: + QExplicitlySharedDataPointer d; + }; +} + +#endif //LASTFM_ALBUM_H diff -Nru liblastfm-0.4.0~really0.3.3/src/Artist.cpp liblastfm-1.0.1/src/Artist.cpp --- liblastfm-0.4.0~really0.3.3/src/Artist.cpp 1970-01-01 00:00:00.000000000 +0000 +++ liblastfm-1.0.1/src/Artist.cpp 2012-06-18 10:37:51.000000000 +0000 @@ -0,0 +1,329 @@ +/* + 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 "UrlBuilder.h" +#include "XmlQuery.h" +#include "ws.h" + +#include +#include +#include + +using lastfm::Artist; +using lastfm::ArtistData; +using lastfm::User; +using lastfm::XmlQuery; + + +class lastfm::ArtistData : public QSharedData +{ +public: + ArtistData() {} + ~ArtistData() {} + QString name; + QMap images; +}; + + +Artist::Artist() + :AbstractType() +{ + d = new ArtistData; +} + +Artist::Artist( const QString& name ) + : AbstractType() +{ + d = new ArtistData; + d->name = name; +} + +Artist::Artist( const XmlQuery& xml ) + :AbstractType() +{ + d = new ArtistData; + + d->name = xml["name"].text(); + setImageUrl( SmallImage, xml["image size=small"].text() ); + setImageUrl( MediumImage, xml["image size=medium"].text() ); + setImageUrl( LargeImage, xml["image size=large"].text() ); + setImageUrl( ExtraLargeImage, xml["image size=extralarge"].text() ); + setImageUrl( MegaImage, xml["image size=mega"].text() ); +} + +Artist::Artist( const Artist& artist ) + :AbstractType(), d( artist.d ) +{ +} + +Artist::~Artist() +{ +} + +QUrl +Artist::imageUrl( ImageSize size, bool square ) const +{ + if( !square ) return d->images.value( size ); + + QUrl url = d->images.value( size ); + QRegExp re( "/serve/(\\d*)s?/" ); + return QUrl( url.toString().replace( re, "/serve/\\1s/" )); +} + +void +Artist::setImageUrl( ImageSize size, const QString& url ) +{ + if ( !url.isEmpty() ) + d->images[size] = url; +} + +QMap //private +Artist::params( const QString& method ) const +{ + QMap map; + map["method"] = "artist."+method; + map["artist"] = d->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 QString& username ) const +{ + QMap map = params("getInfo"); + if (!username.isEmpty()) map["username"] = 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; + + XmlQuery lfm; + + if ( lfm.parse( 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() ); + } + } + else + { + qWarning() << lfm.parseError().message(); + } + return artists; +} + + +QStringList /* static */ +Artist::getTopTracks( QNetworkReply* r ) +{ + QStringList tracks; + try + { + XmlQuery lfm; + lfm.parse( r->readAll() ); + foreach (XmlQuery e, lfm.children( "track" )) + { + tracks << e["name"].text(); + } + } + catch (ws::ParseError& e) + { + qWarning() << e.message(); + } + return tracks; +} + + +QList /* static */ +Artist::list( QNetworkReply* r ) +{ + QList artists; + XmlQuery lfm; + + if ( lfm.parse( r->readAll() ) ) + { + foreach (XmlQuery xq, lfm.children( "artist" )) + { + Artist artist( xq ); + artists += artist; + } + } + else + { + qWarning() << lfm.parseError().message(); + } + return artists; +} + + +Artist +Artist::getInfo( QNetworkReply* r ) +{ + XmlQuery lfm; + + if ( lfm.parse( r->readAll() ) ) + { + Artist artist = Artist( lfm["artist"] ); + return artist; + } + else + { + qWarning() << lfm.parseError().message(); + 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); +} + +bool +Artist::isNull() const +{ + return d->name.isEmpty(); +} + +Artist& +Artist::operator=( const Artist& that ) +{ + d->name = that.name(); d->images = that.d->images; return *this; +} + +bool +lastfm::Artist::operator==( const Artist& that ) const +{ + return d->name == that.d->name; +} + +bool +Artist::operator!=( const Artist& that ) const +{ + return d->name != that.d->name; +} +bool +Artist::operator<( const Artist& that ) const +{ + return d->name < that.d->name; +} + +Artist::operator QString() const +{ + return d->name; +} + +QString Artist::toString() const +{ + return name(); +} + +QString Artist::name() const +{ + return QString(*this); +} + +void Artist::setName( const QString& name ) +{ + d->name = name; +} + +QDomElement Artist::toDomElement( QDomDocument& ) const +{ + return QDomElement(); +} + diff -Nru liblastfm-0.4.0~really0.3.3/src/Artist.h liblastfm-1.0.1/src/Artist.h --- liblastfm-0.4.0~really0.3.3/src/Artist.h 1970-01-01 00:00:00.000000000 +0000 +++ liblastfm-1.0.1/src/Artist.h 2012-06-18 10:37:51.000000000 +0000 @@ -0,0 +1,98 @@ +/* + 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 "AbstractType.h" + +#include +#include + +class QNetworkReply; + +namespace lastfm +{ + class LASTFM_DLLEXPORT Artist : public AbstractType + { + private: + QExplicitlySharedDataPointer d; + + public: + Artist(); + ~Artist(); + Artist( const QString& name ); + Artist( const class XmlQuery& xml ); + Artist( const Artist& artist ); + + /** will be QUrl() unless you got this back from a getInfo or something call */ + QUrl imageUrl( ImageSize size = LargeImage, bool square = false ) const; + void setImageUrl( ImageSize size, const QString& url ); + + bool isNull() const; + + /** the url for this artist's page at www.last.fm */ + QUrl www() const; + + Artist& operator=( const Artist& that ); + bool operator==( const Artist& that ) const; + bool operator!=( const Artist& that ) const; + bool operator<( const Artist& that ) const; + + operator QString() const; + + QString toString() const; + + QString name() const; + void setName( const QString& name ); + + QDomElement toDomElement( QDomDocument& ) const; + + QNetworkReply* share( const QStringList& recipients, const QString& message = "", bool isPublic = true ) const; + + QNetworkReply* getEvents(int limit = 0) const; + QNetworkReply* getInfo( const QString& username = "" ) 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 -Nru liblastfm-0.4.0~really0.3.3/src/Audioscrobbler.cpp liblastfm-1.0.1/src/Audioscrobbler.cpp --- liblastfm-0.4.0~really0.3.3/src/Audioscrobbler.cpp 1970-01-01 00:00:00.000000000 +0000 +++ liblastfm-1.0.1/src/Audioscrobbler.cpp 2012-06-18 10:37:51.000000000 +0000 @@ -0,0 +1,241 @@ +/* + 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 "Audioscrobbler.h" +#include "ScrobbleCache.h" +#include "Track.h" +#include "User.h" +#include "ws.h" +#include "XmlQuery.h" + +#include +#include + + +namespace lastfm +{ + class AudioscrobblerPrivate + { + public: + AudioscrobblerPrivate(const QString& id) + : m_id( id ) + , m_cache( ws::Username ) + {} + + ~AudioscrobblerPrivate() + { + } + + void parseTrack( const XmlQuery& trackXml, const Track& track ); + + 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, const QString& ) +{ + 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::AudioscrobblerPrivate::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.setScrobbleErrorText( trackXml["ignoredMessage"].text() ); + mTrack.setScrobbleStatus( Track::Error ); + } +} + +void +lastfm::Audioscrobbler::onNowPlayingReturn() +{ + lastfm::XmlQuery lfm; + + if ( lfm.parse( static_cast(sender())->readAll() ) ) + { + qDebug() << lfm; + + if ( lfm.attribute("status") == "ok" ) + d->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; + } + else + { + qDebug() << lfm.parseError().message() << lfm.parseError().enumValue(); + } + + d->m_nowPlayingTrack = Track(); + d->m_nowPlayingReply = 0; +} + + +void +lastfm::Audioscrobbler::onTrackScrobbleReturn() +{ + lastfm::XmlQuery lfm; + + if ( lfm.parse( d->m_scrobbleReply->readAll() ) ) + { + qDebug() << lfm; + + if (lfm.attribute("status") == "ok") + { + int index = 0; + + foreach ( const XmlQuery& scrobble, lfm["scrobbles"].children("scrobble") ) + d->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(); + } + else + { + qDebug() << lfm.parseError().message() << lfm.parseError().enumValue(); + d->m_scrobbleReply = 0; + } +} diff -Nru liblastfm-0.4.0~really0.3.3/src/Audioscrobbler.h liblastfm-1.0.1/src/Audioscrobbler.h --- liblastfm-0.4.0~really0.3.3/src/Audioscrobbler.h 1970-01-01 00:00:00.000000000 +0000 +++ liblastfm-1.0.1/src/Audioscrobbler.h 2012-06-18 10:37:51.000000000 +0000 @@ -0,0 +1,74 @@ +/* + 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 "global.h" +#include +#include + +namespace lastfm +{ + class Track; + + /** @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&, const QString& id = "" ); + + /** will submit the submission cache for this user */ + void submit(); + + private slots: + void onNowPlayingReturn(); + void onTrackScrobbleReturn(); + + private: + class AudioscrobblerPrivate * const d; + }; +} + +#endif diff -Nru liblastfm-0.4.0~really0.3.3/src/Auth.cpp liblastfm-1.0.1/src/Auth.cpp --- liblastfm-0.4.0~really0.3.3/src/Auth.cpp 1970-01-01 00:00:00.000000000 +0000 +++ liblastfm-1.0.1/src/Auth.cpp 2012-06-18 10:37:51.000000000 +0000 @@ -0,0 +1,37 @@ +/* + Copyright 2012 Last.fm Ltd. + - Primarily authored by 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 "Auth.h" +#include "ws.h" + + +lastfm::Auth::Auth() +{ +} + + +QNetworkReply* +lastfm::Auth::getSessionInfo() +{ + QMap map; + map["method"] = "Auth.getSessionInfo"; + if (!lastfm::ws::Username.isEmpty()) map["username"] = lastfm::ws::Username; + return nam()->get( QNetworkRequest( lastfm::ws::url( map, true ) ) ); +} diff -Nru liblastfm-0.4.0~really0.3.3/src/Auth.h liblastfm-1.0.1/src/Auth.h --- liblastfm-0.4.0~really0.3.3/src/Auth.h 1970-01-01 00:00:00.000000000 +0000 +++ liblastfm-1.0.1/src/Auth.h 2012-06-18 10:37:51.000000000 +0000 @@ -0,0 +1,40 @@ +/* + Copyright 2012 Last.fm Ltd. + - Primarily authored by 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_AUTH_H +#define LASTFM_AUTH_H + +#include "global.h" + +class QNetworkReply; + +namespace lastfm +{ + class LASTFM_DLLEXPORT Auth + { + private: + Auth(); + + public: + static QNetworkReply* getSessionInfo(); + }; +} + +#endif // TASTEOMETER_H diff -Nru liblastfm-0.4.0~really0.3.3/src/Chart.cpp liblastfm-1.0.1/src/Chart.cpp --- liblastfm-0.4.0~really0.3.3/src/Chart.cpp 1970-01-01 00:00:00.000000000 +0000 +++ liblastfm-1.0.1/src/Chart.cpp 2012-06-18 10:37:51.000000000 +0000 @@ -0,0 +1,98 @@ +/* + Copyright 2011 Last.fm Ltd. + - Primarily authored by 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 "Chart.h" +#include "ws.h" + +#include + + +lastfm::Chart::Chart() +{ +} + +QNetworkReply* +lastfm::Chart::getHypedArtists( int limit, int page ) +{ + QMap map; + map["method"] = "chart.getHypedArtists"; + if ( page != -1 ) map["page"] = QString::number( page ); + if ( limit != -1 ) map["limit"] = QString::number( limit ); + return ws::get( map ); +} + +QNetworkReply* +lastfm::Chart::getHypedTracks( int limit, int page ) +{ + QMap map; + map["method"] = "chart.getHypedTracks"; + if ( page != -1 ) map["page"] = QString::number( page ); + if ( limit != -1 ) map["limit"] = QString::number( limit ); + return ws::get( map ); +} + +QNetworkReply* +lastfm::Chart::getLovedTracks( int limit, int page ) +{ + QMap map; + map["method"] = "chart.getLovedTracks"; + if ( page != -1 ) map["page"] = QString::number( page ); + if ( limit != -1 ) map["limit"] = QString::number( limit ); + return ws::get( map ); +} + +QNetworkReply* +lastfm::Chart::getTopArtists( int limit, int page ) +{ + QMap map; + map["method"] = "chart.getTopArtists"; + if ( page != -1 ) map["page"] = QString::number( page ); + if ( limit != -1 ) map["limit"] = QString::number( limit ); + return ws::get( map ); +} + +QNetworkReply* +lastfm::Chart::getTopDownloads( int limit, int page ) +{ + QMap map; + map["method"] = "chart.getTopDownloads"; + if ( page != -1 ) map["page"] = QString::number( page ); + if ( limit != -1 ) map["limit"] = QString::number( limit ); + return ws::get( map ); +} + +QNetworkReply* +lastfm::Chart::getTopTags( int limit, int page ) +{ + QMap map; + map["method"] = "chart.getTopTags"; + if ( page != -1 ) map["page"] = QString::number( page ); + if ( limit != -1 ) map["limit"] = QString::number( limit ); + return ws::get( map ); +} + +QNetworkReply* +lastfm::Chart::getTopTracks( int limit, int page ) +{ + QMap map; + map["method"] = "chart.getTopTracks"; + if ( page != -1 ) map["page"] = QString::number( page ); + if ( limit != -1 ) map["limit"] = QString::number( limit ); + return ws::get( map ); +} diff -Nru liblastfm-0.4.0~really0.3.3/src/Chart.h liblastfm-1.0.1/src/Chart.h --- liblastfm-0.4.0~really0.3.3/src/Chart.h 1970-01-01 00:00:00.000000000 +0000 +++ liblastfm-1.0.1/src/Chart.h 2012-06-18 10:37:51.000000000 +0000 @@ -0,0 +1,46 @@ +/* + Copyright 2011 Last.fm Ltd. + - Primarily authored by 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_CHART_H +#define LASTFM_CHART_H + +#include "global.h" + +class QNetworkReply; + +namespace lastfm +{ + class LASTFM_DLLEXPORT Chart + { + private: + Chart(); + + public: + static QNetworkReply* getHypedArtists( int limit = -1, int page = -1 ); + static QNetworkReply* getHypedTracks( int limit = -1, int page = -1 ); + static QNetworkReply* getLovedTracks( int limit = -1, int page = -1 ); + static QNetworkReply* getTopArtists( int limit = -1, int page = -1 ); + static QNetworkReply* getTopDownloads( int limit = -1, int page = -1 ); + static QNetworkReply* getTopTags( int limit = -1, int page = -1 ); + static QNetworkReply* getTopTracks( int limit = -1, int page = -1 ); + }; +} + +#endif // LASTFM_CHART_H + diff -Nru liblastfm-0.4.0~really0.3.3/src/CMakeLists.txt liblastfm-1.0.1/src/CMakeLists.txt --- liblastfm-0.4.0~really0.3.3/src/CMakeLists.txt 1970-01-01 00:00:00.000000000 +0000 +++ liblastfm-1.0.1/src/CMakeLists.txt 2012-06-18 10:37:51.000000000 +0000 @@ -0,0 +1,99 @@ + +add_definitions(${QT_DEFINITIONS}) +include_directories(${QT_INCLUDES} ${CMAKE_CURRENT_BINARY_DIR}) +set(liblastfm_LIBRARIES + ${QT_QTCORE_LIBRARY} + ${QT_QTNETWORK_LIBRARY} + ${QT_QTXML_LIBRARY} +) + +set(liblastfm_SOURCES + ws.cpp + NetworkConnectionMonitor.cpp + NetworkAccessManager.cpp + InternetConnectionMonitor.cpp + Xspf.cpp + User.cpp + Track.cpp + Tasteometer.cpp + Tag.cpp + Playlist.cpp + Mbid.cpp + FingerprintId.cpp + Artist.cpp + Album.cpp + ScrobbleCache.cpp + ScrobblePoint.cpp + Audioscrobbler.cpp + RadioTuner.cpp + RadioStation.cpp + XmlQuery.cpp + UrlBuilder.cpp + misc.cpp + Chart.cpp + Auth.cpp + Library.cpp +) + +if(WIN32) + add_definitions("-DWIN32_LEAN_AND_MEAN") + + if(NOT MINGW) + add_definitions("-D_ATL_DLL -D_CRT_SECURE_NO_WARNINGS") + + list(APPEND liblastfm_SOURCES + win/WNetworkConnectionMonitor_win.cpp + win/WmiSink.cpp + win/Pac.cpp + win/NdisEvents.cpp + ) + list(APPEND liblastfm_LIBRARIES + winhttp + wbemuuid + ) + endif() +endif() + +if(APPLE) + #FIXME: enable this when deploying + #set(CMAKE_OSX_ARCHITECTURES "i386;ppc") + #set(CMAKE_OSX_DEPLOYMENT_TARGET 10.5) + #set(CMAKE_OSX_SYSROOT "/Developer/SDKs/MacOSX${CMAKE_OSX_DEPLOYMENT_TARGET}.sdk") + + list(APPEND liblastfm_SOURCES + mac/MNetworkConnectionMonitor_mac.cpp + ) + + find_library(SYSTEMCONFIGURATION_LIBRARY SystemConfiguration) + find_library(COREFOUNDATION_LIBRARY CoreFoundation) + list(APPEND liblastfm_LIBRARIES + ${COREFOUNDATION_LIBRARY} + ${SYSTEMCONFIGURATION_LIBRARY} + ) +endif() + +if(UNIX AND NOT APPLE) + list(APPEND liblastfm_SOURCES + linux/LNetworkConnectionMonitor_linux.cpp + ) + + find_package(Qt4 COMPONENTS QtDbus REQUIRED) + list(APPEND liblastfm_LIBRARIES ${QT_QTDBUS_LIBRARY}) +endif() + +add_library(lastfm SHARED ${liblastfm_SOURCES}) +target_link_libraries(lastfm ${liblastfm_LIBRARIES}) +set_target_properties(lastfm PROPERTIES + VERSION ${LASTFM_VERSION} + SOVERSION ${LASTFM_SOVERSION} + COMPILE_DEFINITIONS LASTFM_LIB +) + +install(TARGETS lastfm + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} +) + +file(GLOB liblastfm_HEADERS ${CMAKE_CURRENT_LIST_DIR}/*.h) +install(FILES ${liblastfm_HEADERS} DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/lastfm/) diff -Nru liblastfm-0.4.0~really0.3.3/src/core/misc.cpp liblastfm-1.0.1/src/core/misc.cpp --- liblastfm-0.4.0~really0.3.3/src/core/misc.cpp 2010-09-25 17:30:01.000000000 +0000 +++ liblastfm-1.0.1/src/core/misc.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -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 -Nru liblastfm-0.4.0~really0.3.3/src/core/misc.h liblastfm-1.0.1/src/core/misc.h --- liblastfm-0.4.0~really0.3.3/src/core/misc.h 2010-09-25 17:30:01.000000000 +0000 +++ liblastfm-1.0.1/src/core/misc.h 1970-01-01 00:00:00.000000000 +0000 @@ -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 -Nru liblastfm-0.4.0~really0.3.3/src/core/README liblastfm-1.0.1/src/core/README --- liblastfm-0.4.0~really0.3.3/src/core/README 2010-09-25 17:30:01.000000000 +0000 +++ liblastfm-1.0.1/src/core/README 1970-01-01 00:00:00.000000000 +0000 @@ -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 -Nru liblastfm-0.4.0~really0.3.3/src/core/UrlBuilder.cpp liblastfm-1.0.1/src/core/UrlBuilder.cpp --- liblastfm-0.4.0~really0.3.3/src/core/UrlBuilder.cpp 2010-09-25 17:30:01.000000000 +0000 +++ liblastfm-1.0.1/src/core/UrlBuilder.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -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 -Nru liblastfm-0.4.0~really0.3.3/src/core/UrlBuilder.h liblastfm-1.0.1/src/core/UrlBuilder.h --- liblastfm-0.4.0~really0.3.3/src/core/UrlBuilder.h 2010-09-25 17:30:01.000000000 +0000 +++ liblastfm-1.0.1/src/core/UrlBuilder.h 1970-01-01 00:00:00.000000000 +0000 @@ -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 -Nru liblastfm-0.4.0~really0.3.3/src/core/XmlQuery.cpp liblastfm-1.0.1/src/core/XmlQuery.cpp --- liblastfm-0.4.0~really0.3.3/src/core/XmlQuery.cpp 2010-09-25 17:30:01.000000000 +0000 +++ liblastfm-1.0.1/src/core/XmlQuery.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -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 . -*/ -#include "XmlQuery.h" -#include -using lastfm::XmlQuery; - - -XmlQuery::XmlQuery( const QByteArray& bytes ) -{ - domdoc.setContent(bytes); - e = domdoc.documentElement(); -} - - -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 -Nru liblastfm-0.4.0~really0.3.3/src/core/XmlQuery.h liblastfm-1.0.1/src/core/XmlQuery.h --- liblastfm-0.4.0~really0.3.3/src/core/XmlQuery.h 2010-09-25 17:30:01.000000000 +0000 +++ liblastfm-1.0.1/src/core/XmlQuery.h 1970-01-01 00:00:00.000000000 +0000 @@ -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 . -*/ -#ifndef LASTFM_XMLQUERY_H -#define LASTFM_XMLQUERY_H - -#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& ); - - 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(); } - - /** 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 -Nru liblastfm-0.4.0~really0.3.3/src/fingerprint/CMakeLists.txt liblastfm-1.0.1/src/fingerprint/CMakeLists.txt --- liblastfm-0.4.0~really0.3.3/src/fingerprint/CMakeLists.txt 1970-01-01 00:00:00.000000000 +0000 +++ liblastfm-1.0.1/src/fingerprint/CMakeLists.txt 2012-06-18 10:37:51.000000000 +0000 @@ -0,0 +1,48 @@ + +find_package(Qt4 COMPONENTS QtCore QtSql REQUIRED) +#FIXME: find modules are horrible, port them to find_package_handle_standard_args +find_package(LibSamplerate REQUIRED) +find_package(LibFFTW3 REQUIRED) + +include_directories(${LIBFFTW3_INCLUDE_DIR}) +include_directories(${LIBSAMPLERATE_INCLUDE_DIR}) +include_directories(${QT_INCLUDES}) +include_directories(${CMAKE_CURRENT_LIST_DIR}/..) + +set(lastfm_fingerprint_SOURCES + Collection.cpp + Fingerprint.cpp + Sha256.cpp + fplib/Filter.cpp + fplib/FingerprintExtractor.cpp + fplib/OptFFT.cpp +) + +set(lastfm_fingerprint_HEADERS + Fingerprint.h + FingerprintableSource.h +) + +add_library(lastfm_fingerprint SHARED ${lastfm_fingerprint_SOURCES}) + +target_link_libraries(lastfm_fingerprint + lastfm + ${QT_QTSQL_LIBRARY} + ${QT_QTCORE_LIBRARY} + ${LIBSAMPLERATE_LIBRARY} + ${LIBFFTW3_LIBRARY} +) + +set_target_properties(lastfm_fingerprint PROPERTIES + COMPILE_DEFINITIONS "LASTFM_FINGERPRINT_LIB" + VERSION ${LASTFM_VERSION} + SOVERSION ${LASTFM_SOVERSION} +) + +install(TARGETS lastfm_fingerprint + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} +) + +install(FILES ${lastfm_fingerprint_HEADERS} DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/lastfm/) diff -Nru liblastfm-0.4.0~really0.3.3/src/fingerprint/Collection.cpp liblastfm-1.0.1/src/fingerprint/Collection.cpp --- liblastfm-0.4.0~really0.3.3/src/fingerprint/Collection.cpp 2010-09-25 17:30:01.000000000 +0000 +++ liblastfm-1.0.1/src/fingerprint/Collection.cpp 2012-06-18 10:37:51.000000000 +0000 @@ -19,7 +19,9 @@ */ #include "Collection.h" -#include "../core/misc.h" + +#include "misc.h" + #include #include #include @@ -27,6 +29,7 @@ #include #include #include +#include static const int k_collectionDbVersion = 1; @@ -38,9 +41,7 @@ { m_db = QSqlDatabase::addDatabase( "QSQLITE", "collection" ); m_db.setDatabaseName( lastfm::dir::runtimeData().filePath( "collection.db" ) ); - - QFileInfo(m_db.databaseName()).dir().mkpath("."); - + if (!m_db.open()) { qDebug() << m_db.lastError(); return; diff -Nru liblastfm-0.4.0~really0.3.3/src/fingerprint/contrib/lastfm-fingerprint.pro liblastfm-1.0.1/src/fingerprint/contrib/lastfm-fingerprint.pro --- liblastfm-0.4.0~really0.3.3/src/fingerprint/contrib/lastfm-fingerprint.pro 2010-09-25 17:30:01.000000000 +0000 +++ liblastfm-1.0.1/src/fingerprint/contrib/lastfm-fingerprint.pro 1970-01-01 00:00:00.000000000 +0000 @@ -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 -Nru liblastfm-0.4.0~really0.3.3/src/fingerprint/contrib/VorbisSource.h liblastfm-1.0.1/src/fingerprint/contrib/VorbisSource.h --- liblastfm-0.4.0~really0.3.3/src/fingerprint/contrib/VorbisSource.h 2010-09-25 17:30:01.000000000 +0000 +++ liblastfm-1.0.1/src/fingerprint/contrib/VorbisSource.h 2012-06-18 10:37:51.000000000 +0000 @@ -20,7 +20,7 @@ #ifndef __VORBIS_SOURCE_H__ #define __VORBIS_SOURCE_H__ -#include +#include #include diff -Nru liblastfm-0.4.0~really0.3.3/src/fingerprint/FingerprintableSource.h liblastfm-1.0.1/src/fingerprint/FingerprintableSource.h --- liblastfm-0.4.0~really0.3.3/src/fingerprint/FingerprintableSource.h 2010-09-25 17:30:01.000000000 +0000 +++ liblastfm-1.0.1/src/fingerprint/FingerprintableSource.h 2012-06-18 10:37:51.000000000 +0000 @@ -21,12 +21,12 @@ #ifndef LASTFM_FINGERPRINTABLE_SOURCE_H #define LASTFM_FINGERPRINTABLE_SOURCE_H -#include +#include #include namespace lastfm { - class LASTFM_DLLEXPORT FingerprintableSource + class LASTFM_FINGERPRINT_DLLEXPORT FingerprintableSource { public: /** do all initialisation here and throw if there is problems */ diff -Nru liblastfm-0.4.0~really0.3.3/src/fingerprint/Fingerprint.cpp liblastfm-1.0.1/src/fingerprint/Fingerprint.cpp --- liblastfm-0.4.0~really0.3.3/src/fingerprint/Fingerprint.cpp 2010-09-25 17:30:01.000000000 +0000 +++ liblastfm-1.0.1/src/fingerprint/Fingerprint.cpp 2012-06-18 10:37:51.000000000 +0000 @@ -23,7 +23,8 @@ #include "Collection.h" #include "Sha256.h" #include "fplib/FingerprintExtractor.h" -#include "../ws/ws.h" +#include "ws.h" +#include #include #include #include @@ -36,21 +37,56 @@ static const uint k_bufferSize = 1024 * 8; static const int k_minTrackDuration = 30; +class lastfm::FingerprintPrivate +{ + public: + FingerprintPrivate( const Track& t ) + : m_track( t ) + , m_id( -1 ) + , m_duration( 0 ) + , m_complete( false ) + { + } + lastfm::Track m_track; + QByteArray m_data; + int m_id; + int m_duration; + bool m_complete; +}; + lastfm::Fingerprint::Fingerprint( const Track& t ) - : m_track( t ) - , m_id( -1 ), m_duration( 0 ) - , m_complete( false ) + : d( new FingerprintPrivate( t ) ) { QString id = Collection::instance().getFingerprintId( t.url().toLocalFile() ); if (id.size()) { bool b; - m_id = id.toInt( &b ); - if (!b) m_id = -1; + d->m_id = id.toInt( &b ); + if (!b) d->m_id = -1; } } +lastfm::Fingerprint::~Fingerprint() +{ + delete d; +} + + +lastfm::FingerprintId +lastfm::Fingerprint::id() const +{ + return d->m_id; +} + + +QByteArray +lastfm::Fingerprint::data() const +{ + return d->m_data; +} + + void lastfm::Fingerprint::generate( FingerprintableSource* ms ) throw( Error ) { @@ -66,8 +102,8 @@ try { - ms->init( m_track.url().toLocalFile() ); - ms->getInfo( m_duration, sampleRate, bitrate, numChannels ); + ms->init( d->m_track.url().toLocalFile() ); + ms->getInfo( d->m_duration, sampleRate, bitrate, numChannels ); } catch (std::exception& e) { @@ -76,7 +112,7 @@ } - if (m_duration < k_minTrackDuration) + if (d->m_duration < k_minTrackDuration) throw TrackTooShortError; ms->skipSilence(); @@ -87,13 +123,13 @@ { extractor = new fingerprint::FingerprintExtractor; - if (m_complete) + if (d->m_complete) { extractor->initForFullSubmit( sampleRate, numChannels ); } else { - extractor->initForQuery( sampleRate, numChannels, m_duration ); + extractor->initForQuery( sampleRate, numChannels, d->m_duration ); // Skippety skip for as long as the skipper sez (optimisation) ms->skip( extractor->getToSkipMs() ); @@ -143,7 +179,7 @@ throw InternalError; // Make a deep copy before extractor gets deleted - m_data = QByteArray( fpData.first, fpData.second ); + d->m_data = QByteArray( fpData.first, fpData.second ); delete extractor; } @@ -206,7 +242,7 @@ QNetworkReply* lastfm::Fingerprint::submit() const { - if (m_data.isEmpty()) + if (d->m_data.isEmpty()) return 0; //Parameters understood by the server according to the MIR team: @@ -214,7 +250,7 @@ // "tracknum", "username", "sha256", "ip", "fpversion", "mbid", // "filename", "genre", "year", "samplerate", "noupdate", "fulldump" } - Track const t = m_track; + Track const t = d->m_track; QString const path = t.url().toLocalFile(); QFileInfo const fi( path ); @@ -223,7 +259,7 @@ 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( "duration", number( d->m_duration > 0 ? d->m_duration : t.duration() ) ); url.addEncodedQueryItem( "mbid", e(t.mbid()) ); url.addEncodedQueryItem( "filename", e(fi.completeBaseName()) ); url.addEncodedQueryItem( "fileextension", e(fi.completeSuffix()) ); @@ -231,7 +267,7 @@ 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( "fulldump", d->m_complete ? "true" : "false" ); url.addEncodedQueryItem( "noupdate", "false" ); #undef e @@ -245,7 +281,7 @@ bytes += "Content-Disposition: "; bytes += "form-data; name=\"fpdata\""; bytes += "\r\n\r\n"; - bytes += m_data; + bytes += d->m_data; bytes += "\r\n"; bytes += "------------------------------8e61d618ca16--\r\n"; @@ -285,12 +321,12 @@ uint fpid_as_uint = fpid.toUInt( &b ); if (!b) goto bad_response; - Collection::instance().setFingerprintId( m_track.url().toLocalFile(), fpid ); + Collection::instance().setFingerprintId( d->m_track.url().toLocalFile(), fpid ); if (complete_fingerprint_requested) *complete_fingerprint_requested = (status == "NEW"); - m_id = (int)fpid_as_uint; + d->m_id = (int)fpid_as_uint; return; } @@ -298,3 +334,30 @@ qWarning() << "Response is bad:" << response; throw BadResponseError; } + + +lastfm::CompleteFingerprint::CompleteFingerprint( const lastfm::Track& t ) : Fingerprint( t ) +{ + d->m_complete = true; +} + + +lastfm::CompleteFingerprint::~CompleteFingerprint() +{ +} + + +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 +} diff -Nru liblastfm-0.4.0~really0.3.3/src/fingerprint/Fingerprint.h liblastfm-1.0.1/src/fingerprint/Fingerprint.h --- liblastfm-0.4.0~really0.3.3/src/fingerprint/Fingerprint.h 2010-09-25 17:30:01.000000000 +0000 +++ liblastfm-1.0.1/src/fingerprint/Fingerprint.h 2012-06-18 10:37:51.000000000 +0000 @@ -20,21 +20,17 @@ #ifndef LASTFM_FINGERPRINT_H #define LASTFM_FINGERPRINT_H -#include -#include - +#include "FingerprintId.h" namespace lastfm { - class LASTFM_DLLEXPORT Fingerprint - { - lastfm::Track m_track; - QByteArray m_data; - int m_id; - int m_duration; + class FingerprintableSource; + class Track; + class LASTFM_FINGERPRINT_DLLEXPORT Fingerprint + { protected: - bool m_complete; + class FingerprintPrivate * const d; public: /** represents a partial fingerprint of 20 seconds of music, this is @@ -42,13 +38,14 @@ * it is much quicker than a complete fingerprint, still though, you * should do the generate step in a thread. */ Fingerprint( const lastfm::Track& ); + ~Fingerprint(); /** if the id isNull(), then you'll need to do generate, submit and decode */ - FingerprintId id() const { return m_id; } + FingerprintId id() const; /** 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; } + QByteArray data() const; enum Error { @@ -87,30 +84,14 @@ }; - class CompleteFingerprint : public Fingerprint + class LASTFM_FINGERPRINT_DLLEXPORT CompleteFingerprint : public Fingerprint { - public: - CompleteFingerprint( const lastfm::Track& t ) : Fingerprint( t ) - { - m_complete = true; - } + CompleteFingerprint( const lastfm::Track& t ); + ~CompleteFingerprint(); }; } -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 -} +QDebug operator<<( QDebug d, lastfm::Fingerprint::Error e ); #endif diff -Nru liblastfm-0.4.0~really0.3.3/src/fingerprint/fingerprint.pro liblastfm-1.0.1/src/fingerprint/fingerprint.pro --- liblastfm-0.4.0~really0.3.3/src/fingerprint/fingerprint.pro 2010-09-25 17:30:01.000000000 +0000 +++ liblastfm-1.0.1/src/fingerprint/fingerprint.pro 1970-01-01 00:00:00.000000000 +0000 @@ -1,28 +0,0 @@ -TEMPLATE = lib -TARGET = lastfm_fingerprint -LIBS += -L$$DESTDIR -llastfm -QT = core xml network sql -include( _files.qmake ) -DEFINES += LASTFM_OHAI_QMAKE - -INSTALLS = target -target.path = /lib - -mac:CONFIG( app_bundle ) { - LIBS += libfftw3f.a libsamplerate.a -L/opt/local/include - INCLUDEPATH += /opt/local/include -}else{ - CONFIG += link_pkgconfig - PKGCONFIG += samplerate - win32 { - CONFIG += link_pkgconfig - PKGCONFIG += fftw3 - DEFINES += __NO_THREAD_CHECK - QMAKE_LFLAGS_DEBUG += /NODEFAULTLIB:msvcrt.lib /NODEFAULTLIB:libcmt.lib - }else{ - # the difference with win32 is that windows doesn't have the f suffix - # but I think this may be because doug didn't compile it with single - # precision, and I'm not sure if that matters or not - PKGCONFIG += fftw3f - } -} \ No newline at end of file diff -Nru liblastfm-0.4.0~really0.3.3/src/FingerprintId.cpp liblastfm-1.0.1/src/FingerprintId.cpp --- liblastfm-0.4.0~really0.3.3/src/FingerprintId.cpp 1970-01-01 00:00:00.000000000 +0000 +++ liblastfm-1.0.1/src/FingerprintId.cpp 2012-06-18 10:37:51.000000000 +0000 @@ -0,0 +1,124 @@ +/* + 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.h" +#include +#include + + +class lastfm::FingerprintIdPrivate +{ +public: + int id; +}; + + +lastfm::FingerprintId::FingerprintId() + : d( new FingerprintIdPrivate ) +{ + d->id = -1; +} + + +lastfm::FingerprintId::FingerprintId( uint i ) + : d( new FingerprintIdPrivate ) +{ + d->id = i; +} + + +lastfm::FingerprintId::FingerprintId( const FingerprintId& that ) + : d( new FingerprintIdPrivate( *that.d ) ) +{ +} + + +lastfm::FingerprintId::~FingerprintId() +{ + delete d; +} + + +bool +lastfm::FingerprintId::isNull() const +{ + return d->id == -1; +} + + +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; +} + + +lastfm::FingerprintId::operator int() const +{ + return d->id; +} + + +lastfm::FingerprintId::operator QString() const +{ + return d->id == -1 ? "" : QString::number( d->id ); +} + +lastfm::FingerprintId& +lastfm::FingerprintId::operator=( const FingerprintId& that ) +{ + d->id = that.d->id; + return *this; +} + + +QDebug +operator<<( QDebug d, lastfm::FingerprintId id) +{ + if (id.isNull()) + return d << "(null)"; + else + return d << int(id); +} diff -Nru liblastfm-0.4.0~really0.3.3/src/FingerprintId.h liblastfm-1.0.1/src/FingerprintId.h --- liblastfm-0.4.0~really0.3.3/src/FingerprintId.h 1970-01-01 00:00:00.000000000 +0000 +++ liblastfm-1.0.1/src/FingerprintId.h 2012-06-18 10:37:51.000000000 +0000 @@ -0,0 +1,57 @@ +/* + 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 "Track.h" + +namespace lastfm +{ + class LASTFM_DLLEXPORT FingerprintId + { + public: + FingerprintId(); + FingerprintId( uint i ); + FingerprintId( const FingerprintId& other ); + + ~FingerprintId(); + + bool isNull() const; + + /** 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; + /** isEmpty() if you need to generate it */ + operator QString() const; + FingerprintId& operator=( const FingerprintId& other ); + + private: + class FingerprintIdPrivate * const d; + }; +} + + +LASTFM_DLLEXPORT QDebug operator<<( QDebug d, lastfm::FingerprintId id); + +#endif diff -Nru liblastfm-0.4.0~really0.3.3/src/global.h liblastfm-1.0.1/src/global.h --- liblastfm-0.4.0~really0.3.3/src/global.h 2010-09-25 17:30:01.000000000 +0000 +++ liblastfm-1.0.1/src/global.h 2012-06-18 10:37:51.000000000 +0000 @@ -21,26 +21,29 @@ #ifndef LASTFM_GLOBAL_H #define LASTFM_GLOBAL_H -#define LASTFM_VERSION 0x00000303 -#define LASTFM_VERSION_STRING "0.3.3" -#define LASTFM_MAJOR_VERSION 0 -#define LASTFM_MINOR_VERSION 3 -#define LASTFM_PATCH_VERSION 3 +#define LASTFM_VERSION 0x00010000 +#define LASTFM_VERSION_STRING "1.0.0" +#define LASTFM_MAJOR_VERSION 1 +#define LASTFM_MINOR_VERSION 0 +#define LASTFM_PATCH_VERSION 0 -#include - -#ifdef Q_CC_MSVC - #ifdef LASTFM_OHAI_QMAKE - #define LASTFM_DLLEXPORT __declspec(dllexport) +#ifndef LASTFM_LIB_STATIC + #ifdef LASTFM_LIB + #define LASTFM_DLLEXPORT Q_DECL_EXPORT #else - #define LASTFM_DLLEXPORT __declspec(dllimport) + #define LASTFM_DLLEXPORT Q_DECL_IMPORT #endif -#elif __GNUC__ >= 4 - #define LASTFM_DLLEXPORT __attribute__ ((visibility("default"))) -#else + #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 -#endif + #define LASTFM_FINGERPRINT_DLLEXPORT +#endif // LASTFM_LIB_STATIC + #include @@ -64,66 +67,12 @@ } return QString("Unknown enum value for \"%1\": %2").arg( enum_name ).arg( enum_value ); } - - - enum ImageSize - { - Small = 0, - Medium = 1, - Large = 2, /** seemingly 174x174 */ - ExtraLarge = 3 - }; - - - //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 Scrobble; - 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::Scrobble; -using lastfm::Tag; -using lastfm::Track; -using lastfm::XmlQuery; -using lastfm::Xspf; +using namespace ::lastfm; #endif -//convenience -class QDomDocument; -class QNetworkAccessManager; -class QNetworkReply; - - -//convenience for development -#include - #endif //LASTFM_GLOBAL_H diff -Nru liblastfm-0.4.0~really0.3.3/src/InternetConnectionMonitor.cpp liblastfm-1.0.1/src/InternetConnectionMonitor.cpp --- liblastfm-0.4.0~really0.3.3/src/InternetConnectionMonitor.cpp 1970-01-01 00:00:00.000000000 +0000 +++ liblastfm-1.0.1/src/InternetConnectionMonitor.cpp 2012-06-18 10:37:51.000000000 +0000 @@ -0,0 +1,143 @@ +/* + 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" + +#include + +class lastfm::InternetConnectionMonitorPrivate +{ +public: + bool m_up; + NetworkConnectionMonitor* m_networkMonitor; +}; + +lastfm::InternetConnectionMonitor::InternetConnectionMonitor( QObject *parent ) + : QObject( parent ) + , d( new InternetConnectionMonitorPrivate) +{ + d->m_up = true; + d->m_networkMonitor = createNetworkConnectionMonitor(); + + if ( d->m_networkMonitor ) + { + connect( d->m_networkMonitor, SIGNAL( networkUp() ), this, SLOT( onNetworkUp() ) ); + connect( d->m_networkMonitor, SIGNAL( networkDown() ), this, SLOT( onNetworkDown() ) ); + } + + connect( nam(), SIGNAL( finished( QNetworkReply* ) ), this, SLOT( onFinished( QNetworkReply* ) ) ); +} + +lastfm::InternetConnectionMonitor::~InternetConnectionMonitor() +{ + delete d; +} + +bool lastfm::InternetConnectionMonitor::isDown() const +{ + return !d->m_up; +} + +bool lastfm::InternetConnectionMonitor::isUp() const +{ + return d->m_up; +} + +void +lastfm::InternetConnectionMonitor::onFinished( QNetworkReply* reply ) +{ + if( reply->attribute( QNetworkRequest::SourceIsFromCacheAttribute).toBool() ) return; + + switch( reply->error() ) + { + case QNetworkReply::NoError: + if ( !d->m_up ) + { + d->m_up = true; + emit up(); + emit connectivityChanged( d->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 ( d->m_up ) + { + d->m_up = false; + emit down(); + emit connectivityChanged( d->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 + d->m_up = true; + + emit up(); + emit connectivityChanged( d->m_up ); + qDebug() << "Internet connection is reachable :)"; +#else + qDebug() << "Network seems to be up again. Let's try if there's internet connection!"; + nam()->head( QNetworkRequest( QUrl( tr( "http://www.last.fm/" ) ) ) ); +#endif +} + +void +lastfm::InternetConnectionMonitor::onNetworkDown() +{ + qDebug() << "Internet is unreachable :("; + d->m_up = false; + emit down(); + emit connectivityChanged( d->m_up ); +} + +lastfm::NetworkConnectionMonitor* +lastfm::InternetConnectionMonitor::createNetworkConnectionMonitor() +{ + NetworkConnectionMonitor* ncm = 0; + +#ifdef Q_WS_X11 + ncm = new LNetworkConnectionMonitor( this ); +#elif defined(Q_WS_WIN) && ! defined __MINGW32__ + ncm = new WNetworkConnectionMonitor( this ); +#elif defined(Q_WS_MAC) + ncm = new MNetworkConnectionMonitor( this ); +#endif + + return ncm; +} diff -Nru liblastfm-0.4.0~really0.3.3/src/InternetConnectionMonitor.h liblastfm-1.0.1/src/InternetConnectionMonitor.h --- liblastfm-0.4.0~really0.3.3/src/InternetConnectionMonitor.h 1970-01-01 00:00:00.000000000 +0000 +++ liblastfm-1.0.1/src/InternetConnectionMonitor.h 2012-06-18 10:37:51.000000000 +0000 @@ -0,0 +1,70 @@ +/* + 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 "global.h" +#include + +class QNetworkReply; + +namespace lastfm { + +class NetworkConnectionMonitor; + +class LASTFM_DLLEXPORT InternetConnectionMonitor : public QObject +{ + Q_OBJECT + +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 ); + ~InternetConnectionMonitor(); + + bool isDown() const; + bool isUp() const; + + 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: + class InternetConnectionMonitorPrivate * const d; +}; + +} //namespace lastfm + +#endif diff -Nru liblastfm-0.4.0~really0.3.3/src/lastfm.pro liblastfm-1.0.1/src/lastfm.pro --- liblastfm-0.4.0~really0.3.3/src/lastfm.pro 2010-09-25 17:30:01.000000000 +0000 +++ liblastfm-1.0.1/src/lastfm.pro 1970-01-01 00:00:00.000000000 +0000 @@ -1,16 +0,0 @@ -TEMPLATE = lib -QT = core network xml -include( _files.qmake ) - -INSTALLS = target -target.path = /lib - -win32{ - DEFINES += LASTFM_OHAI_QMAKE _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 -} diff -Nru liblastfm-0.4.0~really0.3.3/src/Library.cpp liblastfm-1.0.1/src/Library.cpp --- liblastfm-0.4.0~really0.3.3/src/Library.cpp 1970-01-01 00:00:00.000000000 +0000 +++ liblastfm-1.0.1/src/Library.cpp 2012-06-18 10:37:51.000000000 +0000 @@ -0,0 +1,155 @@ +/* + Copyright 2011 Last.fm Ltd. + - Primarily authored by 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 "Library.h" +#include "ws.h" + +#include + + +lastfm::Library::Library() +{ +} + +QNetworkReply* +lastfm::Library::addAlbum( const QList& albums ) +{ + QMap map; + map["method"] = "library.addAlbum"; + + for ( int i = 0 ; i < albums.count() ; ++i ) + { + map["artist[" + QString::number(i) + "]"] = albums[i].artist(); + map["album[" + QString::number(i) + "]"] = albums[i].title(); + } + + return ws::post( map ); +} + +QNetworkReply* +lastfm::Library::addArtist( const QList& artists ) +{ + QMap map; + map["method"] = "library.addArtist"; + + for ( int i = 0 ; i < artists.count() ; ++i ) + map["artist[" + QString::number(i) + "]"] = artists[i].name(); + + return ws::post( map ); +} + +QNetworkReply* +lastfm::Library::addTrack( const Track &track ) +{ + QMap map; + map["method"] = "library.addTrack"; + map["track"] = track.title(); + map["artist"] = track.artist().name(); + return ws::post( map ); +} + +QNetworkReply* +lastfm::Library::getAlbums( const QString& user, const lastfm::Artist& artist, int limit, int page ) +{ + QMap map; + map["method"] = "library.getAlbums"; + map["user"] = user; + map["artist"] = artist.name(); + if ( page != -1 ) map["page"] = QString::number( page ); + if ( limit != -1 ) map["limit"] = QString::number( limit ); + return ws::post( map ); +} + +QNetworkReply* +lastfm::Library::getArtists( const QString& user, int limit, int page ) +{ + QMap map; + map["method"] = "library.getArtists"; + map["user"] = user; + if ( page != -1 ) map["page"] = QString::number( page ); + if ( limit != -1 ) map["limit"] = QString::number( limit ); + return ws::post( map ); +} + +QNetworkReply* +lastfm::Library::getTracks( const QString& user, const lastfm::Artist& artist, int limit, int page ) +{ + QMap map; + map["method"] = "library.getTracks"; + map["user"] = user; + map["artist"] = artist.name(); + map["limit"] = QString::number( limit ); + map["page"] = QString::number( page ); + return ws::post( map ); +} + +QNetworkReply* +lastfm::Library::getTracks( const QString& user, const lastfm::Album& album, int limit, int page ) +{ + QMap map; + map["method"] = "library.getTracks"; + map["user"] = user; + map["album"] = album.title(); + map["artist"] = album.artist().name(); + if ( page != -1 ) map["page"] = QString::number( page ); + if ( limit != -1 ) map["limit"] = QString::number( limit ); + return ws::post( map ); +} + +QNetworkReply* +lastfm::Library::removeAlbum( const lastfm::Album& album ) +{ + QMap map; + map["method"] = "library.removeAlbum"; + map["album"] = album.title(); + map["artist"] = album.artist().name(); + return ws::post( map ); +} + +QNetworkReply* +lastfm::Library::removeArtist( const lastfm::Artist& artist ) +{ + QMap map; + map["method"] = "library.removeArtist"; + map["artist"] = artist.name(); + return ws::post( map ); +} + +QNetworkReply* +lastfm::Library::removeTrack( const lastfm::Track& track ) +{ + QMap map; + map["method"] = "library.removeTrack"; + map["artist"] = track.artist().name(); + map["track"] = track.title(); + return ws::post( map ); +} + +QNetworkReply* +lastfm::Library::removeScrobble( const lastfm::Track& track ) +{ + QMap map; + map["method"] = "library.removeScrobble"; + map["artist"] = track.artist().name(); + map["track"] = track.title(); + map["timestamp"] = QString::number( track.timestamp().toTime_t() ); + return ws::post( map ); +} + diff -Nru liblastfm-0.4.0~really0.3.3/src/Library.h liblastfm-1.0.1/src/Library.h --- liblastfm-0.4.0~really0.3.3/src/Library.h 1970-01-01 00:00:00.000000000 +0000 +++ liblastfm-1.0.1/src/Library.h 2012-06-18 10:37:51.000000000 +0000 @@ -0,0 +1,51 @@ +/* + Copyright 2011 Last.fm Ltd. + - Primarily authored by 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_LIBRARY_H +#define LASTFM_LIBRARY_H + +#include "Track.h" + +namespace lastfm +{ + class LASTFM_DLLEXPORT Library + { + private: + Library(); + + public: + static QNetworkReply* addAlbum( const QList& albums ); + static QNetworkReply* addArtist( const QList& artists ); + static QNetworkReply* addTrack( const lastfm::Track& tracks ); + + static QNetworkReply* getAlbums( const QString& user, const lastfm::Artist& artist = lastfm::Artist(), int limit = -1, int page = -1 ); + static QNetworkReply* getArtists( const QString& user, int limit = -1, int page = -1 ); + static QNetworkReply* getTracks( const QString& user, const lastfm::Artist& artist = lastfm::Artist(), int limit = -1, int page = -1 ); + static QNetworkReply* getTracks( const QString& user, const lastfm::Album& album = lastfm::Album(), int limit = -1, int page = -1 ); + + static QNetworkReply* removeAlbum( const lastfm::Album& album ); + static QNetworkReply* removeArtist( const lastfm::Artist& artist ); + static QNetworkReply* removeTrack( const lastfm::Track& track ); + + static QNetworkReply* removeScrobble( const lastfm::Track& track ); + }; +} + +#endif // LASTFM_LIBRARY_H + diff -Nru liblastfm-0.4.0~really0.3.3/src/linux/LNetworkConnectionMonitor.h liblastfm-1.0.1/src/linux/LNetworkConnectionMonitor.h --- liblastfm-0.4.0~really0.3.3/src/linux/LNetworkConnectionMonitor.h 1970-01-01 00:00:00.000000000 +0000 +++ liblastfm-1.0.1/src/linux/LNetworkConnectionMonitor.h 2012-06-18 10:37:51.000000000 +0000 @@ -0,0 +1,61 @@ +/* + 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 "../global.h" + +class QDBusConnection; +class QDBusInterface; + +namespace lastfm +{ + +class LNetworkConnectionMonitor : public NetworkConnectionMonitor +{ + Q_OBJECT + + typedef enum { + NM_STATE_UNKNOWN = 0, + NM_STATE_ASLEEP = 10, + NM_STATE_DISCONNECTED = 20, + NM_STATE_DISCONNECTING = 30, + NM_STATE_CONNECTING = 40, + NM_STATE_CONNECTED_LOCAL = 50, + NM_STATE_CONNECTED_SITE = 60, + NM_STATE_CONNECTED_GLOBAL = 70 + } NMState; + +public: + LNetworkConnectionMonitor( QObject* parent = 0 ); + ~LNetworkConnectionMonitor(); +private slots: + void onStateChange( uint newState ); +private: + QDBusInterface* m_nmInterface; +}; + +} + +#endif // LNETWORK_CONNECTION_MONITOR_H + diff -Nru liblastfm-0.4.0~really0.3.3/src/linux/LNetworkConnectionMonitor_linux.cpp liblastfm-1.0.1/src/linux/LNetworkConnectionMonitor_linux.cpp --- liblastfm-0.4.0~really0.3.3/src/linux/LNetworkConnectionMonitor_linux.cpp 1970-01-01 00:00:00.000000000 +0000 +++ liblastfm-1.0.1/src/linux/LNetworkConnectionMonitor_linux.cpp 2012-06-18 10:37:51.000000000 +0000 @@ -0,0 +1,92 @@ +/* + 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 +#include + +#define NM_DBUS_SERVICE "org.freedesktop.NetworkManager" +#define NM_DBUS_PATH "/org/freedesktop/NetworkManager" +#define NM_DBUS_INTERFACE "org.freedesktop.NetworkManager" + +lastfm::LNetworkConnectionMonitor::LNetworkConnectionMonitor( QObject* parent ) : + NetworkConnectionMonitor( parent ) +{ + m_nmInterface = new QDBusInterface( NM_DBUS_SERVICE, + NM_DBUS_PATH, + NM_DBUS_INTERFACE, + QDBusConnection::systemBus(), + this ); + + //get current connection state + QDBusReply reply = m_nmInterface->call( QDBus::AutoDetect, "state" ); + if ( reply.isValid() ) + { + if ( reply.value() == NM_STATE_CONNECTED_GLOBAL ) + { + setConnected( true ); + } + else if ( reply.value() == NM_STATE_DISCONNECTED || reply.value() == NM_STATE_ASLEEP ) + { + setConnected( false ); + } + } + else + { + qDebug() << "Error: " << reply.error(); + } + + //connect network manager signals + m_nmInterface->connection().connect( NM_DBUS_SERVICE, + NM_DBUS_PATH, + NM_DBUS_INTERFACE, + "StateChanged", + this, + SLOT( onStateChange( uint ) ) + ); + +} + +lastfm::LNetworkConnectionMonitor::~LNetworkConnectionMonitor() +{ + delete m_nmInterface; +} + + +void +lastfm::LNetworkConnectionMonitor::onStateChange( uint newState ) +{ + qDebug() << "Networkmanager state change!"; + + if ( newState == NM_STATE_DISCONNECTED || newState == NM_STATE_ASLEEP ) + { + setConnected( false ); + } + else if ( newState == NM_STATE_CONNECTED_GLOBAL ) + { + setConnected( true ); + } +} + +#include "moc_LNetworkConnectionMonitor.cpp" diff -Nru liblastfm-0.4.0~really0.3.3/src/mac/MNetworkConnectionMonitor.h liblastfm-1.0.1/src/mac/MNetworkConnectionMonitor.h --- liblastfm-0.4.0~really0.3.3/src/mac/MNetworkConnectionMonitor.h 1970-01-01 00:00:00.000000000 +0000 +++ liblastfm-1.0.1/src/mac/MNetworkConnectionMonitor.h 2012-06-18 10:37:51.000000000 +0000 @@ -0,0 +1,55 @@ +/* + 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" + +#ifdef Q_WS_MAC +#include //TODO remove +#include +#endif + +class __SCNetworkReachability; + +namespace lastfm +{ + +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 -Nru liblastfm-0.4.0~really0.3.3/src/mac/MNetworkConnectionMonitor_mac.cpp liblastfm-1.0.1/src/mac/MNetworkConnectionMonitor_mac.cpp --- liblastfm-0.4.0~really0.3.3/src/mac/MNetworkConnectionMonitor_mac.cpp 1970-01-01 00:00:00.000000000 +0000 +++ liblastfm-1.0.1/src/mac/MNetworkConnectionMonitor_mac.cpp 2012-06-18 10:37:51.000000000 +0000 @@ -0,0 +1,70 @@ +/* + 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 "moc_MNetworkConnectionMonitor.cpp" +#include "../ws.h" + +#include +#include + +lastfm::MNetworkConnectionMonitor* context = 0; + +lastfm::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 ); +} + +lastfm::MNetworkConnectionMonitor::~MNetworkConnectionMonitor() +{ +} + + +void +lastfm::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 -Nru liblastfm-0.4.0~really0.3.3/src/mac/ProxyDict.h liblastfm-1.0.1/src/mac/ProxyDict.h --- liblastfm-0.4.0~really0.3.3/src/mac/ProxyDict.h 1970-01-01 00:00:00.000000000 +0000 +++ liblastfm-1.0.1/src/mac/ProxyDict.h 2012-06-18 10:37:51.000000000 +0000 @@ -0,0 +1,75 @@ +/* + 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 -Nru liblastfm-0.4.0~really0.3.3/src/Mbid.cpp liblastfm-1.0.1/src/Mbid.cpp --- liblastfm-0.4.0~really0.3.3/src/Mbid.cpp 1970-01-01 00:00:00.000000000 +0000 +++ liblastfm-1.0.1/src/Mbid.cpp 2012-06-18 10:37:51.000000000 +0000 @@ -0,0 +1,86 @@ +/* + 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 +{ + +class MbidPrivate +{ +public: + QString id; +}; + + +Mbid::Mbid( const QString& p ) + : d( new MbidPrivate ) +{ + d->id = p; +} + + +Mbid::Mbid( const Mbid& that ) + : d( new MbidPrivate( *that.d ) ) +{ +} + + +Mbid::~Mbid() +{ + delete d; +} + + +bool +Mbid::isNull() const +{ + return d->id.isNull() || d->id.isEmpty(); +} + + +Mbid::operator QString() const +{ + return d->id; +} + + +Mbid& +Mbid::operator=( const Mbid& that ) +{ + d->id = that.d->id; + return *this; +} + + +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.d->id = QString::fromLatin1( out ); + return mbid; +} + +} diff -Nru liblastfm-0.4.0~really0.3.3/src/Mbid.h liblastfm-1.0.1/src/Mbid.h --- liblastfm-0.4.0~really0.3.3/src/Mbid.h 1970-01-01 00:00:00.000000000 +0000 +++ liblastfm-1.0.1/src/Mbid.h 2012-06-18 10:37:51.000000000 +0000 @@ -0,0 +1,46 @@ +/* + 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 "global.h" + +namespace lastfm +{ + class LASTFM_DLLEXPORT Mbid + { + public: + explicit Mbid( const QString& p = "" ); + Mbid( const Mbid& that ); + ~Mbid(); + + bool isNull() const; + operator QString() const; + Mbid& operator=( const Mbid& that ); + + /** 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 ); + private: + class MbidPrivate * const d; + }; +} + +#endif diff -Nru liblastfm-0.4.0~really0.3.3/src/mbid_mp3.c liblastfm-1.0.1/src/mbid_mp3.c --- liblastfm-0.4.0~really0.3.3/src/mbid_mp3.c 1970-01-01 00:00:00.000000000 +0000 +++ liblastfm-1.0.1/src/mbid_mp3.c 2012-06-18 10:37:51.000000000 +0000 @@ -0,0 +1,183 @@ +/* +* 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 + +#include + +// ----------------------------------------------------------------------------- + +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 -Nru liblastfm-0.4.0~really0.3.3/src/misc.cpp liblastfm-1.0.1/src/misc.cpp --- liblastfm-0.4.0~really0.3.3/src/misc.cpp 1970-01-01 00:00:00.000000000 +0000 +++ liblastfm-1.0.1/src/misc.cpp 2012-06-18 10:37:51.000000000 +0000 @@ -0,0 +1,222 @@ +/* + 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 +#include +#include +#ifdef WIN32 + #include +#endif + + +#ifdef Q_WS_MAC +#include + +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 + + +const char* +lastfm::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_WINDOWS7: return "Windows 7"; + 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"; + case QSysInfo::MV_10_6: return "Mac OS X 10.6"; + case QSysInfo::MV_10_7: return "Mac OS X 10.7"; + + default: return "Unknown"; + } +#elif defined Q_WS_X11 + return "UNIX X11"; +#else + return "Unknown"; +#endif +} + +QString lastfm:: +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 +QString +lastfm::CFStringToQString( CFStringRef s ) +{ + return QString::fromUtf8( CFStringToUtf8( s ) ); +} +#endif + diff -Nru liblastfm-0.4.0~really0.3.3/src/misc.h liblastfm-1.0.1/src/misc.h --- liblastfm-0.4.0~really0.3.3/src/misc.h 1970-01-01 00:00:00.000000000 +0000 +++ liblastfm-1.0.1/src/misc.h 2012-06-18 10:37:51.000000000 +0000 @@ -0,0 +1,53 @@ +/* + 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 "global.h" +#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& ); + LASTFM_DLLEXPORT QString CFStringToQString( CFStringRef s ); +#endif + LASTFM_DLLEXPORT const char* platform(); + LASTFM_DLLEXPORT QString md5( const QByteArray& src ); +} +#endif //LASTFM_MISC_H diff -Nru liblastfm-0.4.0~really0.3.3/src/NetworkAccessManager.cpp liblastfm-1.0.1/src/NetworkAccessManager.cpp --- liblastfm-0.4.0~really0.3.3/src/NetworkAccessManager.cpp 1970-01-01 00:00:00.000000000 +0000 +++ liblastfm-1.0.1/src/NetworkAccessManager.cpp 2012-06-18 10:37:51.000000000 +0000 @@ -0,0 +1,159 @@ +/* + 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 "ws.h" +#include "misc.h" +#include +#include +#if defined WIN32 && ! defined __MINGW32__ + #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() + { + #if defined WIN32 && ! defined __MINGW32__ + 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(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 ) + #if defined WIN32 && ! defined __MINGW32__ + , 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() +{ +#if defined WIN32 && ! defined __MINGW32__ + delete m_pac; +#endif +} + + +QNetworkProxy +lastfm::NetworkAccessManager::proxy( const QNetworkRequest& request ) +{ + Q_UNUSED( request ); + +#if defined WIN32 && ! defined __MINGW32__ + 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 ); + +#if defined WIN32 && ! defined __MINGW32__ + if (up && m_pac) m_pac->resetFailedState(); +#endif +} diff -Nru liblastfm-0.4.0~really0.3.3/src/NetworkAccessManager.h liblastfm-1.0.1/src/NetworkAccessManager.h --- liblastfm-0.4.0~really0.3.3/src/NetworkAccessManager.h 1970-01-01 00:00:00.000000000 +0000 +++ liblastfm-1.0.1/src/NetworkAccessManager.h 2012-06-18 10:37:51.000000000 +0000 @@ -0,0 +1,67 @@ +/* + 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 "global.h" +#include +#include +#include + +class QNetworkReply; + +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 -Nru liblastfm-0.4.0~really0.3.3/src/NetworkConnectionMonitor.cpp liblastfm-1.0.1/src/NetworkConnectionMonitor.cpp --- liblastfm-0.4.0~really0.3.3/src/NetworkConnectionMonitor.cpp 1970-01-01 00:00:00.000000000 +0000 +++ liblastfm-1.0.1/src/NetworkConnectionMonitor.cpp 2012-06-18 10:37:51.000000000 +0000 @@ -0,0 +1,59 @@ +/* + 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" + +class lastfm::NetworkConnectionMonitorPrivate +{ + public: + bool connected; +}; + +lastfm::NetworkConnectionMonitor::NetworkConnectionMonitor( QObject* /*parent*/ ) + : d( new NetworkConnectionMonitorPrivate ) +{ + d->connected = true; +} + +lastfm::NetworkConnectionMonitor::~NetworkConnectionMonitor() +{ + delete d; +} + +bool +lastfm::NetworkConnectionMonitor::isConnected() const +{ + return d->connected; +} + +void +lastfm::NetworkConnectionMonitor::setConnected( bool connected ) +{ + if ( d->connected != connected ) + { + d->connected = connected; + + if ( connected ) + emit networkUp(); + else + emit networkDown(); + } +} + diff -Nru liblastfm-0.4.0~really0.3.3/src/NetworkConnectionMonitor.h liblastfm-1.0.1/src/NetworkConnectionMonitor.h --- liblastfm-0.4.0~really0.3.3/src/NetworkConnectionMonitor.h 1970-01-01 00:00:00.000000000 +0000 +++ liblastfm-1.0.1/src/NetworkConnectionMonitor.h 2012-06-18 10:37:51.000000000 +0000 @@ -0,0 +1,51 @@ +/* + 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 "global.h" +#include + +namespace lastfm +{ + +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: + class NetworkConnectionMonitorPrivate * const d; +}; + +} + +#endif // NETWORK_CONNECTION_MONITOR_H diff -Nru liblastfm-0.4.0~really0.3.3/src/Playlist.cpp liblastfm-1.0.1/src/Playlist.cpp --- liblastfm-0.4.0~really0.3.3/src/Playlist.cpp 1970-01-01 00:00:00.000000000 +0000 +++ liblastfm-1.0.1/src/Playlist.cpp 2012-06-18 10:37:51.000000000 +0000 @@ -0,0 +1,111 @@ +/* + 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.h" + + +class lastfm::PlaylistPrivate +{ + public: + int id; +}; + + +lastfm::Playlist::Playlist() + : d( new PlaylistPrivate ) +{ + d->id = -1; +} + + +lastfm::Playlist::Playlist( const Playlist& that ) + : d( new PlaylistPrivate( *that.d ) ) +{ +} + + +lastfm::Playlist::~Playlist() +{ + delete d; +} + + +lastfm::Playlist::Playlist( int id ) + : d( new PlaylistPrivate ) +{ + d->id = id; +} + + +int +lastfm::Playlist::id() const +{ + return d->id; +} + + +QNetworkReply* +lastfm::Playlist::addTrack( const Track& t ) const +{ + QMap map; + map["method"] = "playlist.addTrack"; + map["playlistID"] = d->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( d->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); +} + + +lastfm::Playlist& +lastfm::Playlist::operator=( const Playlist& that ) +{ + d->id = that.d->id; + return *this; +} diff -Nru liblastfm-0.4.0~really0.3.3/src/Playlist.h liblastfm-1.0.1/src/Playlist.h --- liblastfm-0.4.0~really0.3.3/src/Playlist.h 1970-01-01 00:00:00.000000000 +0000 +++ liblastfm-1.0.1/src/Playlist.h 2012-06-18 10:37:51.000000000 +0000 @@ -0,0 +1,49 @@ +/* + 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 "Xspf.h" + +namespace lastfm +{ + class LASTFM_DLLEXPORT Playlist + { + Playlist(); + class PlaylistPrivate * const d; + + public: + Playlist( int id ); + Playlist( const Playlist& that ); + ~Playlist(); + + int id() const; + + QNetworkReply* addTrack( const Track& ) const; + QNetworkReply* fetch() const; + + static QNetworkReply* create( const QString& title, const QString& description = "" ); + static QNetworkReply* fetch( const QUrl& url ); + + Playlist& operator=( const Playlist& that ); + }; +} + +#endif diff -Nru liblastfm-0.4.0~really0.3.3/src/radio/RadioStation.cpp liblastfm-1.0.1/src/radio/RadioStation.cpp --- liblastfm-0.4.0~really0.3.3/src/radio/RadioStation.cpp 2010-09-25 17:30:01.000000000 +0000 +++ liblastfm-1.0.1/src/radio/RadioStation.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,40 +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 "RadioStation.h" -#include "../core/XmlQuery.h" - -//static -QList -lastfm::RadioStation::list( QNetworkReply* r ) -{ - QList result; - try { - foreach (XmlQuery xq, XmlQuery(ws::parse(r)).children("station")) { - lastfm::RadioStation rs(xq["url"].text()); - rs.setTitle(xq["name"].text()); - result.append(rs); - } - } - catch (ws::ParseError& e) - { - qWarning() << e.what(); - } - return result; -} diff -Nru liblastfm-0.4.0~really0.3.3/src/radio/RadioStation.h liblastfm-1.0.1/src/radio/RadioStation.h --- liblastfm-0.4.0~really0.3.3/src/radio/RadioStation.h 2010-09-25 17:30:01.000000000 +0000 +++ liblastfm-1.0.1/src/radio/RadioStation.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,96 +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 ) : m_url( s ) - {} - explicit RadioStation( const QUrl& u ) : m_url( u.toString() ) - {} - - static RadioStation library( const lastfm::User& user ) { return "lastfm://user/" + user + "/personal"; } - static RadioStation recommendations( const lastfm::User& user ) { return "lastfm://user/" + user + "/recommended"; } - static RadioStation neighbourhood( const lastfm::User& user ) { return "lastfm://user/" + user + "/neighbours"; } - static RadioStation lovedTracks( const lastfm::User& user ) { return "lastfm://user/" + user + "/loved"; } - static RadioStation globalTag( const lastfm::Tag& tag ) { return "lastfm://globaltags/" + tag; } - static RadioStation similar( const lastfm::Artist& artist ) { return "lastfm://artist/" + artist + "/similarartists"; } - - static RadioStation rql( const QString& rql ) - { - RadioStation station; - station.m_rql = rql; - station.m_url = "lastfm://rql/" + QString(rql.toUtf8().toBase64()); - return station; - } - - /** 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 { return m_title; } - /** the Last.fm url, eg. lastfm://user/mxcl/loved */ - QString url() const { return m_url; } - QString rql() const { return m_rql; } - - void setTitle( const QString& s ) { m_title = s; } - - bool isLegacyPlaylist() const - { - return m_url.startsWith( "lastfm://play/" ) || - m_url.startsWith( "lastfm://preview/" ) || - m_url.startsWith( "lastfm://track/" ) || - m_url.startsWith( "lastfm://playlist/" ); - } - - // good for getRecentStations: - static QList list( QNetworkReply* ); - - private: - QString m_rql; - QString m_url; - QString m_title; - }; -} - - -Q_DECLARE_METATYPE( lastfm::RadioStation ) - - -inline QDebug operator<<( QDebug d, const lastfm::RadioStation& station ) -{ - return d << station.url(); -} - -#endif diff -Nru liblastfm-0.4.0~really0.3.3/src/radio/RadioTuner.cpp liblastfm-1.0.1/src/radio/RadioTuner.cpp --- liblastfm-0.4.0~really0.3.3/src/radio/RadioTuner.cpp 2010-09-25 17:30:01.000000000 +0000 +++ liblastfm-1.0.1/src/radio/RadioTuner.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,120 +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 "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) - - -RadioTuner::RadioTuner( const RadioStation& station ) - : m_retry_counter( 0 ) -{ - QMap map; - map["method"] = "radio.tune"; - map["station"] = station.url(); - QNetworkReply* reply = ws::post(map); - connect( reply, SIGNAL(finished()), SLOT(onTuneReturn()) ); -} - - -void -RadioTuner::onTuneReturn() -{ - try { - XmlQuery lfm = ws::parse( (QNetworkReply*)sender() ); - emit title( lfm["station"]["name"].text() ); - fetchFiveMoreTracks(); - } - catch (ws::ParseError& e) - { - emit error( e.enumValue() ); - } -} - - -bool -RadioTuner::fetchFiveMoreTracks() -{ - //TODO check documentation, I figure this needs a session key - QMap map; - map["method"] = "radio.getPlaylist"; - map["rtp"] = "1"; // see above - QNetworkReply* reply = ws::post( map ); - connect( reply, SIGNAL(finished()), SLOT(onGetPlaylistReturn()) ); - return true; -} - - -bool -RadioTuner::tryAgain() -{ - qDebug() << "Bad response count" << m_retry_counter; - - if (++m_retry_counter > 5) - return false; - fetchFiveMoreTracks(); - return true; -} - - -void -RadioTuner::onGetPlaylistReturn() -{ - try { - XmlQuery lfm = ws::parse( (QNetworkReply*)sender() ); - Xspf xspf( lfm["playlist"] ); - QList tracks( xspf.tracks() ); - if (tracks.isEmpty()) //often we get empty playlists because php is shit - throw ws::TryAgainLater; - - m_retry_counter = 0; - foreach (Track t, tracks) - MutableTrack( t ).setSource( Track::LastFmRadio ); - m_queue += tracks; - emit trackAvailable(); - } - catch (ws::ParseError& e) - { - qWarning() << e.what(); - - if (e.enumValue() != ws::TryAgainLater || !tryAgain()) - emit error( e.enumValue() ); - } -} - - -Track -RadioTuner::takeNextTrack() -{ - //TODO presumably, we should check if fetchMoreTracks is working? - if (m_queue.isEmpty()) - return Track(); - - Track result = m_queue.takeFirst(); - if (m_queue.isEmpty()) - fetchFiveMoreTracks(); - - return result; -} diff -Nru liblastfm-0.4.0~really0.3.3/src/radio/RadioTuner.h liblastfm-1.0.1/src/radio/RadioTuner.h --- liblastfm-0.4.0~really0.3.3/src/radio/RadioTuner.h 2010-09-25 17:30:01.000000000 +0000 +++ liblastfm-1.0.1/src/radio/RadioTuner.h 1970-01-01 00:00:00.000000000 +0000 @@ -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_TUNER_H -#define LASTFM_TUNER_H - -#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(); - - signals: - void title( const QString& ); - void trackAvailable(); - void error( lastfm::ws::Error ); - - private slots: - void onTuneReturn(); - void onGetPlaylistReturn(); - - 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. - */ - bool fetchFiveMoreTracks(); - - QList m_queue; - uint m_retry_counter; - }; -} - -#endif diff -Nru liblastfm-0.4.0~really0.3.3/src/RadioStation.cpp liblastfm-1.0.1/src/RadioStation.cpp --- liblastfm-0.4.0~really0.3.3/src/RadioStation.cpp 1970-01-01 00:00:00.000000000 +0000 +++ liblastfm-1.0.1/src/RadioStation.cpp 2012-06-18 10:37:51.000000000 +0000 @@ -0,0 +1,379 @@ +/* + 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 "RadioStation.h" +#include "XmlQuery.h" + +#include +#include +#include + + +const float k_defaultRep(0.5); +const float k_defaultMainstr(0.5); +const bool k_defaultDisco(false); + +class lastfm::RadioStationData : public QSharedData +{ +public: + QUrl m_url; + QString m_title; + QString m_tagFilter; + + float m_rep; + float m_mainstr; + bool m_disco; +}; + + +lastfm::RadioStation::RadioStation() + : d( new RadioStationData ) +{ +} + +lastfm::RadioStation::RadioStation( const QString& s ) + : d( new RadioStationData ) +{ + // If it's a tag filtered station then extract that part + QString tempString = s; + + if ( !tempString.startsWith("lastfm://tag/") ) + { + int index = tempString.indexOf("/tag/"); + + if ( index != -1 ) + { + d->m_tagFilter = tempString.mid( index + 5, tempString.count() - (index + 5) ); + tempString = tempString.mid( 0, index ); + } + } + + d->m_url = tempString; +} + +lastfm::RadioStation::RadioStation( const RadioStation& other ) + : d(other.d) +{ +} + +lastfm::RadioStation& +lastfm::RadioStation::operator=( const RadioStation& that ) +{ + d = that.d; + return *this; +} + +lastfm::RadioStation::~RadioStation() +{ +} + +lastfm::RadioStation +lastfm::RadioStation::library( const lastfm::User& user ) +{ + QList users; + users << user; + return library( users ); +} + +lastfm::RadioStation +lastfm::RadioStation::library( 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"); + + RadioStation s( url ); + 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( "lastfm://user/" + user + "/recommended" ); + + 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( "lastfm://user/" + user + "/friends" ); + + 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( "lastfm://user/" + user + "/neighbours" ); + s.setTitle( QObject::tr( "%1%2s Neighbourhood Radio").arg( lastfm::ws::Username )); + 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 ) +{ + qSort(tag.begin(), tag.end()); + + QString url = (tag.count() > 1) ? "lastfm://tag/" : "lastfm://globaltags/"; + + url.append( tag[0].name() ); + + for ( int i = 1 ; i < tag.count() ; ++i ) + url.append( "*" + tag[i].name() ); + + return RadioStation( url ); +} + + +lastfm::RadioStation +lastfm::RadioStation::similar( const lastfm::Artist& artist ) +{ + QList artists; + artists << artist; + return similar( artists ); +} + + +lastfm::RadioStation +lastfm::RadioStation::similar( 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 RadioStation( url ); +} + + +lastfm::RadioStation +lastfm::RadioStation::mix( const lastfm::User& user ) +{ + RadioStation s( "lastfm://user/" + user + "/mix" ); + s.setTitle( QObject::tr( "%1%2s Mix Radio").arg( lastfm::ws::Username, QChar(0x2019) ) ); + return s; +} + + +QString +lastfm::RadioStation::url() const +{ + return d->m_url.toString() + (d->m_tagFilter.isEmpty() ? "" : "/tag/" + d->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 ( !d->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 Neighbourhood Radio").arg( lastfm::ws::Username, QChar(0x2019) ), Qt::CaseInsensitive ) == 0 ) + title = QObject::tr("My Neighbourhood Radio"); + + d->m_title = title; +} + +void +lastfm::RadioStation::setUrl( const QString& url ) +{ + d->m_url = url; +} + + +QString +lastfm::RadioStation::title() const +{ + return d->m_title; // + (d->m_tagFilter.isEmpty() ? "" : ": " + d->m_tagFilter); +} + + +void +lastfm::RadioStation::setTagFilter( const QString& tag ) +{ + d->m_tagFilter = tag; +} + + +QNetworkReply* +lastfm::RadioStation::getSampleArtists( int limit ) const +{ + QMap map; + map["method"] = "radio.getSampleArtists"; + map["station"] = d->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"] = d->m_url.toString(); + map["limit"] = QString::number( limit ); + return ws::get( map ); +} + + +bool +lastfm::RadioStation::isLegacyPlaylist() const +{ + return d->m_url.toString().startsWith( "lastfm://play/" ) || + d->m_url.toString().startsWith( "lastfm://preview/" ) || + d->m_url.toString().startsWith( "lastfm://track/" ) || + d->m_url.toString().startsWith( "lastfm://playlist/" ); +} + + +//static +QList +lastfm::RadioStation::list( QNetworkReply* r ) +{ + QList result; + XmlQuery lfm; + + if ( lfm.parse( r->readAll() ) ) + { + + foreach (XmlQuery xq, lfm.children("station")) + { + lastfm::RadioStation rs( QUrl::fromPercentEncoding( xq["url"].text().toUtf8() ) ); + rs.setTitle(xq["name"].text()); + result.append(rs); + } + } + else + { + qWarning() << lfm.parseError().message(); + } + + return result; +} + + +bool +lastfm::RadioStation::operator==( const RadioStation& that ) const +{ + return this->d->m_url == that.d->m_url && this->d->m_tagFilter == that.d->m_tagFilter; +} + + +void +lastfm::RadioStation::setRep(float rep) +{ + d->m_rep = rep; +} + + +void +lastfm::RadioStation::setMainstr(float mainstr) +{ + d->m_mainstr = mainstr; +} + + +void +lastfm::RadioStation::setDisco(bool disco) +{ + d->m_disco = disco; +} + + +float lastfm::RadioStation::rep() const +{ + return d->m_rep; +} + + +float lastfm::RadioStation::mainstr() const +{ + return d->m_mainstr; +} + + +bool lastfm::RadioStation::disco() const +{ + return d->m_disco; +} + + +QDebug operator<<( QDebug d, const lastfm::RadioStation& station ) +{ + return d << station.url(); +} diff -Nru liblastfm-0.4.0~really0.3.3/src/RadioStation.h liblastfm-1.0.1/src/RadioStation.h --- liblastfm-0.4.0~really0.3.3/src/RadioStation.h 1970-01-01 00:00:00.000000000 +0000 +++ liblastfm-1.0.1/src/RadioStation.h 2012-06-18 10:37:51.000000000 +0000 @@ -0,0 +1,99 @@ +/* + 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 "User.h" +#include "Tag.h" +#include "Artist.h" + +namespace lastfm +{ + /** @author + */ + + class LASTFM_DLLEXPORT RadioStation + { + public: + RadioStation(); + RadioStation( const QString& s ); + RadioStation( const RadioStation& that ); + ~RadioStation(); + + 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 setUrl( const QString& url ); + + 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; + + // good for getRecentStations: + static QList list( QNetworkReply* ); + + bool operator==( const RadioStation& that ) const; + RadioStation& operator=( const RadioStation& that ); + + private: + QSharedDataPointer d; + }; +} + + +Q_DECLARE_METATYPE( lastfm::RadioStation ) + + +LASTFM_DLLEXPORT QDebug operator<<( QDebug d, const lastfm::RadioStation& station ); + +#endif diff -Nru liblastfm-0.4.0~really0.3.3/src/RadioTuner.cpp liblastfm-1.0.1/src/RadioTuner.cpp --- liblastfm-0.4.0~really0.3.3/src/RadioTuner.cpp 1970-01-01 00:00:00.000000000 +0000 +++ liblastfm-1.0.1/src/RadioTuner.cpp 2012-06-18 10:37:51.000000000 +0000 @@ -0,0 +1,284 @@ +/* + 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 "RadioTuner.h" +#include "RadioStation.h" +#include "XmlQuery.h" +#include "Xspf.h" +#include "ws.h" + +#include +#include + +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 + + +class lastfm::RadioTunerPrivate : public QObject +{ + Q_OBJECT + public: + QList m_playlistQueue; + uint m_retry_counter; + bool m_fetchingPlaylist; + bool m_requestedPlaylist; + class QTimer* m_twoSecondTimer; + RadioStation m_station; + RadioStation m_retuneStation; + + RadioTunerPrivate( QObject * parent, const RadioStation& station ); + + /** 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 slots: + void onTwoSecondTimeout(); +}; + + +lastfm::RadioTunerPrivate::RadioTunerPrivate( QObject *parent, const RadioStation& station ) + : QObject( parent ), + m_station( 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())); +} + + +void +RadioTunerPrivate::onTwoSecondTimeout() +{ + if (m_requestedPlaylist) + { + m_requestedPlaylist = false; + fetchFiveMoreTracks(); + } +} + + + +void +RadioTunerPrivate::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()), parent(), 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()), parent(), SLOT(onGetPlaylistReturn()) ); + m_fetchingPlaylist = true; + } + else + m_requestedPlaylist = true; + } +} + + +bool +RadioTunerPrivate::tryAgain() +{ + qDebug() << "Bad response count" << m_retry_counter; + + if (++m_retry_counter > MAX_TUNING_ATTEMPTS) + return false; + fetchFiveMoreTracks(); + return true; +} + + +RadioTuner::RadioTuner( const RadioStation& station ) + :d( new RadioTunerPrivate( this, station ) ) +{ + qDebug() << station.url(); + + //Empty RadioStation implies that the radio + //should tune to the previous station. + if( station.url().isEmpty() ) + { + d->fetchFiveMoreTracks(); + } + else + { + QMap map; + map["method"] = "radio.tune"; + map["station"] = station.url(); + map["additional_info"] = "1"; + connect( ws::post(map), SIGNAL(finished()), SLOT(onTuneReturn()) ); + } +} + +RadioTuner::~RadioTuner() +{ +} + +void +RadioTuner::retune( const RadioStation& station ) +{ + d->m_playlistQueue.clear(); + d->m_retuneStation = station; + + qDebug() << station.url(); +} + + +void +RadioTuner::onTuneReturn() +{ + if ( !d->m_retuneStation.url().isEmpty() ) + d->m_station = d->m_retuneStation; + + XmlQuery lfm; + + if ( lfm.parse( qobject_cast(sender())->readAll() ) ) + { + qDebug() << lfm; + + d->m_station.setTitle( lfm["station"]["name"].text() ); + d->m_station.setUrl( lfm["station"]["url"].text() ); + + emit title( lfm["station"]["name"].text() ); + emit supportsDisco( lfm["station"]["supportsdiscovery"].text() == "1" ); + d->fetchFiveMoreTracks(); + } + else + { + emit error( lfm.parseError().enumValue(), lfm.parseError().message() ); + } +} + + +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 + d->m_twoSecondTimer->start( 2000 ); + + // This will block us fetching two playlists at once + d->m_fetchingPlaylist = false; + + XmlQuery lfm; + + if ( lfm.parse( qobject_cast(sender())->readAll() ) ) + { + qDebug() << lfm; + + d->m_station.setTitle( lfm["playlist"]["title"].text() ); + // we don't get the radio url in the playlist + //d->m_station.setUrl( lfm["station"]["url"].text() ); + + emit title( lfm["playlist"]["title"].text() ); + + Xspf* xspf = new Xspf( lfm["playlist"], this ); + connect( xspf, SIGNAL(expired()), SLOT(onXspfExpired()) ); + + if ( xspf->isEmpty() ) + { + // give up after too many empty playlists :( + if (!d->tryAgain()) + emit error( ws::NotEnoughContent, tr("Not enough content") ); + } + else + { + d->m_retry_counter = 0; + d->m_playlistQueue << xspf; + emit trackAvailable(); + } + } + else + { + qDebug() << lfm.parseError().message() << lfm.parseError().enumValue(); + emit error( lfm.parseError().enumValue(), lfm.parseError().message() ); + } +} + +void +RadioTuner::onXspfExpired() +{ + int index = d->m_playlistQueue.indexOf( static_cast(sender()) ); + if ( index != -1 ) + d->m_playlistQueue.takeAt( index )->deleteLater(); +} + +Track +RadioTuner::takeNextTrack() +{ + if ( d->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 ( !d->m_fetchingPlaylist ) + d->fetchFiveMoreTracks(); + + return Track(); + } + + Track result = d->m_playlistQueue[0]->takeFirst(); + + if ( d->m_playlistQueue[0]->isEmpty() ) + d->m_playlistQueue.removeFirst(); + + if ( d->m_playlistQueue.isEmpty() ) + d->fetchFiveMoreTracks(); + + return result; +} + +#include "RadioTuner.moc" diff -Nru liblastfm-0.4.0~really0.3.3/src/RadioTuner.h liblastfm-1.0.1/src/RadioTuner.h --- liblastfm-0.4.0~really0.3.3/src/RadioTuner.h 1970-01-01 00:00:00.000000000 +0000 +++ liblastfm-1.0.1/src/RadioTuner.h 2012-06-18 10:37:51.000000000 +0000 @@ -0,0 +1,66 @@ +/* + 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 "Track.h" +#include "ws.h" + +#include + +namespace lastfm +{ + class RadioStation; + + /** 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& ); + ~RadioTuner(); + + 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(); + + + private: + class RadioTunerPrivate * const d; + }; +} + +#endif diff -Nru liblastfm-0.4.0~really0.3.3/src/scrobble/Audioscrobbler.cpp liblastfm-1.0.1/src/scrobble/Audioscrobbler.cpp --- liblastfm-0.4.0~really0.3.3/src/scrobble/Audioscrobbler.cpp 2010-09-25 17:30:01.000000000 +0000 +++ liblastfm-1.0.1/src/scrobble/Audioscrobbler.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,264 +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 "Audioscrobbler.h" -#include "NowPlaying.h" -#include "ScrobbleCache.h" -#include "Handshake.h" -#include "ScrobblerSubmission.h" -#include "../ws/ws.h" - - -namespace lastfm -{ - struct AudioscrobblerPrivate - { - AudioscrobblerPrivate(const QString& id) - : id( id ) - , cache( ws::Username ) - , hard_failures( 0 ) - {} - - ~AudioscrobblerPrivate() - { - delete handshake; - delete np; - delete submitter; - } - - const QString id; - QPointer handshake; - QPointer np; - QPointer submitter; - ScrobbleCache cache; - uint hard_failures; - }; -} - - -lastfm::Audioscrobbler::Audioscrobbler( const QString& id ) - : d( new AudioscrobblerPrivate(id) ) -{ - handshake(); - submit(); // will submit what's there once the handshake completes -} - - -lastfm::Audioscrobbler::~Audioscrobbler() -{ - delete d; -} - - -void -lastfm::Audioscrobbler::handshake() //private -{ - d->hard_failures = 0; - - // if we are here due to hard failure then we need to save what we were - // doing and load it back into the new requests - QByteArray np_data; - QList tracks; - if (d->np) np_data = d->np->postData(); - if (d->submitter) tracks = d->submitter->unsubmittedTracks(); - - // we delete to be sure of the state of the QHttp objects, as they are - // rather black box - delete d->handshake; - delete d->np; - delete d->submitter; - - d->handshake = new ScrobblerHandshake( d->id ); - connect( d->handshake, SIGNAL(done( QByteArray )), SLOT(onHandshakeReturn( QByteArray )), Qt::QueuedConnection ); - d->np = new NowPlaying( np_data ); - connect( d->np, SIGNAL(done( QByteArray )), SLOT(onNowPlayingReturn( QByteArray )), Qt::QueuedConnection ); - d->submitter = new ScrobblerSubmission; - d->submitter->setTracks( tracks ); - connect( d->submitter, SIGNAL(done( QByteArray )), SLOT(onSubmissionReturn( QByteArray )), Qt::QueuedConnection ); -} - - -void -lastfm::Audioscrobbler::rehandshake() //public -{ - if (!d->submitter->hasSession()) - { - d->handshake->request(); - } - else - // if we still have a valid session, np may have been failing, so just - // send it as it doesn't hurt - d->np->request(); -} - - -void -lastfm::Audioscrobbler::nowPlaying( const Track& track ) -{ - d->np->submit( track ); -} - - -void -lastfm::Audioscrobbler::cache( const Track& track ) -{ - d->cache.add( track ); -} - - -void -lastfm::Audioscrobbler::cache( const QList& tracks ) -{ - d->cache.add( tracks ); -} - - -void -lastfm::Audioscrobbler::submit() -{ - d->submitter->setTracks( d->cache.tracks() ); - d->submitter->submitNextBatch(); - - if (d->submitter->isActive()) - emit status( Scrobbling ); -} - - -void -lastfm::Audioscrobbler::onError( Audioscrobbler::Error code ) -{ - qDebug() << code; //TODO error text - - switch (code) - { - case Audioscrobbler::ErrorBannedClientVersion: - case Audioscrobbler::ErrorInvalidSessionKey: - case Audioscrobbler::ErrorBadTime: - // np and submitter are in invalid state and won't send any requests - // the app has to tell the user and let them decide what to do - break; - - default: - Q_ASSERT( false ); // you (yes you!) have missed an enum value out - - case Audioscrobbler::ErrorThreeHardFailures: - case Audioscrobbler::ErrorBadSession: - handshake(); - break; - } - - emit status( code ); -} - - -#define SPLIT( x ) QList const results = x.split( '\n' ); QByteArray const code = results.value( 0 ); qDebug() << x.trimmed(); - - -void -lastfm::Audioscrobbler::onHandshakeReturn( const QByteArray& result ) //TODO trim before passing here -{ - SPLIT( result ) - - if (code == "OK" && results.count() >= 4) - { - d->np->setSession( results[1] ); - d->np->setUrl( QString::fromUtf8( results[2] ) ); - d->submitter->setSession( results[1] ); - d->submitter->setUrl( QString::fromUtf8( results[3] ) ); - - emit status( Audioscrobbler::Handshaken ); - - // submit any queued work - d->np->request(); - d->submitter->request(); - } - else if (code == "BANNED") - { - onError( Audioscrobbler::ErrorBannedClientVersion ); - } - else if (code == "BADAUTH") - { - onError( Audioscrobbler::ErrorInvalidSessionKey ); - } - else if (code == "BADTIME") - { - onError( Audioscrobbler::ErrorBadTime ); - } - else - d->handshake->retry(); //TODO increasing time up to 2 hours -} - - -void -lastfm::Audioscrobbler::onNowPlayingReturn( const QByteArray& result ) -{ - SPLIT( result ) - - if (code == "OK") - { - d->np->reset(); - } - else if (code == "BADSESSION") - { - // don't do anything, because we should use hard-failure route to ensure - // we don't do an infinitely fast np:BADSESSION->handshake() loop - // but we don't so we can't do anything - } - // yep, no else. The protocol says hard fail, I say, don't: - // 1) if only np is down, then hard failing will just mean a lot of work for the handshake php script with no good reason - // 2) if both are down, subs will hard fail too, so just rely on that - // 3) if np is up and subs is down, successful np requests will reset the failure count and possibly prevent timely scrobbles - - // TODO retry if server replies with busy, at least - // TODO you need a lot more error handling for the scrobblerHttp returns "" case -} - - -void -lastfm::Audioscrobbler::onSubmissionReturn( const QByteArray& result ) -{ - SPLIT( result ) - - if (code == "OK") - { - d->hard_failures = 0; - d->cache.remove( d->submitter->batch() ); - d->submitter->submitNextBatch(); - - if (d->submitter->batch().isEmpty()) - { - emit status( Audioscrobbler::TracksScrobbled ); - } - } - else if (code == "BADSESSION") - { - onError( Audioscrobbler::ErrorBadSession ); - } - else if (code.startsWith( "FAILED Plugin bug" )) - { - qWarning() << "YOU SUCK! Attempting reasonable error handling..."; - d->cache.remove( d->submitter->batch() ); - } - else if (++d->hard_failures >= 3) - { - onError( Audioscrobbler::ErrorThreeHardFailures ); - } - else - d->submitter->retry(); -} diff -Nru liblastfm-0.4.0~really0.3.3/src/scrobble/Audioscrobbler.h liblastfm-1.0.1/src/scrobble/Audioscrobbler.h --- liblastfm-0.4.0~really0.3.3/src/scrobble/Audioscrobbler.h 2010-09-25 17:30:01.000000000 +0000 +++ liblastfm-1.0.1/src/scrobble/Audioscrobbler.h 1970-01-01 00:00:00.000000000 +0000 @@ -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_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(); - - public slots: - /** will ask Last.fm to update the now playing information for the - * authenticated user */ - void nowPlaying( const Track& ); - /** will cache the track, but we won't submit it until you call submit() */ - void cache( const Track& ); - /** will submit the submission cache for this user */ - void submit(); - - public: - void cache( const QList& ); - - /** provided the current session is invalid, we will rehandshake. - * if the current session is valid, we do nothing. Basically, I don't want - * to write the code to safely delete currently executing submission - * requests */ - void rehandshake(); - - public: - enum Status - { - Connecting, - Handshaken, - Scrobbling, - TracksScrobbled, - - StatusMax - }; - - enum Error - { - /** the following will show via the status signal, the scrobbler will - * not submit this session (np too), however caching will continue */ - ErrorBadSession = StatusMax, - ErrorBannedClientVersion, - ErrorInvalidSessionKey, - ErrorBadTime, - ErrorThreeHardFailures - }; - - signals: - /** the controller should show status in an appropriate manner */ - void status( int code ); - - private slots: - void onHandshakeReturn( const QByteArray& ); - void onNowPlayingReturn( const QByteArray& ); - void onSubmissionReturn( const QByteArray& ); - - private: - void handshake(); - void onError( Error ); - - private: - class AudioscrobblerPrivate* d; - }; -} - - -static inline QDebug operator<<( QDebug d, lastfm::Audioscrobbler::Status status ) -{ - return d << lastfm::qMetaEnumString( status, "Status" ); -} -static inline QDebug operator<<( QDebug d, lastfm::Audioscrobbler::Error error ) -{ - return d << lastfm::qMetaEnumString( error, "Status" ); -} - -#endif diff -Nru liblastfm-0.4.0~really0.3.3/src/scrobble/Handshake.cpp liblastfm-1.0.1/src/scrobble/Handshake.cpp --- liblastfm-0.4.0~really0.3.3/src/scrobble/Handshake.cpp 2010-09-25 17:30:01.000000000 +0000 +++ liblastfm-1.0.1/src/scrobble/Handshake.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -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 . -*/ -#include "Handshake.h" -#include "../core/misc.h" -#include "../ws/ws.h" -#include -#include -#include - - -ScrobblerHandshake::ScrobblerHandshake( const QString& clientId ) - : m_clientId( clientId ) -{ - request(); -} - - -void -ScrobblerHandshake::request() -{ - if (isActive()) return; - - QString timestamp = QString::number( QDateTime::currentDateTime().toTime_t() ); - QString auth_token = lastfm::md5( (lastfm::ws::SharedSecret + timestamp).toUtf8() ); - - QString query_string = QString() + - "?hs=true" + - "&p=1.2.1" - "&c=" + m_clientId + - "&v=" + qApp->applicationVersion() + - "&u=" + QString(QUrl::toPercentEncoding( lastfm::ws::Username )) + - "&t=" + timestamp + - "&a=" + auth_token + - "&api_key=" + lastfm::ws::ApiKey + - "&sk=" + lastfm::ws::SessionKey; - - QUrl url = "http://post.audioscrobbler.com:80/" + query_string; - rp = lastfm::nam()->get( QNetworkRequest(url) ); - connect( rp, SIGNAL(finished()), SLOT(onRequestFinished()) ); - - qDebug() << "HTTP GET" << url; -} diff -Nru liblastfm-0.4.0~really0.3.3/src/scrobble/Handshake.h liblastfm-1.0.1/src/scrobble/Handshake.h --- liblastfm-0.4.0~really0.3.3/src/scrobble/Handshake.h 2010-09-25 17:30:01.000000000 +0000 +++ liblastfm-1.0.1/src/scrobble/Handshake.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,37 +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_SCROBBLER_HANDSHAKE_H -#define LASTFM_SCROBBLER_HANDSHAKE_H - -#include "ScrobblerHttp.h" -#include - - -class ScrobblerHandshake : public ScrobblerHttp -{ - QString const m_clientId; - -public: - ScrobblerHandshake( const QString& clientId ); - - virtual void request(); -}; - -#endif diff -Nru liblastfm-0.4.0~really0.3.3/src/scrobble/NowPlaying.cpp liblastfm-1.0.1/src/scrobble/NowPlaying.cpp --- liblastfm-0.4.0~really0.3.3/src/scrobble/NowPlaying.cpp 2010-09-25 17:30:01.000000000 +0000 +++ liblastfm-1.0.1/src/scrobble/NowPlaying.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -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 . -*/ -#include "NowPlaying.h" -#include "../types/Track.h" -#include - - -NowPlaying::NowPlaying( const QByteArray& data ) -{ - // will be submitted after the handshake, if there is some data that is - m_data = data; - - // we wait 5 seconds to prevent the server panicking when people skip a lot - // tracks in succession - m_timer = new QTimer( this ); - m_timer->setSingleShot( true ); - connect( m_timer, SIGNAL(timeout()), SLOT(request()) ); -} - - -void -NowPlaying::reset() -{ - m_timer->stop(); - m_data.clear(); -} - - -void -NowPlaying::submit( const lastfm::Track& track ) -{ - if (track.isNull()) - return; - - #define e( x ) QUrl::toPercentEncoding( x ) - m_data = "&a=" + e(track.artist()) + - "&t=" + e(track.title()) + - "&b=" + e(track.album()) + - "&l=" + QByteArray::number( track.duration() ) + - "&n=" + QByteArray::number( track.trackNumber() ) + - "&m=" + e(track.mbid()); - #undef e - - // m_time is initialised to midnight, so a bug exists that if the app is - // started after 00:00 and before 00:04 we trigger via the timer. But meh! - uint ms = m_delay.elapsed(); - - if (ms < 10000) { - m_timer->setInterval( 10000 - ms ); - m_timer->start(); - } - else { - m_delay.restart(); - request(); - } -} diff -Nru liblastfm-0.4.0~really0.3.3/src/scrobble/NowPlaying.h liblastfm-1.0.1/src/scrobble/NowPlaying.h --- liblastfm-0.4.0~really0.3.3/src/scrobble/NowPlaying.h 2010-09-25 17:30:01.000000000 +0000 +++ liblastfm-1.0.1/src/scrobble/NowPlaying.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,41 +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_NOW_PLAYING_H -#define LASTFM_NOW_PLAYING_H - -#include "../global.h" -#include "ScrobblerHttp.h" -#include - - -class NowPlaying : public ScrobblerPostHttp -{ - class QTimer* m_timer; - QTime m_delay; - -public: - NowPlaying( const QByteArray& ); - void submit( const lastfm::Track& ); - void reset(); - - using ScrobblerPostHttp::request; -}; - -#endif diff -Nru liblastfm-0.4.0~really0.3.3/src/scrobble/ScrobbleCache.cpp liblastfm-1.0.1/src/scrobble/ScrobbleCache.cpp --- liblastfm-0.4.0~really0.3.3/src/scrobble/ScrobbleCache.cpp 2010-09-25 17:30:01.000000000 +0000 +++ liblastfm-1.0.1/src/scrobble/ScrobbleCache.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,136 +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 -#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 ); -} - - -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 ); - - QFileInfo(m_path).dir().mkpath("."); - - QFile file( m_path ); - file.open( QIODevice::WriteOnly | QIODevice::Text ); - - QTextStream stream( &file ); - stream.setCodec( "UTF-8" ); - stream << "\n"; - stream << xml.toString( 2 ); - } -} - - -void -ScrobbleCache::add( const Scrobble& track ) -{ - add( QList() << track ); -} - - -void -ScrobbleCache::add( const QList& tracks ) -{ - foreach (const Track& track, tracks) - { - Scrobble::Invalidity invalidity; - - if (!Scrobble(track).isValid( &invalidity )) - { - qWarning() << invalidity; - } - else if (track.isNull()) - qDebug() << "Will not cache an empty track"; - - else if (!m_tracks.contains( track )) - 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 -Nru liblastfm-0.4.0~really0.3.3/src/scrobble/ScrobbleCache.h liblastfm-1.0.1/src/scrobble/ScrobbleCache.h --- liblastfm-0.4.0~really0.3.3/src/scrobble/ScrobbleCache.h 2010-09-25 17:30:01.000000000 +0000 +++ liblastfm-1.0.1/src/scrobble/ScrobbleCache.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,74 +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 -#include -#include - - -#if LASTFM_VERSION >= 0x00010000 -namespace lastfm { -#else -using lastfm::Scrobble; -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 Scrobble& ); - 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 -}; - -#if LASTFM_VERSION >= 0x00010000 -} -#endif - -#endif diff -Nru liblastfm-0.4.0~really0.3.3/src/scrobble/Scrobble.cpp liblastfm-1.0.1/src/scrobble/Scrobble.cpp --- liblastfm-0.4.0~really0.3.3/src/scrobble/Scrobble.cpp 2010-09-25 17:30:01.000000000 +0000 +++ liblastfm-1.0.1/src/scrobble/Scrobble.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -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 "Scrobble.h" -#include "ScrobblePoint.h" -#include -using lastfm::Scrobble; - - -QByteArray -Scrobble::sourceString() const -{ - switch (d->source) - { - case LastFmRadio: return "L" + d->extras["trackauth"].toAscii(); - case Player: return "P" + d->extras["playerId"].toUtf8(); - case MediaDevice: return "P" + d->extras["mediaDeviceId"].toUtf8(); - case NonPersonalisedBroadcast: return "R"; - case PersonalisedRecommendation: return "E"; - default: return "U"; - } -} - - -bool -Scrobble::isValid( Invalidity* v ) const -{ - #define TEST( test, x ) \ - if (test) { \ - if (v) *v = x; \ - return false; \ - } - - TEST( duration() < ScrobblePoint::kScrobbleMinLength, TooShort ); - - // Radio tracks above preview length always scrobble - if (source() == LastFmRadio) - return true; - - TEST( !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( timestamp() > QDateTime::currentDateTime().addMonths( 1 ), FromTheFuture ); - - TEST( timestamp() < QDateTime::fromString( "2003-01-01", Qt::ISODate ), FromTheDistantPast ); - - // Check if any required fields are empty - TEST( d->artist.isEmpty(), ArtistNameMissing ); - TEST( d->title.isEmpty(), TrackNameMissing ); - - TEST( (QStringList() << "unknown artist" - << "unknown" - << "[unknown]" - << "[unknown artist]").contains( d->artist.toLower() ), - ArtistInvalid ); - - return true; -} diff -Nru liblastfm-0.4.0~really0.3.3/src/scrobble/Scrobble.h liblastfm-1.0.1/src/scrobble/Scrobble.h --- liblastfm-0.4.0~really0.3.3/src/scrobble/Scrobble.h 2010-09-25 17:30:01.000000000 +0000 +++ liblastfm-1.0.1/src/scrobble/Scrobble.h 1970-01-01 00:00:00.000000000 +0000 @@ -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_SCROBBLE_H -#define LASTFM_SCROBBLE_H - -#include - -namespace lastfm -{ - struct LASTFM_DLLEXPORT Scrobble : lastfm::Track - { - Scrobble() - {} - - Scrobble( const lastfm::Track& that ) : Track( that ) - {} - - QByteArray sourceString() const; - - QByteArray ratingCharacter() const - { - return d->extras["rating"].toAscii(); - } - - bool isLoved() const { return ratingCharacter() == QChar('L'); } - bool isBanned() const { return ratingCharacter() == QChar('B'); } - bool isSkipped() const { return ratingCharacter() == QChar('S'); } - - /** if isValid() returns false, we will not scrobble the track */ - enum Invalidity - { - TooShort, - ArtistNameMissing, - TrackNameMissing, - ArtistInvalid, - NoTimestamp, - FromTheFuture, - FromTheDistantPast - }; - - /** @returns true if the server is unlikely to reject this scrobble */ - bool isValid( Invalidity* = 0 ) const; - }; -} - -#endif diff -Nru liblastfm-0.4.0~really0.3.3/src/scrobble/ScrobblePoint.h liblastfm-1.0.1/src/scrobble/ScrobblePoint.h --- liblastfm-0.4.0~really0.3.3/src/scrobble/ScrobblePoint.h 2010-09-25 17:30:01.000000000 +0000 +++ liblastfm-1.0.1/src/scrobble/ScrobblePoint.h 1970-01-01 00:00:00.000000000 +0000 @@ -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 -Nru liblastfm-0.4.0~really0.3.3/src/scrobble/ScrobblerHttp.cpp liblastfm-1.0.1/src/scrobble/ScrobblerHttp.cpp --- liblastfm-0.4.0~really0.3.3/src/scrobble/ScrobblerHttp.cpp 2010-09-25 17:30:01.000000000 +0000 +++ liblastfm-1.0.1/src/scrobble/ScrobblerHttp.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,102 +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 "ScrobblerHttp.h" -#include -#include -#include -#include "../ws/ws.h" - - -ScrobblerHttp::ScrobblerHttp( QObject* parent ) - : QObject( parent ) -{ - m_retry_timer = new QTimer( this ); - m_retry_timer->setSingleShot( true ); - connect( m_retry_timer, SIGNAL(timeout()), SLOT(request()) ); - resetRetryTimer(); -} - - -void -ScrobblerHttp::onRequestFinished() -{ - if (rp->error() == QNetworkReply::OperationCanceledError) - ; //we aborted it - if (rp->error()) - { - qWarning() << "ERROR!" << rp->error(); - emit done( QByteArray() ); - } - else - { - emit done( rp->readAll() ); - - // if it is running then someone called retry() in the slot connected to - // the done() signal above, so don't reset it, init - if (!m_retry_timer->isActive()) - resetRetryTimer(); - } - - rp->deleteLater(); -} - - -void -ScrobblerHttp::retry() -{ - if (!m_retry_timer->isActive()) - { - int const i = m_retry_timer->interval(); - if (i < 120 * 60 * 1000) - m_retry_timer->setInterval( i * 2 ); - } - - qDebug() << "Will retry in" << m_retry_timer->interval() / 1000 << "seconds"; - - m_retry_timer->start(); -} - - -void -ScrobblerHttp::resetRetryTimer() -{ - m_retry_timer->setInterval( 30 * 1000 ); -} - - -void -ScrobblerPostHttp::request() -{ - if (m_data.isEmpty() || m_session.isEmpty()) - return; - - if (rp) - rp->deleteLater(); - - QByteArray data = "s=" + m_session + m_data; - - QNetworkRequest rq( m_url ); - rq.setRawHeader( "Content-Type", "application/x-www-form-urlencoded" ); - rp = lastfm::nam()->post( rq, data ); - connect( rp, SIGNAL(finished()), SLOT(onRequestFinished()) ); - rp->setParent( this ); - - qDebug() << "HTTP POST:" << m_url << data; -} diff -Nru liblastfm-0.4.0~really0.3.3/src/scrobble/ScrobblerHttp.h liblastfm-1.0.1/src/scrobble/ScrobblerHttp.h --- liblastfm-0.4.0~really0.3.3/src/scrobble/ScrobblerHttp.h 2010-09-25 17:30:01.000000000 +0000 +++ liblastfm-1.0.1/src/scrobble/ScrobblerHttp.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,82 +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 SCROBBLER_HTTP_H -#define SCROBBLER_HTTP_H - -#include -#include -class QNetworkReply; - - -/** This was a QHttp class, but then we realised QNetworkAccessManager and that - * is oodles better. So we chnaged it to use that. */ -class ScrobblerHttp : public QObject -{ - Q_OBJECT - -public: - void retry(); - bool isActive() const { return !rp.isNull(); } - -protected: - ScrobblerHttp( QObject* parent = 0 ); - -protected slots: - virtual void request() = 0; - -signals: - void done( const QByteArray& data ); - -protected: - class QTimer *m_retry_timer; - QPointer rp; - -private slots: - void onRequestFinished(); - -private: - void resetRetryTimer(); -}; - - -class ScrobblerPostHttp : public ScrobblerHttp -{ - QUrl m_url; - QByteArray m_session; - -protected: - QByteArray m_data; - -public: - ScrobblerPostHttp() - {} - - /** if you reimplement call the base version after setting m_data */ - virtual void request(); - - void setSession( const QByteArray& id ) { m_session = id; } - void setUrl( const QUrl& url ) { m_url = url; } - - QByteArray postData() const { return m_data; } - - bool hasSession() const { return m_session.size(); } -}; - -#endif diff -Nru liblastfm-0.4.0~really0.3.3/src/scrobble/ScrobblerSubmission.cpp liblastfm-1.0.1/src/scrobble/ScrobblerSubmission.cpp --- liblastfm-0.4.0~really0.3.3/src/scrobble/ScrobblerSubmission.cpp 2010-09-25 17:30:01.000000000 +0000 +++ liblastfm-1.0.1/src/scrobble/ScrobblerSubmission.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,79 +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 "ScrobblerSubmission.h" -#include "ScrobbleCache.h" -#include "Scrobble.h" - -using lastfm::Track; -using lastfm::Scrobble; - -void -ScrobblerSubmission::setTracks( const QList& tracks ) -{ - m_tracks = tracks; - // submit in chronological order - qSort( m_tracks.begin(), m_tracks.end() ); -} - - -void -ScrobblerSubmission::submitNextBatch() -{ - if (isActive()) - // the tracks cannot be submitted at this time - // if a parent Scrobbler instance exists, it will submit another batch - // when the current one is done - return; - - m_batch.clear(); //yep before isEmpty() check - m_data.clear(); - - if (m_tracks.isEmpty()) - return; - - bool portable = false; - for (int i = 0; i < 50 && !m_tracks.isEmpty(); ++i) - { - Scrobble s = m_tracks.takeFirst(); - - QByteArray const N = QByteArray::number( i ); - #define e( x ) QUrl::toPercentEncoding( x ) - m_data += "&a[" + N + "]=" + e(s.artist()) + - "&t[" + N + "]=" + e(s.title()) + - "&i[" + N + "]=" + QByteArray::number( s.timestamp().toTime_t() ) + - "&o[" + N + "]=" + s.sourceString() + - "&r[" + N + "]=" + s.ratingCharacter() + - "&l[" + N + "]=" + QByteArray::number( s.duration() ) + - "&b[" + N + "]=" + e(s.album()) + - "&n[" + N + "]=" + QByteArray::number( s.trackNumber() ) + - "&m[" + N + "]=" + e(s.mbid()); - #undef e - - if (s.source() == Track::MediaDevice) - portable = true; - - m_batch += s; - } - - if (portable) - m_data += "&portable=1"; - - request(); -}; diff -Nru liblastfm-0.4.0~really0.3.3/src/scrobble/ScrobblerSubmission.h liblastfm-1.0.1/src/scrobble/ScrobblerSubmission.h --- liblastfm-0.4.0~really0.3.3/src/scrobble/ScrobblerSubmission.h 2010-09-25 17:30:01.000000000 +0000 +++ liblastfm-1.0.1/src/scrobble/ScrobblerSubmission.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,48 +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_SCROBBLER_SUBMISSION_H -#define LASTFM_SCROBBLER_SUBMISSION_H - -#include "ScrobblerHttp.h" -#include "../types/Track.h" -#include - -class ScrobblerSubmission : public ScrobblerPostHttp -{ - QList m_tracks; - QList m_batch; - -public: - /** tracks will be submitted in batches of 50 */ - void setTracks( const QList& ); - /** submits a batch, if we are already submitting, does nothing */ - void submitNextBatch(); - /** the batch that is being submitted currently */ - QList batch() const { return m_batch; } - /** tracks that have not yet been removed due to an OK from Last.fm */ - QList unsubmittedTracks() const { return m_tracks; } - - virtual void request() - { - if (!isActive()) ScrobblerPostHttp::request(); - } -}; - -#endif diff -Nru liblastfm-0.4.0~really0.3.3/src/ScrobbleCache.cpp liblastfm-1.0.1/src/ScrobbleCache.cpp --- liblastfm-0.4.0~really0.3.3/src/ScrobbleCache.cpp 1970-01-01 00:00:00.000000000 +0000 +++ liblastfm-1.0.1/src/ScrobbleCache.cpp 2012-06-18 10:37:51.000000000 +0000 @@ -0,0 +1,232 @@ +/* + 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 "misc.h" +#include +#include +#include +#include +#include + +using lastfm::ScrobbleCache; + + +class lastfm::ScrobbleCachePrivate +{ + public: + enum Invalidity + { + TooShort, + ArtistNameMissing, + TrackNameMissing, + ArtistInvalid, + NoTimestamp, + FromTheFuture, + FromTheDistantPast + }; + + QString m_username; + QString m_path; + QList m_tracks; + + bool isValid( const Track& track, Invalidity* = 0 ); + void write(); /// writes m_tracks to m_path + void read( QDomDocument& xml ); /// reads from m_path into m_tracks + +}; + + +bool +lastfm::ScrobbleCachePrivate::isValid( const lastfm::Track& track, Invalidity* v ) +{ + #define TEST( test, x ) \ + if (test) { \ + if (v) *v = x; \ + return false; \ + } + + TEST( track.duration() < ScrobblePoint::scrobbleTimeMin(), 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; +} + + +ScrobbleCache::ScrobbleCache( const QString& username ) + : d( new ScrobbleCachePrivate ) +{ + Q_ASSERT( username.length() ); + + d->m_path = lastfm::dir::runtimeData().filePath( username + "_subs_cache.xml" ); + d->m_username = username; + + QDomDocument xml; + d->read( xml ); +} + + +ScrobbleCache::ScrobbleCache( const ScrobbleCache& that ) + : d ( new ScrobbleCachePrivate( *that.d ) ) +{ +} + + +ScrobbleCache& +ScrobbleCache::operator=( const ScrobbleCache& that ) +{ + d->m_username = that.d->m_username; + d->m_path = that.d->m_path; + d->m_tracks = that.d->m_tracks; + return *this; +} + + +ScrobbleCache::~ScrobbleCache() +{ + delete d; +} + + +void +lastfm::ScrobbleCachePrivate::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 +lastfm::ScrobbleCachePrivate::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) + { + ScrobbleCachePrivate::Invalidity invalidity; + + if ( !d->isValid( track, &invalidity ) ) + { + qWarning() << invalidity; + } + else if (track.isNull()) + qDebug() << "Will not cache an empty track"; + else + d->m_tracks += track; + } + + d->write(); +} + + +int +ScrobbleCache::remove( const QList& toremove ) +{ + QMutableListIterator i( d->m_tracks ); + while (i.hasNext()) { + Track t = i.next(); + for (int x = 0; x < toremove.count(); ++x) + if (toremove[x] == t) + i.remove(); + } + + d->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 d->m_tracks.count(); +} + + +QList +ScrobbleCache::tracks() const +{ + return d->m_tracks; +} + + +QString +ScrobbleCache::path() const +{ + return d->m_path; +} + + +QString +ScrobbleCache::username() const +{ + return d->m_username; +} diff -Nru liblastfm-0.4.0~really0.3.3/src/ScrobbleCache.h liblastfm-1.0.1/src/ScrobbleCache.h --- liblastfm-0.4.0~really0.3.3/src/ScrobbleCache.h 1970-01-01 00:00:00.000000000 +0000 +++ liblastfm-1.0.1/src/ScrobbleCache.h 2012-06-18 10:37:51.000000000 +0000 @@ -0,0 +1,56 @@ +/* + 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 "Track.h" +#include + +namespace lastfm { + +/** absolutely not thread-safe */ +class LASTFM_DLLEXPORT ScrobbleCache +{ +public: + explicit ScrobbleCache( const QString& username ); + ScrobbleCache( const ScrobbleCache& that ); + ~ScrobbleCache(); + + /** 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& ); + + ScrobbleCache& operator=( const ScrobbleCache& that ); + + QList tracks() const; + QString path() const; + QString username() const; + +private: + bool operator==( const ScrobbleCache& ); //undefined + class ScrobbleCachePrivate * const d; +}; + +} + +#endif diff -Nru liblastfm-0.4.0~really0.3.3/src/ScrobblePoint.cpp liblastfm-1.0.1/src/ScrobblePoint.cpp --- liblastfm-0.4.0~really0.3.3/src/ScrobblePoint.cpp 1970-01-01 00:00:00.000000000 +0000 +++ liblastfm-1.0.1/src/ScrobblePoint.cpp 2012-06-18 10:37:51.000000000 +0000 @@ -0,0 +1,114 @@ +/* + 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 "ScrobblePoint.h" + +#define SCROBBLE_PERCENT_MIN 50 +#define SCROBBLE_PERCENT_MAX 100 +#define DEFAULT_SCROBBLE_PERCENT 50 +#define SCROBBLE_TIME_MIN 31 +#define SCROBBLE_TIME_MAX 240 + +class lastfm::ScrobblePointPrivate +{ +public: + uint i; +}; + + +lastfm::ScrobblePoint::ScrobblePoint() + : d( new ScrobblePointPrivate ) +{ + d->i = SCROBBLE_TIME_MAX; +} + + +lastfm::ScrobblePoint::ScrobblePoint( uint j ) + : d( new ScrobblePointPrivate ) +{ + // we special case 0, returning SCROBBLE_TIME_MAX because we are + // cruel and callous people + if (j == 0) --j; + + d->i = qBound( uint(SCROBBLE_TIME_MIN), + j, + uint(SCROBBLE_TIME_MAX) ); +} + + +lastfm::ScrobblePoint::ScrobblePoint( const ScrobblePoint& that ) + : d( new ScrobblePointPrivate( *that.d ) ) +{ +} + + +lastfm::ScrobblePoint::~ScrobblePoint() +{ + delete d; +} + + +lastfm::ScrobblePoint::operator uint() const +{ + return d->i; +} + + +lastfm::ScrobblePoint& +lastfm::ScrobblePoint::operator=( const ScrobblePoint& that ) +{ + d->i = that.d->i; + return *this; +} + + +uint +lastfm::ScrobblePoint::scrobblePercentMin() +{ + return SCROBBLE_PERCENT_MIN; +} + + +uint +lastfm::ScrobblePoint::scrobblePercentMax() +{ + return SCROBBLE_PERCENT_MAX; +} + + +uint +lastfm::ScrobblePoint::defaultScrobblePercent() +{ + return DEFAULT_SCROBBLE_PERCENT; +} + + +uint +lastfm::ScrobblePoint::scrobbleTimeMin() +{ + return SCROBBLE_TIME_MIN; +} + + +uint +lastfm::ScrobblePoint::scrobbleTimeMax() +{ + return SCROBBLE_TIME_MAX; +} diff -Nru liblastfm-0.4.0~really0.3.3/src/ScrobblePoint.h liblastfm-1.0.1/src/ScrobblePoint.h --- liblastfm-0.4.0~really0.3.3/src/ScrobblePoint.h 1970-01-01 00:00:00.000000000 +0000 +++ liblastfm-1.0.1/src/ScrobblePoint.h 2012-06-18 10:37:51.000000000 +0000 @@ -0,0 +1,57 @@ +/* + 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 "global.h" + + +namespace lastfm +{ + +class LASTFM_DLLEXPORT ScrobblePoint +{ +public: + ScrobblePoint(); + ~ScrobblePoint(); + + /** j is in seconds, and should be 50% the duration of a track */ + explicit ScrobblePoint( uint j ); + ScrobblePoint( const ScrobblePoint& that ); + operator uint() const; + ScrobblePoint& operator=( const ScrobblePoint& that ); + + // scrobbles can occur between these two percentages of track duration + static uint scrobblePercentMin(); // 50 + static uint scrobblePercentMax(); // 100 + static uint defaultScrobblePercent(); // 50 + + // Shortest track length allowed to scrobble in seconds + static uint scrobbleTimeMin(); // 31 + // Upper limit for scrobble time in seconds + static uint scrobbleTimeMax(); // 240 + +private: + class ScrobblePointPrivate * const d; +}; + +} + +#endif diff -Nru liblastfm-0.4.0~really0.3.3/src/Tag.cpp liblastfm-1.0.1/src/Tag.cpp --- liblastfm-0.4.0~really0.3.3/src/Tag.cpp 1970-01-01 00:00:00.000000000 +0000 +++ liblastfm-1.0.1/src/Tag.cpp 2012-06-18 10:37:51.000000000 +0000 @@ -0,0 +1,138 @@ +/* + 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 "UrlBuilder.h" +#include "XmlQuery.h" +#include "ws.h" + +#include + +using lastfm::Tag; +using lastfm::User; + + +class lastfm::TagPrivate +{ +public: + QString name; +}; + + +Tag::Tag( const QString& name ) + : d( new TagPrivate ) +{ + d->name = name; +} + + +Tag::Tag( const Tag& that ) + : d( new TagPrivate( *that.d ) ) +{ +} + + +Tag::~Tag() +{ + delete d; +} + +Tag::operator QString() const +{ + return d->name; +} + + +QString +Tag::name() const +{ + return d->name; +} + + +lastfm::Tag +Tag::operator=( const Tag& that ) const +{ + return Tag( that.name() ); +} + + +bool +Tag::operator<( const Tag& that ) const +{ + return this->d->name < that.d->name; +} + + +QUrl +Tag::www() const +{ + return UrlBuilder( "tag" ).slash( d->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"] = d->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; + + XmlQuery lfm; + + if ( lfm.parse( r->readAll() ) ) + { + + foreach ( XmlQuery xq, lfm.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() ); + } + else + { + qDebug() << lfm.parseError().message() << lfm.parseError().enumValue(); + } + + return tags; +} diff -Nru liblastfm-0.4.0~really0.3.3/src/Tag.h liblastfm-1.0.1/src/Tag.h --- liblastfm-0.4.0~really0.3.3/src/Tag.h 1970-01-01 00:00:00.000000000 +0000 +++ liblastfm-1.0.1/src/Tag.h 2012-06-18 10:37:51.000000000 +0000 @@ -0,0 +1,68 @@ +/* + 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 "global.h" +#include +#include + +class QNetworkReply; + +namespace lastfm +{ + class User; + + class LASTFM_DLLEXPORT Tag + { + public: + Tag( const QString& name ); + Tag( const Tag& that ); + ~Tag(); + + operator QString() const; + QString name() const; + + lastfm::Tag operator=( const Tag& that ) const; + bool operator<( const Tag& that ) const; + + /** 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 User& user ) const; + /** pass the finished QNetworkReply to Tag::list() */ + QNetworkReply* search() const; + + /** the top global tags on Last.fm, sorted by popularity (number of times used) */ + static 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* ); + + private: + class TagPrivate * const d; + }; +} + +#endif diff -Nru liblastfm-0.4.0~really0.3.3/src/Tasteometer.cpp liblastfm-1.0.1/src/Tasteometer.cpp --- liblastfm-0.4.0~really0.3.3/src/Tasteometer.cpp 1970-01-01 00:00:00.000000000 +0000 +++ liblastfm-1.0.1/src/Tasteometer.cpp 2012-06-18 10:37:51.000000000 +0000 @@ -0,0 +1,44 @@ +/* + Copyright 2011 Last.fm Ltd. + - Primarily authored by 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 "Tasteometer.h" +#include "User.h" + +lastfm::Tasteometer::Tasteometer() +{ +} + + +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 -Nru liblastfm-0.4.0~really0.3.3/src/Tasteometer.h liblastfm-1.0.1/src/Tasteometer.h --- liblastfm-0.4.0~really0.3.3/src/Tasteometer.h 1970-01-01 00:00:00.000000000 +0000 +++ liblastfm-1.0.1/src/Tasteometer.h 2012-06-18 10:37:51.000000000 +0000 @@ -0,0 +1,43 @@ +/* + Copyright 2011 Last.fm Ltd. + - Primarily authored by 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 TASTEOMETER_H +#define TASTEOMETER_H + +#include "global.h" + +class QNetworkReply; + +namespace lastfm +{ + class User; + + class LASTFM_DLLEXPORT Tasteometer + { + public: + Tasteometer(); + ~Tasteometer(); + + public: + static QNetworkReply* compare( const User& left, const User& right ); + }; +} + +#endif // TASTEOMETER_H diff -Nru liblastfm-0.4.0~really0.3.3/src/Track.cpp liblastfm-1.0.1/src/Track.cpp --- liblastfm-0.4.0~really0.3.3/src/Track.cpp 1970-01-01 00:00:00.000000000 +0000 +++ liblastfm-1.0.1/src/Track.cpp 2012-06-18 10:37:51.000000000 +0000 @@ -0,0 +1,1161 @@ +/* + 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 "Track.h" +#include "User.h" +#include "UrlBuilder.h" +#include "XmlQuery.h" +#include "ws.h" + +#include +#include +#include +#include + + +class lastfm::TrackContextPrivate +{ + public: + TrackContext::Type m_type; + QList m_values; + static TrackContext::Type getType( const QString& typeString ); +}; + +lastfm::TrackContext::Type +lastfm::TrackContextPrivate::getType( const QString& typeString ) +{ + lastfm::TrackContext::Type type = lastfm::TrackContext::UnknownType; + + if ( typeString == "artist" ) + type = lastfm::TrackContext::Artist; + else if ( typeString == "user" ) + type = lastfm::TrackContext::User; + else if ( typeString == "neighbour" ) + type = lastfm::TrackContext::Neighbour; + else if ( typeString == "friend" ) + type = lastfm::TrackContext::Friend; + + return type; +} + + +lastfm::TrackContext::TrackContext() + :d( new TrackContextPrivate ) +{ + d->m_type = UnknownType; +} + +lastfm::TrackContext::TrackContext( const QString& type, const QList& values ) + :d( new TrackContextPrivate ) +{ + d->m_values = values; + d->m_type = d->getType( type ); +} + +lastfm::TrackContext::TrackContext( const TrackContext& that ) + :d( new TrackContextPrivate( *that.d ) ) +{ +} + +lastfm::TrackContext::~TrackContext() +{ + delete d; +} + +lastfm::TrackContext::Type +lastfm::TrackContext::type() const +{ + return d->m_type; +} + + +QList +lastfm::TrackContext::values() const +{ + return d->m_values; +} + +lastfm::TrackContext& +lastfm::TrackContext::operator=( const TrackContext& that ) +{ + d->m_type = that.d->m_type; + d->m_values = that.d->m_values; + return *this; +} + + +class lastfm::TrackData : public QObject, public QSharedData +{ + Q_OBJECT + + friend class Track; + friend class MutableTrack; +public: + TrackData(); + +public: + lastfm::Artist artist; + lastfm::Artist albumArtist; + lastfm::Album album; + QString title; + lastfm::Artist correctedArtist; + lastfm::Artist correctedAlbumArtist; + lastfm::Album 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 + lastfm::Track::LoveStatus loved; + QMap m_images; + short scrobbleStatus; + short scrobbleError; + QString scrobbleErrorText; + + //FIXME I hate this, but is used for radio trackauth etc. + QMap extras; + + struct Observer + { + QNetworkReply* reply; + QPointer receiver; + const char* method; + }; + + QList observers; + + bool null; + + bool podcast; + bool video; + +private: + void forceLoveToggled( bool love ); + void forceScrobbleStatusChanged(); + void forceCorrected( QString correction ); + +private slots: + void onLoveFinished(); + void onUnloveFinished(); + void onGotInfo(); + +signals: + void loveToggled( bool love ); + void scrobbleStatusChanged( short scrobbleStatus ); + void corrected( QString correction ); +}; + + +lastfm::TrackData::TrackData() + : trackNumber( 0 ), + duration( 0 ), + source( Track::UnknownSource ), + rating( 0 ), + fpid( -1 ), + loved( Track::UnknownLoveStatus ), + scrobbleStatus( Track::Null ), + scrobbleError( Track::None ), + null( false ), + podcast( false ), + video( false ) +{} + +lastfm::Track::Track() + :AbstractType() +{ + d = new TrackData; + d->null = true; +} + +lastfm::Track::Track( const Track& that ) + :AbstractType(), d( that.d ) +{ +} + +lastfm::Track::Track( const QDomElement& e ) + :AbstractType() +{ + d = new TrackData; + + if (e.isNull()) { d->null = true; return; } + + //TODO: not sure of lastfm's xml changed, but nodes have + // Artist Name.. + // as children isntead of Artist Name + // we detect both here. + QDomNode artistName = e.namedItem( "artist" ).namedItem( "name" ); + if( artistName.isNull() ) { + d->artist = e.namedItem( "artist" ).toElement().text(); + } else { + d->artist = artistName.toElement().text(); + + } + + //TODO: not sure if lastfm xml's changed, or if chart.getTopTracks uses + //a different format, but the title is stored at + //Title... + //we detect both here. + 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 = Album( d->artist, e.namedItem( "album" ).toElement().text() ); + d->correctedArtist = e.namedItem( "correctedArtist" ).toElement().text(); + d->correctedAlbumArtist = e.namedItem( "correctedAlbumArtist" ).toElement().text(); + d->correctedAlbum = Album( d->correctedArtist, 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::UnknownSource + d->time = QDateTime::fromTime_t( e.namedItem( "timestamp" ).toElement().text().toUInt() ); + d->loved = static_cast(e.namedItem( "loved" ).toElement().text().toInt()); + d->scrobbleStatus = e.namedItem( "scrobbleStatus" ).toElement().text().toInt(); + d->scrobbleError = e.namedItem( "scrobbleError" ).toElement().text().toInt(); + d->scrobbleErrorText = e.namedItem( "scrobbleErrorText" ).toElement().text(); + d->podcast = e.namedItem( "podcast" ).toElement().text().toInt(); + d->video = e.namedItem( "video" ).toElement().text().toInt(); + + for (QDomElement image = e.firstChildElement("image") ; !image.isNull() ; image = image.nextSiblingElement("image")) + d->m_images[static_cast(image.attribute("size").toInt())] = image.text(); + + QDomNode artistNode = e.namedItem("artistImages"); + + for (QDomElement artistImage = artistNode.firstChildElement("image") ; !artistImage.isNull() ; artistImage = artistImage.nextSiblingElement("image")) + artist().setImageUrl( static_cast(artistImage.attribute("size").toInt()), artistImage.text() ); + + QDomNode albumNode = e.namedItem("albumImages"); + + for (QDomElement albumImage = albumNode.firstChildElement("image") ; !albumImage.isNull() ; albumImage = albumImage.nextSiblingElement("image")) + album().setImageUrl( static_cast(albumImage.attribute("size").toInt()), albumImage.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() +{ + XmlQuery lfm; + + if ( lfm.parse( static_cast(sender())->readAll() ) ) + { + if ( lfm.attribute( "status" ) == "ok") + loved = Track::Loved; + + } + + emit loveToggled( loved == Track::Loved ); +} + + +void +lastfm::TrackData::onUnloveFinished() +{ + XmlQuery lfm; + + if ( lfm.parse( static_cast(sender())->readAll() ) ) + { + if ( lfm.attribute( "status" ) == "ok") + loved = Track::Unloved; + } + + emit loveToggled( loved == Track::Loved ); +} + +void +lastfm::TrackData::onGotInfo() +{ + Observer observer; + + for ( int i = 0 ; i < observers.count() ; ++i ) + { + if ( observers.at( i ).reply == sender() ) + { + observer = observers.takeAt( i ); + break; + } + } + + const QByteArray data = static_cast(sender())->readAll(); + + lastfm::XmlQuery lfm; + + if ( lfm.parse( data ) ) + { + qDebug() << lfm; + + QString imageUrl = lfm["track"]["image size=small"].text(); + if ( !imageUrl.isEmpty() ) m_images[AbstractType::SmallImage] = imageUrl; + imageUrl = lfm["track"]["image size=medium"].text(); + if ( !imageUrl.isEmpty() ) m_images[AbstractType::MediumImage] = imageUrl; + imageUrl = lfm["track"]["image size=large"].text(); + if ( !imageUrl.isEmpty() ) m_images[AbstractType::LargeImage] = imageUrl; + imageUrl = lfm["track"]["image size=extralarge"].text(); + if ( !imageUrl.isEmpty() ) m_images[AbstractType::ExtraLargeImage] = imageUrl; + imageUrl = lfm["track"]["image size=mega"].text(); + if ( !imageUrl.isEmpty() ) m_images[AbstractType::MegaImage] = imageUrl; + + if ( lfm["track"]["userloved"].text().length() > 0 ) + loved = lfm["track"]["userloved"].text() == "0" ? Track::Unloved : Track::Loved; + + if ( observer.receiver ) + if ( !QMetaObject::invokeMethod( observer.receiver, observer.method, Q_ARG(QByteArray, data) ) ) + QMetaObject::invokeMethod( observer.receiver, observer.method ); + + emit loveToggled( loved == Track::Loved ); + } + else + { + if ( observer.receiver ) + if ( !QMetaObject::invokeMethod( observer.receiver, observer.method, Q_ARG(QByteArray, data) ) ) + QMetaObject::invokeMethod( observer.receiver, observer.method ); + } +} + +void +lastfm::TrackData::forceLoveToggled( bool love ) +{ + emit loveToggled( love ); +} + +void +lastfm::TrackData::forceScrobbleStatusChanged() +{ + emit scrobbleStatusChanged( scrobbleStatus ); +} + +void +lastfm::TrackData::forceCorrected( QString correction ) +{ + emit corrected( correction ); +} + + +lastfm::Track& +lastfm::Track::operator=( const Track& that ) +{ + d = that.d; + return *this; +} + +lastfm::Track::~Track() +{ +} + +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( d->loved ) ); + makeElement( "scrobbleStatus", QString::number( scrobbleStatus() ) ); + makeElement( "scrobbleError", QString::number( scrobbleError() ) ); + makeElement( "scrobbleErrorText", scrobbleErrorText() ); + makeElement( "podcast", QString::number( isPodcast() ) ); + makeElement( "video", QString::number( isVideo() ) ); + + // 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 ); + } + + QDomElement artistElement = xml.createElement( "artistImages" ); + + for ( int size = SmallImage ; size <= MegaImage ; ++size ) + { + QString imageUrl = d->artist.imageUrl( static_cast(size) ).toString(); + + if ( !imageUrl.isEmpty() ) + { + QDomElement e = xml.createElement( "image" ); + e.appendChild( xml.createTextNode( d->artist.imageUrl( static_cast(size) ).toString() ) ); + e.setAttribute( "size", size ); + artistElement.appendChild( e ); + } + } + + if ( artistElement.childNodes().count() != 0 ) + item.appendChild( artistElement ); + + QDomElement albumElement = xml.createElement( "albumImages" ); + + for ( int size = SmallImage ; size <= MegaImage ; ++size ) + { + QString imageUrl = d->album.imageUrl( static_cast(size) ).toString(); + + if ( !imageUrl.isEmpty() ) + { + QDomElement e = xml.createElement( "image" ); + e.appendChild( xml.createTextNode( d->album.imageUrl( static_cast(size) ).toString() ) ); + e.setAttribute( "size", size ); + albumElement.appendChild( e ); + } + } + + if ( albumElement.childNodes().count() != 0 ) + item.appendChild( albumElement ); + + // 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.toString().isEmpty() && (d->correctedAlbum.toString() != d->album.toString())) + || (!d->correctedArtist.isNull() && (d->correctedArtist.name() != d->artist.name())) + || (!d->correctedAlbumArtist.isNull() && (d->correctedAlbumArtist.name() != d->albumArtist.name()))); +} + +lastfm::Artist +lastfm::Track::artist( Corrections corrected ) const +{ + if ( corrected == Corrected && !d->correctedArtist.name().isEmpty() ) + return d->correctedArtist; + + return d->artist; +} + +lastfm::Artist +lastfm::Track::albumArtist( Corrections corrected ) const +{ + if ( corrected == Corrected && !d->correctedAlbumArtist.name().isEmpty() ) + return d->correctedAlbumArtist; + + return d->albumArtist; +} + +lastfm::Album +lastfm::Track::album( Corrections corrected ) const +{ + if ( corrected == Corrected && !d->correctedAlbum.title().isEmpty() ) + return d->correctedAlbum; + + return 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; +} + + +QUrl +lastfm::Track::imageUrl( 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.name().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::MutableTrack::setFromLfm( const XmlQuery& lfm ) +{ + QString imageUrl = lfm["track"]["image size=small"].text(); + if ( !imageUrl.isEmpty() ) d->m_images[SmallImage] = imageUrl; + imageUrl = lfm["track"]["image size=medium"].text(); + if ( !imageUrl.isEmpty() ) d->m_images[MediumImage] = imageUrl; + imageUrl = lfm["track"]["image size=large"].text(); + if ( !imageUrl.isEmpty() ) d->m_images[LargeImage] = imageUrl; + imageUrl = lfm["track"]["image size=extralarge"].text(); + if ( !imageUrl.isEmpty() ) d->m_images[ExtraLargeImage] = imageUrl; + imageUrl = lfm["track"]["image size=mega"].text(); + if ( !imageUrl.isEmpty() ) d->m_images[MegaImage] = imageUrl; + + if ( lfm["track"]["userloved"].text().length() > 0) + d->loved = lfm["track"]["userloved"].text() == "0" ? Unloved : Loved; + + d->forceLoveToggled( d->loved == Loved ); +} + +void +lastfm::MutableTrack::setImageUrl( ImageSize size, const QString& url ) +{ + if ( !url.isEmpty() ) + d->m_images[size] = url; +} + + +void +lastfm::MutableTrack::love() +{ + QNetworkReply* reply = ws::post(params("love")); + QObject::connect( reply, SIGNAL(finished()), signalProxy(), SLOT(onLoveFinished())); +} + + +void +lastfm::MutableTrack::unlove() +{ + QNetworkReply* reply = ws::post(params("unlove")); + QObject::connect( reply, SIGNAL(finished()), signalProxy(), SLOT(onUnloveFinished())); +} + +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; + + if ( lfm.parse( 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.message(); + } + + 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( QObject *receiver, const char *method, const QString &username ) const +{ + QMap map = params("getInfo", true); + if (!username.isEmpty()) map["username"] = username; + + // this is so the web services knows whether to use corrections or not + if (!lastfm::ws::SessionKey.isEmpty()) map["sk"] = lastfm::ws::SessionKey; + + qDebug() << map; + + QNetworkReply* reply = ws::get( map ); + + TrackData::Observer observer; + observer.receiver = receiver; + observer.method = method; + observer.reply = reply; + d->observers << observer; + + QObject::connect( reply, 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.title().isEmpty() ) map["album"] = d->album.title(); + map["chosenByUser"] = source() == Track::LastFmRadio ? "0" : "1"; + + 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(); + map["chosenByUser[" + QString::number(i) + "]"] = tracks[i].source() == Track::LastFmRadio ? "0" : "1"; + } + + 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 ); +} + +bool +lastfm::Track::sameObject( const Track& that ) +{ + return (this->d == that.d); +} + +bool +lastfm::Track::operator==( const Track& that ) const +{ + return ( title( Corrected ) == that.title( Corrected ) + // if either album is empty, assume they are the same album + && ( album( Corrected ).title().isEmpty() || that.album( Corrected ).title().isEmpty() || album( Corrected ) == that.album( Corrected )) + && artist( Corrected ) == that.artist( Corrected )); +} + +bool +lastfm::Track::operator!=( const Track& that ) const +{ + return !operator==( that ); +} + +const QObject* +lastfm::Track::signalProxy() const +{ + return d.data(); +} + +bool +lastfm::Track::isNull() const +{ + return d->null; +} + +uint +lastfm::Track::trackNumber() const +{ return d->trackNumber; } +uint +lastfm::Track::duration() const +{ + // in seconds + return d->duration; +} + +lastfm::Mbid +lastfm::Track::mbid() const +{ + return lastfm::Mbid(d->mbid); } +QUrl +lastfm::Track::url() const +{ + return d->url; } +QDateTime +lastfm::Track::timestamp() const +{ + return d->time; +} + +lastfm::Track::Source +lastfm::Track::source() const +{ + return static_cast(d->source); +} + +uint +lastfm::Track::fingerprintId() const +{ + return d->fpid; +} + +bool +lastfm::Track::isLoved() const +{ + return d->loved == Loved; +} + +lastfm::Track::LoveStatus +lastfm::Track::loveStatus() const +{ + return d->loved; +} + + +QString +lastfm::Track::durationString() const +{ + return durationString( d->duration ); +} + + +lastfm::Track::ScrobbleStatus +lastfm::Track::scrobbleStatus() const +{ + return static_cast(d->scrobbleStatus); +} + +lastfm::Track::ScrobbleError +lastfm::Track::scrobbleError() const +{ + return static_cast(d->scrobbleError); +} +QString +lastfm::Track::scrobbleErrorText() const +{ + return d->scrobbleErrorText; +} + +/** default separator is an en-dash */ +QString +lastfm::Track::toString() const +{ + return toString( Corrected ); +} + +QString +lastfm::Track::toString( Corrections corrections ) const +{ + return toString( QChar(8211), corrections ); +} + +lastfm::TrackContext +lastfm::Track::context() const +{ + return d->context; +} + +// iTunes tracks might be podcasts or videos +bool +lastfm::Track::isPodcast() const +{ + return d->podcast; +} + +bool +lastfm::Track::isVideo() const +{ + return d->video; +} + +QString +lastfm::Track::extra( const QString& key ) const +{ + return d->extras[ key ]; +} + +bool lastfm::Track::operator<( const Track &that ) const +{ + return this->d->time < that.d->time; +} + +lastfm::Track::operator QVariant() const +{ + return QVariant::fromValue( *this ); +} + +void +lastfm::MutableTrack::setCorrections( QString title, QString album, QString artist, QString albumArtist ) +{ + d->correctedTitle = title; + d->correctedArtist = artist; + d->correctedAlbum = Album( artist, album ); + d->correctedAlbumArtist = albumArtist; + + d->forceCorrected( toString() ); +} + +lastfm::MutableTrack::MutableTrack() +{ + d->null = false; +} + + +lastfm::MutableTrack::MutableTrack( const Track& that ) + : Track( that ) +{ + d->null = false; +} + +void +lastfm::MutableTrack::setArtist( QString artist ) +{ + d->artist.setName( artist.trimmed() ); + d->album.setArtist( artist.trimmed() ); + d->correctedAlbum.setArtist( artist.trimmed() ); +} + +void +lastfm::MutableTrack::setAlbumArtist( QString albumArtist ) +{ + d->albumArtist.setName( albumArtist.trimmed() ); +} + +void +lastfm::MutableTrack::setAlbum( QString album ) +{ + d->album = Album( d->artist.name(), album.trimmed() ); +} + +void +lastfm::MutableTrack::setTitle( QString title ) +{ + d->title = title.trimmed(); +} + +void +lastfm::MutableTrack::setTrackNumber( uint n ) +{ + d->trackNumber = n; +} + +void +lastfm::MutableTrack::setDuration( uint duration ) +{ + d->duration = duration; +} + +void +lastfm::MutableTrack::setUrl( QUrl url ) +{ + d->url = url; +} + +void +lastfm::MutableTrack::setSource( Source s ) +{ + d->source = s; +} + +void +lastfm::MutableTrack::setLoved( bool loved ) +{ + d->loved = loved ? Loved : Unloved; +} + +void +lastfm::MutableTrack::setMbid( Mbid id ) +{ + d->mbid = id; +} + +void +lastfm::MutableTrack::setFingerprintId( uint id ) +{ + d->fpid = id; +} + +void +lastfm::MutableTrack::setScrobbleStatus( ScrobbleStatus scrobbleStatus ) +{ + d->scrobbleStatus = scrobbleStatus; + d->forceScrobbleStatusChanged(); +} + +void +lastfm::MutableTrack::setScrobbleError( ScrobbleError scrobbleError ) +{ + d->scrobbleError = scrobbleError; +} + +void +lastfm::MutableTrack::setScrobbleErrorText( const QString& scrobbleErrorText ) +{ + d->scrobbleErrorText = scrobbleErrorText; +} + +void +lastfm::MutableTrack::stamp() +{ + d->time = QDateTime::currentDateTime(); +} + +void +lastfm::MutableTrack::setExtra( const QString& key, const QString& value ) +{ + d->extras[key] = value; +} + +void +lastfm::MutableTrack::removeExtra( QString key ) +{ + d->extras.remove( key ); +} + +void +lastfm::MutableTrack::setTimeStamp( const QDateTime& dt ) +{ + d->time = dt; +} + +void +lastfm::MutableTrack::setContext( TrackContext context ) +{ + d->context = context; +} + +// iTunes tracks might be podcasts or videos +void +lastfm::MutableTrack::setPodcast( bool podcast ) +{ + d->podcast = podcast; +} +void +lastfm::MutableTrack::setVideo( bool video ) +{ + d->video = video; +} + +QDebug +operator<<( QDebug d, const lastfm::Track& t ) +{ + return !t.isNull() + ? d << t.toString( '-' ) << t.url() + : d << "Null Track object"; +} + +#include "Track.moc" diff -Nru liblastfm-0.4.0~really0.3.3/src/Track.h liblastfm-1.0.1/src/Track.h --- liblastfm-0.4.0~really0.3.3/src/Track.h 1970-01-01 00:00:00.000000000 +0000 +++ liblastfm-1.0.1/src/Track.h 2012-06-18 10:37:51.000000000 +0000 @@ -0,0 +1,303 @@ +/* + 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 "Album.h" + +namespace lastfm { + +class TrackData; + +class LASTFM_DLLEXPORT TrackContext +{ +public: + enum Type + { + UnknownType, + User, + Friend, + Neighbour, + Artist + }; + + TrackContext(); + TrackContext( const QString& type, const QList& values ); + TrackContext( const TrackContext& that ); + ~TrackContext(); + + Type type() const; + QList values() const; + TrackContext& operator=( const TrackContext& that ); + +private: + class TrackContextPrivate * const d; +}; + + +/** 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: + 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 + + UnknownSource = 0, + LastFmRadio, + Player, + MediaDevice, + NonPersonalisedBroadcast, // eg Shoutcast, BBC Radio 1, etc. + PersonalisedRecommendation // eg Pandora, but not Last.fm + }; + + enum LoveStatus + { + UnknownLoveStatus = 0, + Loved, + Unloved + }; + + 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& ); + Track( const Track& that ); + ~Track(); + + /** 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 ); + bool operator==( const Track& that ) const; + bool operator!=( const Track& that ) const; + Track& operator=( const Track& that ); + + /** + * Track's private class emits three signals that may be useful for + * applications: + * + * loveToggled( bool love ) + * scrobbleStatusChanged( short scrobbleStatus ) + * corrected( QString correction ) + * + * signalProxy() lets applications connect to them. + * */ + const QObject* signalProxy() const; + + /** only a Track() is null */ + bool isNull() const; + + 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; + uint duration() const; // in seconds + Mbid mbid() const; + QUrl url() const; + QDateTime timestamp() const; + Source source() const; + uint fingerprintId() const; + bool isLoved() const; + LoveStatus loveStatus() const; + QUrl imageUrl( ImageSize size, bool square ) const; + + QString durationString() const; + static QString durationString( int seconds ); + + ScrobbleStatus scrobbleStatus() const; + ScrobbleError scrobbleError() const; + QString scrobbleErrorText() const; + + /** default separator is an en-dash */ + QString toString() const; + QString toString( Corrections corrections ) const; + 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; + + // iTunes tracks might be podcasts or videos + bool isPodcast() const; + bool isVideo() const; + + QString extra( const QString& key ) const; + + bool operator<( const Track &that ) const; + + bool isMp3() const; + + operator QVariant() const; + +//////////// 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; + + /** method should be a method name of reciever that takes a QByteArray + If that fails it will try invoking method with no arguments. + */ + void getInfo( QObject* receiver, const char * method, const QString& username = "" ) 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; +}; + + + +/** 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(); + + /** 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 ); + + void setFromLfm( const XmlQuery& lfm ); + void setImageUrl( ImageSize size, const QString& url ); + + void setArtist( QString artist ); + void setAlbumArtist( QString albumArtist ); + void setAlbum( QString album ); + void setTitle( QString title ); + void setCorrections( QString title, QString album, QString artist, QString albumArtist ); + void setTrackNumber( uint n ); + void setDuration( uint duration ); + void setUrl( QUrl url ); + void setSource( Source s ); + void setLoved( bool loved ); + + void setMbid( Mbid id ); + void setFingerprintId( uint id ); + + void setScrobbleStatus( ScrobbleStatus scrobbleStatus ); + void setScrobbleError( ScrobbleError scrobbleError ); + void setScrobbleErrorText( const QString& scrobbleErrorText ); + + void love(); + void unlove(); + QNetworkReply* ban(); + + void stamp(); + + void setExtra( const QString& key, const QString& value ); + void removeExtra( QString key ); + void setTimeStamp( const QDateTime& dt ); + + void setContext( TrackContext context ); + + // iTunes tracks might be podcasts or videos + void setPodcast( bool podcast ); + void setVideo( bool video ); + +}; + + +} //namespace lastfm + + +LASTFM_DLLEXPORT QDebug operator<<( QDebug d, const lastfm::Track& t ); + +Q_DECLARE_METATYPE( lastfm::Track ) + +#endif //LASTFM_TRACK_H diff -Nru liblastfm-0.4.0~really0.3.3/src/types/Album.cpp liblastfm-1.0.1/src/types/Album.cpp --- liblastfm-0.4.0~really0.3.3/src/types/Album.cpp 2010-09-25 17:30:01.000000000 +0000 +++ liblastfm-1.0.1/src/types/Album.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -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 . -*/ -#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; - 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 User& recipient, const QString& message ) -{ - QMap map; - map["method"] = "album.share"; - map["artist"] = m_artist; - map["album"] = m_title; - map["recipient"] = recipient; - 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 -Nru liblastfm-0.4.0~really0.3.3/src/types/Album.h liblastfm-1.0.1/src/types/Album.h --- liblastfm-0.4.0~really0.3.3/src/types/Album.h 2010-09-25 17:30:01.000000000 +0000 +++ liblastfm-1.0.1/src/types/Album.h 1970-01-01 00:00:00.000000000 +0000 @@ -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 class User& recipient, const QString& message = "" ); - - /** 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 -Nru liblastfm-0.4.0~really0.3.3/src/types/Artist.cpp liblastfm-1.0.1/src/types/Artist.cpp --- liblastfm-0.4.0~really0.3.3/src/types/Artist.cpp 2010-09-25 17:30:01.000000000 +0000 +++ liblastfm-1.0.1/src/types/Artist.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,168 +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 -using lastfm::Artist; -using lastfm::User; - - -QMap //private -Artist::params( const QString& method ) const -{ - QMap map; - map["method"] = "artist."+method; - map["artist"] = m_name; - return map; -} - -QNetworkReply* -Artist::share( const User& user, const QString& message ) -{ - QMap map = params("share"); - map["recipient"] = user; - if (message.size()) map["message"] = message; - return lastfm::ws::post(map); -} - - -QUrl -Artist::www() const -{ - return UrlBuilder( "music" ).slash( Artist::name() ).url(); -} - -QNetworkReply* -Artist::getInfo() const -{ - return ws::get( params("getInfo") ); -} - - -QNetworkReply* -Artist::getTags() const -{ - return ws::get( params("getTags") ); -} - -QNetworkReply* -Artist::getTopTags() const -{ - return ws::get( params("getTopTags") ); -} - - -QNetworkReply* -Artist::getSimilar() const -{ - return ws::get( params("getSimilar") ); -} - - -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 = ws::parse(r); - 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; -} - - -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; -} - - -QList /* static */ -Artist::list( QNetworkReply* r ) -{ - QList artists; - try { - XmlQuery lfm = ws::parse(r); - foreach (XmlQuery xq, lfm.children( "artist" )) { - Artist artist = xq["name"].text(); - artist.m_images = images( xq ); - artists += artist; - } - } - catch (ws::ParseError& e) - { - qWarning() << e.what(); - } - return artists; -} - - -Artist -Artist::getInfo( QNetworkReply* r ) -{ - try { - XmlQuery lfm = ws::parse(r); - 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 -Nru liblastfm-0.4.0~really0.3.3/src/types/Artist.h liblastfm-1.0.1/src/types/Artist.h --- liblastfm-0.4.0~really0.3.3/src/types/Artist.h 2010-09-25 17:30:01.000000000 +0000 +++ liblastfm-1.0.1/src/types/Artist.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,89 +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_ARTIST_H -#define LASTFM_ARTIST_H - -#include -#include -#include -#include - -namespace lastfm -{ - class LASTFM_DLLEXPORT Artist - { - QString m_name; - QList m_images; - - public: - Artist() - {} - - Artist( const QString& name ) : m_name( name ) - {} - - /** will be QUrl() unless you got this back from a getInfo or something call */ - QUrl imageUrl( ImageSize size = Large ) const { return m_images.value( size ); } - - bool isNull() const { return m_name.isEmpty(); } - - /** the url for this artist's page at www.last.fm */ - QUrl www() const; - - 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 name() const { return QString(*this); } - - QNetworkReply* share( const class User& recipient, const QString& message = "" ); - - QNetworkReply* getInfo() const; - static Artist getInfo( QNetworkReply* ); - - QNetworkReply* getSimilar() 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; - - /** 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 -Nru liblastfm-0.4.0~really0.3.3/src/types/FingerprintId.cpp liblastfm-1.0.1/src/types/FingerprintId.cpp --- liblastfm-0.4.0~really0.3.3/src/types/FingerprintId.cpp 2010-09-25 17:30:01.000000000 +0000 +++ liblastfm-1.0.1/src/types/FingerprintId.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -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 -Nru liblastfm-0.4.0~really0.3.3/src/types/FingerprintId.h liblastfm-1.0.1/src/types/FingerprintId.h --- liblastfm-0.4.0~really0.3.3/src/types/FingerprintId.h 2010-09-25 17:30:01.000000000 +0000 +++ liblastfm-1.0.1/src/types/FingerprintId.h 1970-01-01 00:00:00.000000000 +0000 @@ -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 -Nru liblastfm-0.4.0~really0.3.3/src/types/Mbid.cpp liblastfm-1.0.1/src/types/Mbid.cpp --- liblastfm-0.4.0~really0.3.3/src/types/Mbid.cpp 2010-09-25 17:30:01.000000000 +0000 +++ liblastfm-1.0.1/src/types/Mbid.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -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 -Nru liblastfm-0.4.0~really0.3.3/src/types/Mbid.h liblastfm-1.0.1/src/types/Mbid.h --- liblastfm-0.4.0~really0.3.3/src/types/Mbid.h 2010-09-25 17:30:01.000000000 +0000 +++ liblastfm-1.0.1/src/types/Mbid.h 1970-01-01 00:00:00.000000000 +0000 @@ -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 -Nru liblastfm-0.4.0~really0.3.3/src/types/mbid_mp3.c liblastfm-1.0.1/src/types/mbid_mp3.c --- liblastfm-0.4.0~really0.3.3/src/types/mbid_mp3.c 2010-09-25 17:30:01.000000000 +0000 +++ liblastfm-1.0.1/src/types/mbid_mp3.c 1970-01-01 00:00:00.000000000 +0000 @@ -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 -Nru liblastfm-0.4.0~really0.3.3/src/types/Playlist.cpp liblastfm-1.0.1/src/types/Playlist.cpp --- liblastfm-0.4.0~really0.3.3/src/types/Playlist.cpp 2010-09-25 17:30:01.000000000 +0000 +++ liblastfm-1.0.1/src/types/Playlist.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -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 -Nru liblastfm-0.4.0~really0.3.3/src/types/Playlist.h liblastfm-1.0.1/src/types/Playlist.h --- liblastfm-0.4.0~really0.3.3/src/types/Playlist.h 2010-09-25 17:30:01.000000000 +0000 +++ liblastfm-1.0.1/src/types/Playlist.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,53 +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 ); - - static Xspf fetch( QNetworkReply* ); - }; -} - -#endif diff -Nru liblastfm-0.4.0~really0.3.3/src/types/Tag.cpp liblastfm-1.0.1/src/types/Tag.cpp --- liblastfm-0.4.0~really0.3.3/src/types/Tag.cpp 2010-09-25 17:30:01.000000000 +0000 +++ liblastfm-1.0.1/src/types/Tag.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -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 . -*/ -#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); -} - - -QMap //static -Tag::list( QNetworkReply* r ) -{ - QMap tags; - try { - foreach (XmlQuery xq, XmlQuery(ws::parse(r)).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 -Nru liblastfm-0.4.0~really0.3.3/src/types/Tag.h liblastfm-1.0.1/src/types/Tag.h --- liblastfm-0.4.0~really0.3.3/src/types/Tag.h 2010-09-25 17:30:01.000000000 +0000 +++ liblastfm-1.0.1/src/types/Tag.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,57 +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; } - - /** 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 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 -Nru liblastfm-0.4.0~really0.3.3/src/types/Track.cpp liblastfm-1.0.1/src/types/Track.cpp --- liblastfm-0.4.0~really0.3.3/src/types/Track.cpp 2010-09-25 17:30:01.000000000 +0000 +++ liblastfm-1.0.1/src/types/Track.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,239 +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 "Track.h" -#include "User.h" -#include "../core/UrlBuilder.h" -#include "../core/XmlQuery.h" -#include "../ws/ws.h" -#include -#include - - -lastfm::Track::Track() -{ - d = new TrackData; - d->null = true; -} - - -lastfm::Track::Track( const QDomElement& e ) -{ - d = new TrackData; - - if (e.isNull()) { d->null = true; return; } - - d->artist = e.namedItem( "artist" ).toElement().text(); - d->album = e.namedItem( "album" ).toElement().text(); - d->title = e.namedItem( "track" ).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() ); - - 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(); - } -} - - -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( "album", d->album ); - makeElement( "track", d->title ); - 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() ); - - QDomElement extras = xml.createElement( "extras" ); - QMapIterator i( d->extras ); - while (i.hasNext()) { - QDomElement e = xml.createElement( i.next().key() ); - e.appendChild( xml.createTextNode( i.value() ) ); - extras.appendChild( e ); - } - item.appendChild( extras ); - - return item; -} - - -QString -lastfm::Track::toString( const QChar& separator ) const -{ - if ( d->artist.isEmpty() ) - { - if ( d->title.isEmpty() ) - return QFileInfo( d->url.path() ).fileName(); - else - return d->title; - } - - if ( d->title.isEmpty() ) - return d->artist; - - return d->artist + ' ' + separator + ' ' + d->title; -} - - -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 User& recipient, const QString& message ) -{ - QMap map = params("share"); - map["recipient"] = recipient; - if (message.size()) map["message"] = message; - return ws::post(map); -} - - -QNetworkReply* -lastfm::MutableTrack::love() -{ - if (d->extras.value("rating").size()) - return 0; - d->extras["rating"] = "L"; - return ws::post(params("love")); -} - - -QNetworkReply* -lastfm::MutableTrack::ban() -{ - d->extras["rating"] = "B"; - return ws::post(params("ban")); -} - - -void -lastfm::MutableTrack::unlove() -{ - QString& r = d->extras["rating"]; - if (r == "L") r = ""; -} - - -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::getTopTags() const -{ - return ws::get( params("getTopTags", true) ); -} - - -QNetworkReply* -lastfm::Track::getTags() const -{ - return ws::get( params("getTags", true) ); -} - - -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); -} - - -QUrl -lastfm::Track::www() const -{ - return UrlBuilder( "music" ).slash( d->artist ).slash( "_" ).slash( d->title ).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 ); -} - - -lastfm::Track -lastfm::Track::clone() const -{ - Track copy( *this ); - copy.d.detach(); - return copy; -} diff -Nru liblastfm-0.4.0~really0.3.3/src/types/Track.h liblastfm-1.0.1/src/types/Track.h --- liblastfm-0.4.0~really0.3.3/src/types/Track.h 2010-09-25 17:30:01.000000000 +0000 +++ liblastfm-1.0.1/src/types/Track.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,248 +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_TRACK_H -#define LASTFM_TRACK_H - -#include -#include -#include -#include -#include -#include -#include -#include - - -namespace lastfm { - - -struct TrackData : QSharedData -{ - TrackData(); - - QString artist; - QString album; - QString title; - 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 - - //FIXME I hate this, but is used for radio trackauth etc. - QMap extras; - - bool null; -}; - - - -/** 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: - 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 - }; - - Track(); - explicit Track( const QDomElement& ); - - /** if you plan to use this track in a separate thread, you need to clone it - * first, otherwise nothing is thread-safe, not this creates a disconnected - * Track object, modifications to this or that will not effect that or this - */ - Track clone() const; - - /** 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 operator==( const Track& that ) const - { - return this->d == that.d; - } - bool operator!=( const Track& that ) const - { - return !operator==( that ); - } - - /** only a Track() is null */ - bool isNull() const { return d->null; } - - Artist artist() const { return Artist( d->artist ); } - Album album() const { return Album( artist(), d->album ); } - QString title() 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! */ - return d->title.isEmpty() ? "[unknown]" : d->title; - } - 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 (Source)d->source; } - uint fingerprintId() const { return d->fpid; } - - QString durationString() const { return durationString( d->duration ); } - static QString durationString( int seconds ); - - /** default separator is an en-dash */ - QString toString( const QChar& separator = QChar(8211) ) const; - /** the standard representation of this object as an XML node */ - QDomElement toDomElement( class QDomDocument& ) const; - - 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 class User& recipient, const QString& message = "" ); - - /** you can get any QNetworkReply TagList using Tag::list( QNetworkReply* ) */ - QNetworkReply* getTags() const; // for the logged in user - QNetworkReply* getTopTags() 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; - - /** 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; - -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 setArtist( QString artist ) { d->artist = artist.trimmed(); } - void setAlbum( QString album ) { d->album = album.trimmed(); } - void setTitle( QString title ) { d->title = title.trimmed(); } - 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 setMbid( Mbid id ) { d->mbid = id; } - void setFingerprintId( uint id ) { d->fpid = id; } - - /** you also must scrobble this track for the love to become permenant */ - QNetworkReply* love(); - QNetworkReply* ban(); - - /** currently doesn't work, as there is no webservice */ - void unlove(); - - 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 ); } -}; - - -inline -TrackData::TrackData() - : trackNumber( 0 ), - duration( 0 ), - source( Track::Unknown ), - rating( 0 ), - fpid( -1 ), - null( false ) -{} - - -} //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 -Nru liblastfm-0.4.0~really0.3.3/src/types/User.cpp liblastfm-1.0.1/src/types/User.cpp --- liblastfm-0.4.0~really0.3.3/src/types/User.cpp 2010-09-25 17:30:01.000000000 +0000 +++ liblastfm-1.0.1/src/types/User.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,200 +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 "../core/UrlBuilder.h" -#include "../core/XmlQuery.h" -#include -using lastfm::User; -using lastfm::AuthenticatedUser; - - -QMap -User::params(const QString& method) const -{ - QMap map; - map["method"] = "user."+method; - map["user"] = m_name; - return map; -} - - -QNetworkReply* -User::getFriends() const -{ - return ws::get( params( "getFriends" ) ); -} - - -QNetworkReply* -User::getTopTags() const -{ - return ws::get( params( "getTopTags" ) ); -} - - -QNetworkReply* -User::getTopArtists() const -{ - return ws::get( params( "getTopArtists" ) ); -} - - -QNetworkReply* -User::getRecentArtists() const -{ - return ws::get( params( "getRecentArtists" ) ); -} - - -QNetworkReply* -User::getRecentTracks() const -{ - return ws::get( params( "getRecentTracks" ) ); -} - -QNetworkReply* -User::getRecentStations() const -{ - return ws::post( params( "getRecentStations" ) ); -} - -QNetworkReply* -User::getNeighbours() const -{ - return ws::get( params( "getNeighbours" ) ); -} - - -QNetworkReply* -User::getPlaylists() const -{ - return ws::get( params( "getPlaylists" ) ); -} - - -QList //static -User::list( QNetworkReply* r ) -{ - QList users; - try { - XmlQuery lfm = ws::parse(r); - foreach (XmlQuery e, lfm.children( "user" )) - { - User u( e["name"].text() ); - u.m_smallImage = e["image size=small"].text(); - u.m_mediumImage = e["image size=medium"].text(); - u.m_largeImage = e["image size=large"].text(); - u.m_realName = e["realname"].text(); - users += u; - } - } - catch (ws::ParseError& e) - { - qWarning() << e.what(); - } - return users; -} - - -QNetworkReply* //static -AuthenticatedUser::getInfo() -{ - QMap map; - map["method"] = "user.getInfo"; - return ws::post( map ); -} - - -QNetworkReply* //static -AuthenticatedUser::getRecommendedArtists() -{ - QMap map; - map["method"] = "user.getRecommendedArtists"; - return ws::post( map ); -} - - -QUrl -User::www() const -{ - return UrlBuilder( "user" ).slash( m_name ).url(); -} - - -QString //static -AuthenticatedUser::getInfoString( QNetworkReply* reply ) -{ - #define tr QObject::tr - - class Gender - { - QString s; - - public: - 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() - { - QStringList list; - if (male()) - list << tr("boy") << tr("lad") << tr("chap") << tr("guy"); - else if (female()) - // I'm not sexist, it's just I'm gutless and couldn't think - // of any other non offensive terms for women! - list << tr("girl") << tr("lady") << tr("lass"); - else - return tr("person"); - - return list.value( QDateTime::currentDateTime().toTime_t() % list.count() ); - } - }; - - QString text; - try - { - XmlQuery user = XmlQuery(ws::parse(reply))["user"]; - Gender gender = user["gender"].text(); - QString age = user["age"].text(); - uint const scrobbles = user["playcount"].text().toUInt(); - if (gender.known() && age.size() && scrobbles > 0) - { - text = tr("A %1, %2 years of age with %L3 scrobbles") - .arg( gender.toString() ) - .arg( age ) - .arg( scrobbles ); - } - else if (scrobbles > 0) - { - text = tr("%L1 scrobbles").arg( scrobbles ); - } - } - catch (ws::ParseError& e) - { - qWarning() << e.what(); - } - return text; - - #undef tr -} diff -Nru liblastfm-0.4.0~really0.3.3/src/types/User.h liblastfm-1.0.1/src/types/User.h --- liblastfm-0.4.0~really0.3.3/src/types/User.h 2010-09-25 17:30:01.000000000 +0000 +++ liblastfm-1.0.1/src/types/User.h 1970-01-01 00:00:00.000000000 +0000 @@ -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 . -*/ -#ifndef LASTFM_USER_H -#define LASTFM_USER_H - -#include -#include -#include - -namespace lastfm -{ - class LASTFM_DLLEXPORT User - { - QString m_name; - - public: - User( const QString& name ) : m_name( name ), m_match( -1.0f ) - {} - - operator QString() const { return m_name; } - QString name() const { return m_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() const; - QNetworkReply* getNeighbours() const; - - QNetworkReply* getPlaylists() const; - QNetworkReply* getTopArtists() const; - QNetworkReply* getRecentTracks() const; - QNetworkReply* getRecentArtists() const; - QNetworkReply* getRecentStations() const; - - static QList list( QNetworkReply* ); - - ////// - QUrl smallImageUrl() const { return m_smallImage; } - QUrl mediumImageUrl() const { return m_mediumImage; } - QUrl largeImageUrl() const { return m_largeImage; } - - 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; } - - private: - QUrl m_smallImage; - QUrl m_mediumImage; - QUrl m_largeImage; - - float m_match; - - QString m_realName; - - QMap params( const QString& method ) const; - }; - - - /** The authenticated user is special, as some webservices only work for him */ - class LASTFM_DLLEXPORT AuthenticatedUser : public User - { - using User::match; //hide as not useful - - public: - /** the authenticated User */ - AuthenticatedUser() : User( lastfm::ws::Username ) - {} - - /** you can only get information about the autheticated user */ - static QNetworkReply* getInfo(); - - /** a verbose string, eg. "A man with 36,153 scrobbles" */ - static QString getInfoString( QNetworkReply* ); - - // 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(); - }; -} - -#endif diff -Nru liblastfm-0.4.0~really0.3.3/src/types/Xspf.cpp liblastfm-1.0.1/src/types/Xspf.cpp --- liblastfm-0.4.0~really0.3.3/src/types/Xspf.cpp 2010-09-25 17:30:01.000000000 +0000 +++ liblastfm-1.0.1/src/types/Xspf.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,48 +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 "Xspf.h" -#include "../core/XmlQuery.h" -#include - -lastfm::Xspf::Xspf( const QDomElement& playlist_node ) -{ - XmlQuery e( playlist_node ); - - 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 ); - m_tracks += t; // outside try block since location is enough basically - } -} diff -Nru liblastfm-0.4.0~really0.3.3/src/types/Xspf.h liblastfm-1.0.1/src/types/Xspf.h --- liblastfm-0.4.0~really0.3.3/src/types/Xspf.h 2010-09-25 17:30:01.000000000 +0000 +++ liblastfm-1.0.1/src/types/Xspf.h 1970-01-01 00:00:00.000000000 +0000 @@ -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 . -*/ -#ifndef LASTFM_XSPF_H -#define LASTFM_XSPF_H - -#include -#include - -namespace lastfm -{ - class LASTFM_DLLEXPORT Xspf - { - public: - /** pass in the playlist node! */ - Xspf( const class QDomElement& playlist_node ); - - QList tracks() const { return m_tracks; } - QString title() const{ return m_title; } - - private: - QList m_tracks; - QString m_title; - }; -} - -#endif diff -Nru liblastfm-0.4.0~really0.3.3/src/UrlBuilder.cpp liblastfm-1.0.1/src/UrlBuilder.cpp --- liblastfm-0.4.0~really0.3.3/src/UrlBuilder.cpp 1970-01-01 00:00:00.000000000 +0000 +++ liblastfm-1.0.1/src/UrlBuilder.cpp 2012-06-18 10:37:51.000000000 +0000 @@ -0,0 +1,143 @@ +/* + 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 + + +class lastfm::UrlBuilderPrivate +{ +public: + QByteArray path; +}; + + +lastfm::UrlBuilder::UrlBuilder( const QString& base ) + : d( new UrlBuilderPrivate ) +{ + d->path = '/' + base.toAscii(); +} + + +lastfm::UrlBuilder::UrlBuilder( const UrlBuilder& that ) + : d( new UrlBuilderPrivate( *that.d ) ) +{ +} + + +lastfm::UrlBuilder::~UrlBuilder() +{ + delete d; +} + + +lastfm::UrlBuilder& +lastfm::UrlBuilder::slash( const QString& path ) +{ + this->d->path += '/' + encode( path ); + return *this; +} + + +QUrl +lastfm::UrlBuilder::url() const +{ + QUrl url; + url.setScheme( "http" ); + url.setHost( host() ); + url.setEncodedPath( d->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"; + } +} + + +bool // static +lastfm::UrlBuilder::isHost( const QUrl& url ) +{ + QStringList hosts = QStringList() << "www.lastfm.com.br" + << "www.lastfm.com.tr" + << "www.lastfm.fr" + << "www.lastfm.it" + << "www.lastfm.de" + << "www.lastfm.es" + << "www.lastfm.pl" + << "www.lastfm.ru" + << "www.lastfm.jp" + << "www.lastfm.se" + << "cn.last.fm" + << "www.last.fm"; + + return hosts.contains( url.host() ); +} + +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; +} + +lastfm::UrlBuilder& +lastfm::UrlBuilder::operator=( const UrlBuilder& that ) +{ + d->path = that.d->path; + return *this; +} diff -Nru liblastfm-0.4.0~really0.3.3/src/UrlBuilder.h liblastfm-1.0.1/src/UrlBuilder.h --- liblastfm-0.4.0~really0.3.3/src/UrlBuilder.h 1970-01-01 00:00:00.000000000 +0000 +++ liblastfm-1.0.1/src/UrlBuilder.h 2012-06-18 10:37:51.000000000 +0000 @@ -0,0 +1,76 @@ +/* + 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 "global.h" +#include +#include + + +namespace lastfm +{ + /** For building www.last.fm urls. We have special rules for encoding and that */ + class LASTFM_DLLEXPORT UrlBuilder + { + 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 ); + + UrlBuilder& slash( const QString& path ); + + UrlBuilder( const UrlBuilder& that ); + ~UrlBuilder(); + + 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() ); + + /** return true if url is a last.fm url */ + static bool isHost( const QUrl& url ); + + UrlBuilder& operator=( const UrlBuilder& that ); + + private: + class UrlBuilderPrivate * const d; + }; +} + +#endif diff -Nru liblastfm-0.4.0~really0.3.3/src/User.cpp liblastfm-1.0.1/src/User.cpp --- liblastfm-0.4.0~really0.3.3/src/User.cpp 1970-01-01 00:00:00.000000000 +0000 +++ liblastfm-1.0.1/src/User.cpp 2012-06-18 10:37:51.000000000 +0000 @@ -0,0 +1,669 @@ +/* + 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 "UrlBuilder.h" +#include "XmlQuery.h" + +#include +#include +#include + +using lastfm::Gender; +using lastfm::User; +using lastfm::UserList; +using lastfm::XmlQuery; + + +class lastfm::UserListPrivate +{ +public: + UserListPrivate() + : total( 0 ), page( 0 ), perPage( 0 ), totalPages( 0 ) + {} + int total; + int page; + int perPage; + int totalPages; + QList users; +}; + +lastfm::UserList::UserList() + : d( new UserListPrivate ) +{ +} + +lastfm::UserList::UserList( const XmlQuery &lfm ) + : d( new UserListPrivate ) +{ + if ( lfm.parseError().enumValue() == lastfm::ws::NoError ) + { + foreach (XmlQuery e, lfm.children( "user" )) + { + User u( e ); + d->users.append( u ); + } + + d->total = lfm["friends"].attribute("total").toInt(); + d->page = lfm["friends"].attribute("page").toInt(); + d->perPage = lfm["friends"].attribute("perPage").toInt(); + d->totalPages = lfm["friends"].attribute("totalPages").toInt(); + } + else + { + qDebug() << lfm.parseError().message() << lfm.parseError().enumValue(); + } +} + +lastfm::UserList::~UserList() +{ + delete d; +} + +lastfm::UserList::UserList( const UserList& other ) + : d( new UserListPrivate( *other.d ) ) +{ +} + +QList +lastfm::UserList::users() +{ + return d->users; +} + +lastfm::UserList& +lastfm::UserList::operator=( const UserList& other ) +{ + d->total = other.d->total; + d->page = other.d->page; + d->perPage = other.d->perPage; + d->totalPages = other.d->totalPages; + d->users = other.d->users; + return *this; +} + +int +lastfm::UserList::totalUsers() +{ + return d->total; +} + +int +lastfm::UserList::currentPage() +{ + return d->page; +} + +int +lastfm::UserList::usersPerPage() +{ + return d->perPage; +} + +int +lastfm::UserList::totalPages() +{ + return d->totalPages; +} + + +class lastfm::Gender::GenderPrivate +{ + public: + QString s; +}; + + +Gender::Gender() + :d( new GenderPrivate ) +{ +} + +Gender::Gender( const Gender& other ) + :d( new GenderPrivate( *other.d ) ) +{ +} + + +Gender::Gender( const QString& ss ) + :d( new GenderPrivate ) +{ + d->s = ss.toLower(); +} + + +Gender::~Gender() +{ + delete d; +} + + +bool +Gender::known() const +{ + return male() || female(); +} + + +bool +Gender::male() const +{ + return d->s == "m"; +} + + +bool +Gender::female() const +{ + return d->s == "f"; +} + +QString Gender::toString() const +{ + QString result; + + if (male()) + result = QObject::tr( "Male" ); + else if (female()) + result = QObject::tr( "Female" ); + else + result = QObject::tr( "Neuter" ); + + return result; +} + + +Gender& +Gender::operator=( const lastfm::Gender& that ) +{ + d->s = that.d->s; + return *this; +} + + + +class lastfm::User::UserPrivate +{ + public: + UserPrivate() + : m_name( lastfm::ws::Username ) + , m_match( -1.0f ) + , m_age( 0 ) + , m_scrobbles( 0 ) + , m_registered( QDateTime() ) + , m_isSubscriber( false ) + , m_canBootstrap( false ) + {} + QString m_name; + Type m_type; + QList m_images; + float m_match; + QString m_realName; + Gender m_gender; + unsigned short m_age; + unsigned int m_scrobbles; + QDateTime m_registered; + QString m_country; + bool m_isSubscriber; + bool m_canBootstrap; +}; + + + +User::User( const XmlQuery& xml ) + :AbstractType(), + d( new UserPrivate ) +{ + d->m_name = xml["name"].text(); + d->m_images << xml["image size=small"].text() + << xml["image size=medium"].text() + << xml["image size=large"].text(); + d->m_realName = xml["realname"].text(); + + QString type = xml["type"].text(); + + if ( type == "subscriber" ) d->m_type = TypeSubscriber; + else if ( type == "moderator" ) d->m_type = TypeModerator; + else if ( type == "staff" ) d->m_type = TypeStaff; + else if ( type == "alumni" ) d->m_type = TypeAlumni; + else d->m_type = TypeUser; + + d->m_age = xml["age"].text().toUInt(); + d->m_scrobbles = xml["playcount"].text().toUInt(); + d->m_registered = QDateTime::fromTime_t(xml["registered"].attribute("unixtime").toUInt()); + d->m_country = xml["country"].text(); + d->m_isSubscriber = ( xml["subscriber"].text() == "1" ); + d->m_canBootstrap = ( xml["bootstrap"].text() == "1" ); + d->m_gender = xml["gender"].text(); + d->m_images << xml["image size=small"].text() + << xml["image size=medium"].text() + << xml["image size=large"].text() + << xml["image size=extralarge"].text(); +} + +User::User( const User& other ) + :AbstractType(), + d( new UserPrivate( *other.d ) ) +{ +} + +User::User() + :AbstractType(), + d( new UserPrivate ) +{ +} + +User::User( const QString& name ) + :AbstractType(), + d( new UserPrivate ) +{ + d->m_name = name; + d->m_match = -1.0f; + d->m_age = 0; + d->m_scrobbles = 0; + d->m_registered = QDateTime(); + d->m_isSubscriber = false; + d->m_canBootstrap = false; +} + + +User::~User() +{ + delete d; +} + + +lastfm::User& +User::operator=( const User& that ) +{ + d->m_name = that.name(); + d->m_images = that.d->m_images; + d->m_realName = that.d->m_realName; + d->m_match = that.d->m_match; + d->m_type = that.d->m_type; + d->m_age = that.d->m_age; + d->m_scrobbles = that.d->m_scrobbles; + d->m_registered = that.d->m_registered; + d->m_country = that.d->m_country; + d->m_isSubscriber = that.d->m_isSubscriber; + d->m_canBootstrap = that.d->m_canBootstrap; + d->m_gender = that.d->m_gender; + d->m_images = that.d->m_images; + return *this; +} + + +bool +User::operator==(const lastfm::User& that) const +{ + return d->m_name == that.d->m_name; +} + + +bool +User::operator<(const lastfm::User& that) const +{ + return d->m_name < that.d->m_name; +} + + + +User::operator QString() const +{ + return d->m_name; +} + + +QString +User::name() const +{ + return d->m_name; +} + + +void +User::setName( const QString& name ) +{ + d->m_name = name; +} + + +User::Type +User::type() const +{ + return d->m_type; +} + + +void +User::setType( Type type ) +{ + d->m_type = type; +} + + +QUrl +User::imageUrl( 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/" )); +} + + +QMap +User::params(const QString& method) const +{ + QMap map; + map["method"] = "user."+method; + map["user"] = d->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::getLovedTracks( int limit, int page ) const +{ + QMap map = params( "getLovedTracks" ); + 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 ); + map["extended"] = "true"; + 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 ) +{ + + XmlQuery lfm; + + lfm.parse( r->readAll() ); + return UserList( lfm ); +} + + +QString +User::toString() const +{ + return name(); +} + + +QDomElement +User::toDomElement( QDomDocument& ) const +{ + return QDomElement(); +} + + +QNetworkReply* //static +User::getInfo( const QString& username ) +{ + QMap map; + map["method"] = "user.getInfo"; + map["user"] = username; + return ws::post( map ); +} + + + + +/* +QNetworkReply* //static +User::getRecommendedArtists() +{ + QMap map; + map["method"] = "user.getRecommendedArtists"; + return ws::post( map ); +} +*/ + +QUrl +User::www() const +{ + return UrlBuilder( "user" ).slash( d->m_name ).url(); +} + + +float +User::match() const +{ + return d->m_match; +} + + +QString +User::getInfoString() const +{ + QString text; + + text = QObject::tr("%1").arg( d->m_realName.isEmpty() ? d->m_name : d->m_realName ); + if ( d->m_age ) text.append( QObject::tr(", %1").arg( d->m_age ) ); + if ( d->m_gender.known() ) text.append( QObject::tr(", %1").arg( d->m_gender.toString() ) ); + if ( !d->m_country.isEmpty() ) text.append( QObject::tr(", %1").arg( d->m_country ) ); + + return text; +} + + +quint32 +User::scrobbleCount() const +{ + return d->m_scrobbles; +} + + +void +User::setScrobbleCount( quint32 scrobbleCount ) +{ + d->m_scrobbles = scrobbleCount; +} + + +QDateTime +User::dateRegistered() const +{ + return d->m_registered; +} + + +void +User::setDateRegistered( const QDateTime& date ) +{ + d->m_registered = date; +} + + +Gender +User::gender() const +{ + return d->m_gender; +} + + +QString +User::country() const +{ + return d->m_country; +} + + +QString +User::realName() const +{ + return d->m_realName; +} + + +void +User::setRealName( const QString& realName ) +{ + d->m_realName = realName; +} + + +void +User::setImages( const QList& images ) +{ + d->m_images = images; +} + + +void +User::setAge( unsigned short age ) +{ + d->m_age = age; +} + + +bool +User::isSubscriber() const +{ + return d->m_isSubscriber; +} + + +void +User::setIsSubscriber( bool subscriber ) +{ + d->m_isSubscriber = subscriber; +} + + +bool +User::canBootstrap() const +{ + return d->m_canBootstrap; +} + + +void +User::setCanBootstrap( bool canBootstrap ) +{ + d->m_canBootstrap = canBootstrap; +} + +void +User::setGender( const QString& s ) +{ + d->m_gender = Gender( s ); +} + +void +User::setCountry( const QString& country ) +{ + d->m_country = country; +} + diff -Nru liblastfm-0.4.0~really0.3.3/src/User.h liblastfm-1.0.1/src/User.h --- liblastfm-0.4.0~really0.3.3/src/User.h 1970-01-01 00:00:00.000000000 +0000 +++ liblastfm-1.0.1/src/User.h 2012-06-18 10:37:51.000000000 +0000 @@ -0,0 +1,173 @@ +/* + 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 "AbstractType.h" +#include "ws.h" + +namespace lastfm +{ + class UserList; + class XmlQuery; + + class LASTFM_DLLEXPORT Gender + { + + public: + Gender(); + Gender( const Gender& gender ); + Gender( const QString& ss ); + ~Gender(); + + bool known() const; + bool male() const; + bool female() const; + + QString toString() const; + lastfm::Gender& operator=( const lastfm::Gender& that ); + + private: + class GenderPrivate; + GenderPrivate * const d; + }; + + class LASTFM_DLLEXPORT User : public AbstractType + { + public: + enum Type + { + TypeUser, + TypeSubscriber, + TypeModerator, + TypeStaff, + TypeAlumni + }; + + public: + User(); + User( const QString& name ); + User( const XmlQuery& xml ); + User( const User& user ); + ~User(); + + lastfm::User& operator=( const lastfm::User& that ); + bool operator==(const lastfm::User& that) const; + bool operator<(const lastfm::User& that) const; + + operator QString() const; + + QString name() const; + void setName( const QString& name ); + + Type type() const; + void setType( Type type ); + + bool isSubscriber() const; + void setIsSubscriber( bool subscriber ); + + bool canBootstrap() const; + void setCanBootstrap( bool canBootstrap ); + + quint32 scrobbleCount() const; + void setScrobbleCount( quint32 scrobblesCount ); + + QDateTime dateRegistered() const; + void setDateRegistered( const QDateTime& date ); + + Gender gender() const; + QString country() const; + + QString realName() const; + void setRealName( const QString& realName ); + + QUrl imageUrl( ImageSize size = LargeImage, bool square = false ) const; + void setImages( const QList& images ); + + void setAge( unsigned short age ); + + void setGender( const QString& s ); + void setCountry( const QString& country ); + + /** use Tag::list() on the response to get a WeightedStringList */ + QNetworkReply* getTopTags() const; + + /** use User::list() on the response to get a UserList */ + 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* getLovedTracks( 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; + + /** 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; + + static UserList list( QNetworkReply* ); + + QString toString() const; + QDomElement toDomElement( QDomDocument& ) const; + + /** 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; + + protected: + QMap params( const QString& method ) const; + + protected: + class UserPrivate; + UserPrivate * const d; + }; + + class LASTFM_DLLEXPORT UserList + { + public: + UserList(); + UserList( const XmlQuery& query ); + UserList( const UserList& other ); + ~UserList(); + UserList& operator=( const UserList& other ); + + int totalUsers(); + int totalPages(); + int currentPage(); + int usersPerPage(); + QList users(); + + private: + class UserListPrivate * const d; + }; +} + +#endif diff -Nru liblastfm-0.4.0~really0.3.3/src/win/ComSetup.h liblastfm-1.0.1/src/win/ComSetup.h --- liblastfm-0.4.0~really0.3.3/src/win/ComSetup.h 1970-01-01 00:00:00.000000000 +0000 +++ liblastfm-1.0.1/src/win/ComSetup.h 2012-06-18 10:37:51.000000000 +0000 @@ -0,0 +1,67 @@ +/* + 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 +// This means we are targetting Windows XP onwards +// bring in CoInitializeSecurity from objbase.h +#define _WIN32_WINNT 0x0501 +#endif + +#include + +#ifndef __MINGW32__ + #include + #include +#endif + + +/** @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 -Nru liblastfm-0.4.0~really0.3.3/src/win/IeSettings.h liblastfm-1.0.1/src/win/IeSettings.h --- liblastfm-0.4.0~really0.3.3/src/win/IeSettings.h 1970-01-01 00:00:00.000000000 +0000 +++ liblastfm-1.0.1/src/win/IeSettings.h 2012-06-18 10:37:51.000000000 +0000 @@ -0,0 +1,43 @@ +/* + 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 -Nru liblastfm-0.4.0~really0.3.3/src/win/NdisEvents.cpp liblastfm-1.0.1/src/win/NdisEvents.cpp --- liblastfm-0.4.0~really0.3.3/src/win/NdisEvents.cpp 1970-01-01 00:00:00.000000000 +0000 +++ liblastfm-1.0.1/src/win/NdisEvents.cpp 2012-06-18 10:37:51.000000000 +0000 @@ -0,0 +1,87 @@ +/* + 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 = m_pLocator.CoCreateInstance(CLSID_WbemLocator); + if (FAILED(hr)) + return hr; + + // Connect to the root\wmi namespace with the current user. + hr = 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 -Nru liblastfm-0.4.0~really0.3.3/src/win/NdisEvents.h liblastfm-1.0.1/src/win/NdisEvents.h --- liblastfm-0.4.0~really0.3.3/src/win/NdisEvents.h 1970-01-01 00:00:00.000000000 +0000 +++ liblastfm-1.0.1/src/win/NdisEvents.h 2012-06-18 10:37:51.000000000 +0000 @@ -0,0 +1,47 @@ +/* + 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 + +#ifndef __MINGW32__ +#include +#include +#endif + +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 -Nru liblastfm-0.4.0~really0.3.3/src/win/Pac.cpp liblastfm-1.0.1/src/win/Pac.cpp --- liblastfm-0.4.0~really0.3.3/src/win/Pac.cpp 1970-01-01 00:00:00.000000000 +0000 +++ liblastfm-1.0.1/src/win/Pac.cpp 2012-06-18 10:37:51.000000000 +0000 @@ -0,0 +1,128 @@ +/* + 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 + + +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, request.url().toString().utf16(), &opts, &info)) { + if (info.lpszProxy) + { + QList proxies = parsePacResult(QString::fromUtf16(info.lpszProxy)); + if (!proxies.empty()) + { + out = proxies.at(0); + } + GlobalFree(info.lpszProxy); + } + if (info.lpszProxyBypass) + { + GlobalFree(info.lpszProxyBypass); + } + } else { + m_bFailed = true; + } + } + + return out; +} diff -Nru liblastfm-0.4.0~really0.3.3/src/win/Pac.h liblastfm-1.0.1/src/win/Pac.h --- liblastfm-0.4.0~really0.3.3/src/win/Pac.h 1970-01-01 00:00:00.000000000 +0000 +++ liblastfm-1.0.1/src/win/Pac.h 2012-06-18 10:37:51.000000000 +0000 @@ -0,0 +1,52 @@ +/* + 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 -Nru liblastfm-0.4.0~really0.3.3/src/win/WmiSink.cpp liblastfm-1.0.1/src/win/WmiSink.cpp --- liblastfm-0.4.0~really0.3.3/src/win/WmiSink.cpp 1970-01-01 00:00:00.000000000 +0000 +++ liblastfm-1.0.1/src/win/WmiSink.cpp 2012-06-18 10:37:51.000000000 +0000 @@ -0,0 +1,202 @@ +/* + 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 -Nru liblastfm-0.4.0~really0.3.3/src/win/WmiSink.h liblastfm-1.0.1/src/win/WmiSink.h --- liblastfm-0.4.0~really0.3.3/src/win/WmiSink.h 1970-01-01 00:00:00.000000000 +0000 +++ liblastfm-1.0.1/src/win/WmiSink.h 2012-06-18 10:37:51.000000000 +0000 @@ -0,0 +1,49 @@ +/* + 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 -Nru liblastfm-0.4.0~really0.3.3/src/win/WNetworkConnectionMonitor.h liblastfm-1.0.1/src/win/WNetworkConnectionMonitor.h --- liblastfm-0.4.0~really0.3.3/src/win/WNetworkConnectionMonitor.h 1970-01-01 00:00:00.000000000 +0000 +++ liblastfm-1.0.1/src/win/WNetworkConnectionMonitor.h 2012-06-18 10:37:51.000000000 +0000 @@ -0,0 +1,46 @@ +/* + 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" + +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 -Nru liblastfm-0.4.0~really0.3.3/src/win/WNetworkConnectionMonitor_win.cpp liblastfm-1.0.1/src/win/WNetworkConnectionMonitor_win.cpp --- liblastfm-0.4.0~really0.3.3/src/win/WNetworkConnectionMonitor_win.cpp 1970-01-01 00:00:00.000000000 +0000 +++ liblastfm-1.0.1/src/win/WNetworkConnectionMonitor_win.cpp 2012-06-18 10:37:51.000000000 +0000 @@ -0,0 +1,69 @@ +/* + 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" +#include "moc_WNetworkConnectionMonitor.cpp" + +// 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 -Nru liblastfm-0.4.0~really0.3.3/src/ws/InternetConnectionMonitor.cpp liblastfm-1.0.1/src/ws/InternetConnectionMonitor.cpp --- liblastfm-0.4.0~really0.3.3/src/ws/InternetConnectionMonitor.cpp 2010-09-25 17:30:01.000000000 +0000 +++ liblastfm-1.0.1/src/ws/InternetConnectionMonitor.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -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 "InternetConnectionMonitor.h" -#include "ws.h" - -#ifdef __APPLE__ -#include -#include -QList > monitors; -#endif - -#ifdef Q_CC_MSVC - -// 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(InternetConnectionMonitor *icm) - :m_icm(icm) - { - } - - // WmiSink callbacks: - virtual void onConnectionUp( BSTR name ) - { - emit m_icm->up( QString::fromUtf16(name) ); - emit m_icm->connectivityChanged( true ); - } - - virtual void onConnectionDown( BSTR name ) - { - emit m_icm->down( QString::fromUtf16(name) ); - emit m_icm->connectivityChanged( false ); - } - - InternetConnectionMonitor* m_icm; -}; - -} - -#endif - - -lastfm::InternetConnectionMonitor::InternetConnectionMonitor( QObject *parent ) - : QObject( parent ) - , m_up( true ) -{ -#ifdef __APPLE__ - if (monitors.isEmpty()) - { - SCNetworkReachabilityRef ref = SCNetworkReachabilityCreateWithName( NULL, LASTFM_WS_HOSTNAME ); - SCNetworkReachabilityScheduleWithRunLoop( ref, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode ); - SCNetworkReachabilitySetCallback( ref, callback, NULL ); - CFRelease( ref ); - } - - QPointer p = this; - monitors += p; -#endif -#ifdef Q_CC_MSVC - m_ndisEventsProxy = new NdisEventsProxy(this); - m_ndisEventsProxy->registerForNdisEvents(); -#endif -} - - -#ifdef __APPLE__ -void -lastfm::InternetConnectionMonitor::callback( SCNetworkReachabilityRef, 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); - - qDebug() << "Can reach " LASTFM_WS_HOSTNAME ":" << b << ", flags:" << flags; - - // basically, avoids telling everyone that we're up already on startup - if (up == b) return; - up = b; - - foreach (InternetConnectionMonitor* monitor, monitors) - if (monitor) - { - monitor->m_up = b; - - if (b) - emit monitor->up(); - else - emit monitor->down(); - - emit monitor->connectivityChanged( b ); - } -} -#endif - - diff -Nru liblastfm-0.4.0~really0.3.3/src/ws/InternetConnectionMonitor.h liblastfm-1.0.1/src/ws/InternetConnectionMonitor.h --- liblastfm-0.4.0~really0.3.3/src/ws/InternetConnectionMonitor.h 2010-09-25 17:30:01.000000000 +0000 +++ liblastfm-1.0.1/src/ws/InternetConnectionMonitor.h 1970-01-01 00:00:00.000000000 +0000 @@ -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_CONNECTION_MONITOR_H -#define LASTFM_CONNECTION_MONITOR_H - -#include -#include -#ifdef Q_WS_MAC -#include //TODO remove -typedef const struct __SCNetworkReachability * SCNetworkReachabilityRef; -#endif - - -namespace lastfm { - -class LASTFM_DLLEXPORT InternetConnectionMonitor : public QObject -{ - Q_OBJECT - -#ifdef Q_WS_MAC - static void callback( SCNetworkReachabilityRef, SCNetworkConnectionFlags, void* ); -#endif -#ifdef Q_WS_WIN - class NdisEventsProxy* m_ndisEventsProxy; - friend class NdisEventsProxy; -#endif - - bool m_up; - -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; } - -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 ); -}; - -} //namespace lastfm - -#endif diff -Nru liblastfm-0.4.0~really0.3.3/src/ws/mac/ProxyDict.h liblastfm-1.0.1/src/ws/mac/ProxyDict.h --- liblastfm-0.4.0~really0.3.3/src/ws/mac/ProxyDict.h 2010-09-25 17:30:01.000000000 +0000 +++ liblastfm-1.0.1/src/ws/mac/ProxyDict.h 1970-01-01 00:00:00.000000000 +0000 @@ -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 -Nru liblastfm-0.4.0~really0.3.3/src/ws/NetworkAccessManager.cpp liblastfm-1.0.1/src/ws/NetworkAccessManager.cpp --- liblastfm-0.4.0~really0.3.3/src/ws/NetworkAccessManager.cpp 2010-09-25 17:30:01.000000000 +0000 +++ liblastfm-1.0.1/src/ws/NetworkAccessManager.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,156 +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 Q_CC_MSVC -#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 Q_CC_MSVC - 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(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 Q_CC_MSVC - , 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 Q_CC_MSVC - delete m_pac; -#endif -} - - -QNetworkProxy -lastfm::NetworkAccessManager::proxy( const QNetworkRequest& request ) -{ - Q_UNUSED( request ); - -#ifdef Q_CC_MSVC - IeSettings s; - if (s.fAutoDetect) - { - if (!m_pac) { - m_pac = new Pac; - 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.setRawHeader( "User-Agent", lastfm::UserAgent ); - -#ifdef Q_CC_MSVC - // 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 Q_CC_MSVC - if (up && m_pac) m_pac->resetFailedState(); -#endif -} diff -Nru liblastfm-0.4.0~really0.3.3/src/ws/NetworkAccessManager.h liblastfm-1.0.1/src/ws/NetworkAccessManager.h --- liblastfm-0.4.0~really0.3.3/src/ws/NetworkAccessManager.h 2010-09-25 17:30:01.000000000 +0000 +++ liblastfm-1.0.1/src/ws/NetworkAccessManager.h 1970-01-01 00:00:00.000000000 +0000 @@ -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 -Nru liblastfm-0.4.0~really0.3.3/src/ws/win/ComSetup.h liblastfm-1.0.1/src/ws/win/ComSetup.h --- liblastfm-0.4.0~really0.3.3/src/ws/win/ComSetup.h 2010-09-25 17:30:01.000000000 +0000 +++ liblastfm-1.0.1/src/ws/win/ComSetup.h 1970-01-01 00:00:00.000000000 +0000 @@ -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 _WIN32_WINNT -// bring in CoInitializeSecurity from objbase.h -#define _WIN32_WINNT 0x0400 -#endif - -#include -#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 -Nru liblastfm-0.4.0~really0.3.3/src/ws/win/IeSettings.h liblastfm-1.0.1/src/ws/win/IeSettings.h --- liblastfm-0.4.0~really0.3.3/src/ws/win/IeSettings.h 2010-09-25 17:30:01.000000000 +0000 +++ liblastfm-1.0.1/src/ws/win/IeSettings.h 1970-01-01 00:00:00.000000000 +0000 @@ -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::IeSettings() - { - if (!WinHttpGetIEProxyConfigForCurrentUser(this)) { - fAutoDetect = FALSE; - lpszAutoConfigUrl = lpszProxy = lpszProxyBypass = 0; - } - } - - IeSettings::~IeSettings() - { - if (lpszAutoConfigUrl) GlobalFree(lpszAutoConfigUrl); - if (lpszProxy) GlobalFree(lpszProxy); - if (lpszProxyBypass) GlobalFree(lpszProxyBypass); - } -}; diff -Nru liblastfm-0.4.0~really0.3.3/src/ws/win/NdisEvents.cpp liblastfm-1.0.1/src/ws/win/NdisEvents.cpp --- liblastfm-0.4.0~really0.3.3/src/ws/win/NdisEvents.cpp 2010-09-25 17:30:01.000000000 +0000 +++ liblastfm-1.0.1/src/ws/win/NdisEvents.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -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 = m_pLocator.CoCreateInstance(CLSID_WbemLocator); - if (FAILED(hr)) - return hr; - - // Connect to the root\wmi namespace with the current user. - hr = 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 -Nru liblastfm-0.4.0~really0.3.3/src/ws/win/NdisEvents.h liblastfm-1.0.1/src/ws/win/NdisEvents.h --- liblastfm-0.4.0~really0.3.3/src/ws/win/NdisEvents.h 2010-09-25 17:30:01.000000000 +0000 +++ liblastfm-1.0.1/src/ws/win/NdisEvents.h 1970-01-01 00:00:00.000000000 +0000 @@ -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 -Nru liblastfm-0.4.0~really0.3.3/src/ws/win/Pac.cpp liblastfm-1.0.1/src/ws/win/Pac.cpp --- liblastfm-0.4.0~really0.3.3/src/ws/win/Pac.cpp 2010-09-25 17:30:01.000000000 +0000 +++ liblastfm-1.0.1/src/ws/win/Pac.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,128 +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 - - -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, request.url().toString().utf16(), &opts, &info)) { - if (info.lpszProxy) - { - QList proxies = parsePacResult(QString::fromUtf16(info.lpszProxy)); - if (!proxies.empty()) - { - out = proxies.at(0); - } - GlobalFree(info.lpszProxy); - } - if (info.lpszProxyBypass) - { - GlobalFree(info.lpszProxyBypass); - } - } else { - m_bFailed = true; - } - } - - return out; -} diff -Nru liblastfm-0.4.0~really0.3.3/src/ws/win/Pac.h liblastfm-1.0.1/src/ws/win/Pac.h --- liblastfm-0.4.0~really0.3.3/src/ws/win/Pac.h 2010-09-25 17:30:01.000000000 +0000 +++ liblastfm-1.0.1/src/ws/win/Pac.h 1970-01-01 00:00:00.000000000 +0000 @@ -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 -Nru liblastfm-0.4.0~really0.3.3/src/ws/win/WmiSink.cpp liblastfm-1.0.1/src/ws/win/WmiSink.cpp --- liblastfm-0.4.0~really0.3.3/src/ws/win/WmiSink.cpp 2010-09-25 17:30:01.000000000 +0000 +++ liblastfm-1.0.1/src/ws/win/WmiSink.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -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 -Nru liblastfm-0.4.0~really0.3.3/src/ws/win/WmiSink.h liblastfm-1.0.1/src/ws/win/WmiSink.h --- liblastfm-0.4.0~really0.3.3/src/ws/win/WmiSink.h 2010-09-25 17:30:01.000000000 +0000 +++ liblastfm-1.0.1/src/ws/win/WmiSink.h 1970-01-01 00:00:00.000000000 +0000 @@ -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 -Nru liblastfm-0.4.0~really0.3.3/src/ws/ws.cpp liblastfm-1.0.1/src/ws/ws.cpp --- liblastfm-0.4.0~really0.3.3/src/ws/ws.cpp 2010-09-25 17:30:01.000000000 +0000 +++ liblastfm-1.0.1/src/ws/ws.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,280 +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 -static QNetworkAccessManager* nam = 0; - - -static inline QString 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 url() -{ - QUrl url; - url.setScheme( "http" ); - url.setHost( host() ); - url.setPath( "/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(); -} - -void sign( QMap& params ) -{ - autograph( params ); - // it's allowed for sk to be null if we this is an auth call for instance - if (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() ); -} - -lastfm::ws::ParseError::ParseError( lastfm::ws::Error e ) - : std::runtime_error("lastfm::ws::Error"), - e(e) -{ -} - -lastfm::ws::ParseError::~ParseError() throw() -{ -} - -lastfm::ws::Error lastfm::ws::ParseError::enumValue() const -{ - return e; -} - -QNetworkReply* -lastfm::ws::get( QMap params ) -{ - autograph( params ); - QUrl url = ::url(); - // 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 ); - } - - qDebug() << url; - - return nam()->get( QNetworkRequest(url) ); -} - - -QNetworkReply* -lastfm::ws::post( QMap params ) -{ - sign( params ); - QByteArray query; - QMapIterator i( params ); - while (i.hasNext()) { - i.next(); - query += QUrl::toPercentEncoding( i.key() ) - + '=' - + QUrl::toPercentEncoding( i.value() ) - + '&'; - } - return nam()->post( QNetworkRequest(url()), query ); -} - - -QByteArray -lastfm::ws::parse( QNetworkReply* reply ) throw( ParseError ) -{ - try - { - QByteArray data = reply->readAll(); - - if (!data.size()) - throw MalformedResponse; - - QDomDocument xml; - xml.setContent( data ); - QDomElement lfm = xml.documentElement(); - - if (lfm.isNull()) - throw MalformedResponse; - - QString const status = lfm.attribute( "status" ); - QDomElement error = lfm.firstChildElement( "error" ); - uint const n = lfm.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() - ? MalformedResponse - : Error( error.attribute( "code" ).toUInt() ); - - switch (reply->error()) - { - case QNetworkReply::RemoteHostClosedError: - case QNetworkReply::ConnectionRefusedError: - case QNetworkReply::TimeoutError: - case QNetworkReply::ContentAccessDenied: - case QNetworkReply::ContentOperationNotPermittedError: - case QNetworkReply::UnknownContentError: - case QNetworkReply::ProtocolInvalidOperationError: - case QNetworkReply::ProtocolFailure: - throw TryAgainLater; - - case QNetworkReply::NoError: - default: - break; - } - - //FIXME pretty wasteful to parse XML document twice.. - return data; - } - catch (Error e) - { - switch (e) - { - case OperationFailed: - case InvalidApiKey: - case 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 ) ); - default: - throw ParseError(e); - } - } - - // bit dodgy, but prolly for the best - reply->deleteLater(); -} - - -QNetworkAccessManager* -lastfm::nam() -{ - if (!::nam) ::nam = new NetworkAccessManager( qApp ); - return ::nam; -} - - -void -lastfm::setNetworkAccessManager( QNetworkAccessManager* nam ) -{ - delete ::nam; - ::nam = nam; - nam->setParent( qApp ); // ensure it isn't deleted out from under us -} - - -/** 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 -Nru liblastfm-0.4.0~really0.3.3/src/ws/ws.h liblastfm-1.0.1/src/ws/ws.h --- liblastfm-0.4.0~really0.3.3/src/ws/ws.h 2010-09-25 17:30:01.000000000 +0000 +++ liblastfm-1.0.1/src/ws/ws.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,161 +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 - }; - - /** the map needs a method entry, as per http://last.fm/api */ - 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 ); - - - class LASTFM_DLLEXPORT ParseError : public std::runtime_error - { - Error e; - - public: - explicit ParseError(Error e); - ~ParseError() throw(); - - Error enumValue() const; - }; - - /** Generally you don't use this, eg. if you called Artist::getInfo(), - * use the Artist::getInfo( QNetworkReply* ) function to get the - * results, you have to pass a QDomDocument because QDomElements stop - * existing when the parent DomDocument is deleted. - * - * The QByteArray is basically reply->readAll(), so all this function - * does is sanity check the response and throw if it is bad. - * - * Thus if you don't care about errors just do: reply->readAll() - * - * Not caring about errors is often fine with Qt as you just get null - * strings and that instead, and you can handle those as you go. - * - * The QByteArray is an XML document. You can parse it with QDom or - * use our much more convenient lastfm::XmlQuery. - */ - LASTFM_DLLEXPORT QByteArray parse( QNetworkReply* reply ) throw( ParseError ); - - /** 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 -Nru liblastfm-0.4.0~really0.3.3/src/ws.cpp liblastfm-1.0.1/src/ws.cpp --- liblastfm-0.4.0~really0.3.3/src/ws.cpp 1970-01-01 00:00:00.000000000 +0000 +++ liblastfm-1.0.1/src/ws.cpp 2012-06-18 10:37:51.000000000 +0000 @@ -0,0 +1,288 @@ +/* + 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 "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; + +class lastfm::ws::ParseErrorPrivate +{ +public: + lastfm::ws::Error e; + QString m_message; +}; + +lastfm::ws::ParseError::ParseError( lastfm::ws::Error e, QString message ) + :d( new ParseErrorPrivate ) +{ + d->e = e; + d->m_message = message; +} + +lastfm::ws::ParseError::ParseError( const ParseError& that ) + : d( new ParseErrorPrivate( *that.d ) ) +{ +} + +lastfm::ws::ParseError::~ParseError() throw() +{ + delete d; +} + +lastfm::ws::Error +lastfm::ws::ParseError::enumValue() const +{ + return d->e; +} + +QString +lastfm::ws::ParseError::message() const +{ + return d->m_message; +} + +lastfm::ws::ParseError& +lastfm::ws::ParseError::operator=( const ParseError& that ) +{ + d->e = that.d->e; + d->m_message = that.d->m_message; + return *this; +} + +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(); +} + +void +lastfm::ws::sign( QMap& params, bool sk ) +{ + 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, bool sk ) +{ + lastfm::ws::sign( params, sk ); + 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 ); + +QDebug operator<<( QDebug d, QNetworkReply::NetworkError e ) +{ + return d << lastfm::qMetaEnumString( e, "NetworkError" ); +} diff -Nru liblastfm-0.4.0~really0.3.3/src/ws.h liblastfm-1.0.1/src/ws.h --- liblastfm-0.4.0~really0.3.3/src/ws.h 1970-01-01 00:00:00.000000000 +0000 +++ liblastfm-1.0.1/src/ws.h 2012-06-18 10:37:51.000000000 +0000 @@ -0,0 +1,148 @@ +/* + 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 "global.h" +#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 User 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, bool sessionKey = true); + 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 ); + + LASTFM_DLLEXPORT void sign( QMap&, bool sessionKey = true ); + + + class LASTFM_DLLEXPORT ParseError + { + public: + explicit ParseError( Error e, QString message ); + ParseError( const ParseError& that ); + ~ParseError() throw(); + Error enumValue() const; + QString message() const; + ParseError& operator=( const ParseError& that ); + + private: + class ParseErrorPrivate * const d; + }; + + /** returns the expiry date of this HTTP response */ + LASTFM_DLLEXPORT QDateTime expires( QNetworkReply* ); + } +} + + +LASTFM_DLLEXPORT QDebug operator<<( QDebug d, QNetworkReply::NetworkError e ); + +#define LASTFM_WS_HOSTNAME "ws.audioscrobbler.com" + +#endif diff -Nru liblastfm-0.4.0~really0.3.3/src/XmlQuery.cpp liblastfm-1.0.1/src/XmlQuery.cpp --- liblastfm-0.4.0~really0.3.3/src/XmlQuery.cpp 1970-01-01 00:00:00.000000000 +0000 +++ liblastfm-1.0.1/src/XmlQuery.cpp 2012-06-18 10:37:51.000000000 +0000 @@ -0,0 +1,199 @@ +/* + 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 +#include +#include + +using lastfm::XmlQuery; + +class lastfm::XmlQueryPrivate +{ +public: + XmlQueryPrivate(); + QDomDocument domdoc; + QDomElement e; + lastfm::ws::ParseError error; +}; + + +lastfm::XmlQueryPrivate::XmlQueryPrivate() + : error( lastfm::ws::ParseError( lastfm::ws::NoError, "" ) ) +{ +} + + +XmlQuery::XmlQuery() + : d( new XmlQueryPrivate ) +{ +} + + +XmlQuery::XmlQuery( const XmlQuery& that ) + : d( new XmlQueryPrivate( *that.d ) ) +{ +} + +XmlQuery::XmlQuery( const QDomElement& e, const char* name ) + : d( new XmlQueryPrivate ) +{ + d->e = e; + if (e.isNull()) + qWarning() << "Expected node absent:" << name; +} + + +XmlQuery::~XmlQuery() +{ + delete d; +} + + +bool +XmlQuery::parse( const QByteArray& bytes ) +{ + if ( !bytes.size() ) + d->error = lastfm::ws::ParseError( lastfm::ws::MalformedResponse, "No data" ); + else + { + if( !d->domdoc.setContent( bytes ) ) + d->error = lastfm::ws::ParseError( lastfm::ws::MalformedResponse, "Invalid XML" ); + else + { + d->e = d->domdoc.documentElement(); + + if (d->e.isNull()) + d->error = lastfm::ws::ParseError( lastfm::ws::MalformedResponse, "Lfm is null" ); + else + { + QString const status = d->e.attribute( "status" ); + QDomElement error = d->e.firstChildElement( "error" ); + uint const n = d->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()) ) + d->error = error.isNull() + ? lastfm::ws::ParseError( lastfm::ws::MalformedResponse, "" ) + : lastfm::ws::ParseError( lastfm::ws::Error( error.attribute( "code" ).toUInt() ), error.text() ); + } + } + } + + if ( d->error.enumValue() != lastfm::ws::NoError ) + { + qDebug() << bytes; + + switch ( d->error.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, d->error.enumValue() ) ); + break; + default: + //do nothing + break; + } + } + + return d->error.enumValue() == lastfm::ws::NoError; +} + + +lastfm::ws::ParseError XmlQuery::parseError() const +{ + return d->error; +} + + +QString XmlQuery::text() const +{ + return d->e.text(); +} + + +QString XmlQuery::attribute( const QString& name ) const +{ + return d->e.attribute( name ); +} + + +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.d->e.attribute( attributeName ) == attributeValue) + return e; + } + XmlQuery xq( d->e.firstChildElement( name ), name.toUtf8().data() ); + xq.d->domdoc = this->d->domdoc; + return xq; +} + + +QList +XmlQuery::children( const QString& named ) const +{ + QList elements; + QDomNodeList nodes = d->e.elementsByTagName( named ); + for (int x = 0; x < nodes.count(); ++x) { + XmlQuery xq( nodes.at( x ).toElement() ); + xq.d->domdoc = this->d->domdoc; + elements += xq; + } + return elements; +} + +XmlQuery::operator QDomElement() const +{ + return d->e; +} + + +XmlQuery& +XmlQuery::operator=( const XmlQuery& that ) +{ + d->domdoc = that.d->domdoc; + d->e = that.d->e; + d->error = that.d->error; + return *this; +} + +QDebug operator<<( QDebug d, const lastfm::XmlQuery& xq ) +{ + QString s; + QTextStream t( &s, QIODevice::WriteOnly ); + QDomElement(xq).save( t, 2 ); + return d << s; +} diff -Nru liblastfm-0.4.0~really0.3.3/src/XmlQuery.h liblastfm-1.0.1/src/XmlQuery.h --- liblastfm-0.4.0~really0.3.3/src/XmlQuery.h 1970-01-01 00:00:00.000000000 +0000 +++ liblastfm-1.0.1/src/XmlQuery.h 2012-06-18 10:37:51.000000000 +0000 @@ -0,0 +1,72 @@ +/* + 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 "ws.h" +#include + +namespace lastfm +{ + /** Qt's XmlQuery implementation is totally unimpressive, so this is a + * hack that feels like jQuery */ + class LASTFM_DLLEXPORT XmlQuery + { + 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(); + XmlQuery( const XmlQuery& that ); + ~XmlQuery(); + bool parse( const QByteArray& data ); + ws::ParseError parseError() const; + + XmlQuery( const QDomElement& e, const char* 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; + QString attribute( const QString& name ) const; + + /** selects all children with specified name, recursively */ + QList children( const QString& named ) const; + + operator QDomElement() const; + XmlQuery& operator=( const XmlQuery& that ); + + private: + class XmlQueryPrivate * const d; + }; +} + +LASTFM_DLLEXPORT QDebug operator<<( QDebug d, const lastfm::XmlQuery& xq ); + +#endif diff -Nru liblastfm-0.4.0~really0.3.3/src/Xspf.cpp liblastfm-1.0.1/src/Xspf.cpp --- liblastfm-0.4.0~really0.3.3/src/Xspf.cpp 1970-01-01 00:00:00.000000000 +0000 +++ liblastfm-1.0.1/src/Xspf.cpp 2012-06-18 10:37:51.000000000 +0000 @@ -0,0 +1,111 @@ +/* + 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 "Xspf.h" +#include "XmlQuery.h" + +#include +#include + + +class lastfm::XspfPrivate +{ + public: + QList tracks; + QString title; +}; + + +lastfm::Xspf::Xspf( const QDomElement& playlist_node, QObject* parent ) + :QObject( parent ) + , d( new XspfPrivate ) +{ + XmlQuery e( playlist_node ); + + int expirySeconds = e["link rel=http://www.last.fm/expiry"].text().toInt(); + QTimer::singleShot( expirySeconds * 1000, this, SLOT(onExpired())); + + d->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: + d->title.replace( '+', ' ' ); + d->title = QUrl::fromPercentEncoding( d->title.toUtf8() ); + d->title = d->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 ) ); + + d->tracks << t; // outside try block since location is enough basically + } +} + + +lastfm::Xspf::~Xspf() +{ + delete d; +} + + +QString +lastfm::Xspf::title() const +{ + return d->title; +} + + +bool +lastfm::Xspf::isEmpty() const +{ + return d->tracks.isEmpty(); +} + + +lastfm::Track +lastfm::Xspf::takeFirst() +{ + return d->tracks.takeFirst(); +} + + +void +lastfm::Xspf::onExpired() +{ + emit expired(); +} diff -Nru liblastfm-0.4.0~really0.3.3/src/Xspf.h liblastfm-1.0.1/src/Xspf.h --- liblastfm-0.4.0~really0.3.3/src/Xspf.h 1970-01-01 00:00:00.000000000 +0000 +++ liblastfm-1.0.1/src/Xspf.h 2012-06-18 10:37:51.000000000 +0000 @@ -0,0 +1,52 @@ +/* + 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 "Track.h" +#include + +namespace lastfm +{ + class LASTFM_DLLEXPORT Xspf : public QObject + { + Q_OBJECT + public: + /** pass in the playlist node! */ + Xspf( const QDomElement& playlist_node, QObject* parent ); + ~Xspf(); + + QString title() const; + + bool isEmpty() const; + Track takeFirst(); + + signals: + void expired(); + + private slots: + void onExpired(); + + private: + class XspfPrivate * const d; + }; +} + +#endif diff -Nru liblastfm-0.4.0~really0.3.3/tests/CMakeLists.txt liblastfm-1.0.1/tests/CMakeLists.txt --- liblastfm-0.4.0~really0.3.3/tests/CMakeLists.txt 1970-01-01 00:00:00.000000000 +0000 +++ liblastfm-1.0.1/tests/CMakeLists.txt 2012-06-18 10:37:51.000000000 +0000 @@ -0,0 +1,4 @@ +include(lastfm_add_test.cmake) + +lastfm_add_test(UrlBuilder) +lastfm_add_test(Track) diff -Nru liblastfm-0.4.0~really0.3.3/tests/lastfm_add_test.cmake liblastfm-1.0.1/tests/lastfm_add_test.cmake --- liblastfm-0.4.0~really0.3.3/tests/lastfm_add_test.cmake 1970-01-01 00:00:00.000000000 +0000 +++ liblastfm-1.0.1/tests/lastfm_add_test.cmake 2012-06-18 10:37:51.000000000 +0000 @@ -0,0 +1,16 @@ +macro(lastfm_add_test test_class) + include_directories(${QT_INCLUDES} "${PROJECT_SOURCE_DIR}/src" ${CMAKE_CURRENT_BINARY_DIR}) + + set(LASTFM_TEST_CLASS ${test_class}) + configure_file(main.cpp.in Test${LASTFM_TEST_CLASS}.cpp) + configure_file(Test${LASTFM_TEST_CLASS}.h Test${LASTFM_TEST_CLASS}.h) + add_executable(${LASTFM_TEST_CLASS}Test Test${LASTFM_TEST_CLASS}.cpp) + + target_link_libraries(${LASTFM_TEST_CLASS}Test + lastfm + ${QT_QTTEST_LIBRARY} + ${QT_QTCORE_LIBRARY} + ) + + add_test(NAME ${LASTFM_TEST_CLASS}Test COMMAND ${LASTFM_TEST_CLASS}Test) +endmacro() \ No newline at end of file diff -Nru liblastfm-0.4.0~really0.3.3/tests/main.cpp liblastfm-1.0.1/tests/main.cpp --- liblastfm-0.4.0~really0.3.3/tests/main.cpp 2010-09-25 17:30:01.000000000 +0000 +++ liblastfm-1.0.1/tests/main.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -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 -Nru liblastfm-0.4.0~really0.3.3/tests/main.cpp.in liblastfm-1.0.1/tests/main.cpp.in --- liblastfm-0.4.0~really0.3.3/tests/main.cpp.in 1970-01-01 00:00:00.000000000 +0000 +++ liblastfm-1.0.1/tests/main.cpp.in 2012-06-18 10:37:51.000000000 +0000 @@ -0,0 +1,22 @@ +/* + 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 "Test@LASTFM_TEST_CLASS@.h" +#include "moc_Test@LASTFM_TEST_CLASS@.cpp" + +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( Test@LASTFM_TEST_CLASS@ ); + return 0; +} diff -Nru liblastfm-0.4.0~really0.3.3/tests/tests.pro liblastfm-1.0.1/tests/tests.pro --- liblastfm-0.4.0~really0.3.3/tests/tests.pro 2010-09-25 17:30:01.000000000 +0000 +++ liblastfm-1.0.1/tests/tests.pro 1970-01-01 00:00:00.000000000 +0000 @@ -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 diff -Nru liblastfm-0.4.0~really0.3.3/tests/TestTrack.h liblastfm-1.0.1/tests/TestTrack.h --- liblastfm-0.4.0~really0.3.3/tests/TestTrack.h 2010-09-25 17:30:01.000000000 +0000 +++ liblastfm-1.0.1/tests/TestTrack.h 2012-06-18 10:37:51.000000000 +0000 @@ -3,8 +3,14 @@ support, and with no warranty, express or implied, as to its usefulness for any purpose. */ + +#ifndef LASTFM_TESTTRACK_H +#define LASTFM_TESTTRACK_H + +#include "Track.h" + #include -#include + using lastfm::Track; class TestTrack : public QObject @@ -24,7 +30,7 @@ void testClone() { Track original = example(); - Track copy = original.clone(); + Track copy = original; #define TEST( x ) QVERIFY( original.x == copy.x ) TEST( title() ); @@ -33,3 +39,5 @@ #undef TEST } }; + +#endif diff -Nru liblastfm-0.4.0~really0.3.3/tests/TestUrlBuilder.h liblastfm-1.0.1/tests/TestUrlBuilder.h --- liblastfm-0.4.0~really0.3.3/tests/TestUrlBuilder.h 2010-09-25 17:30:01.000000000 +0000 +++ liblastfm-1.0.1/tests/TestUrlBuilder.h 2012-06-18 10:37:51.000000000 +0000 @@ -3,11 +3,17 @@ support, and with no warranty, express or implied, as to its usefulness for any purpose. */ + +#ifndef LASTFM_TESTURLBUILDER_H +#define LASTFM_TESTURLBUILDER_H + +#include +#include + #include #include #include -#include -#include + static inline int getResponseCode( const QUrl& url ) { @@ -72,9 +78,11 @@ 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 ); } }; + +#endif