parent
d3664dcf78
commit
171575256c
@ -95,9 +95,7 @@ commands:
|
|||||||
libqt5-linguist-devel
|
libqt5-linguist-devel
|
||||||
libcdio-devel
|
libcdio-devel
|
||||||
libgpod-devel
|
libgpod-devel
|
||||||
libplist-devel
|
|
||||||
libmtp-devel
|
libmtp-devel
|
||||||
libusbmuxd-devel
|
|
||||||
libchromaprint-devel
|
libchromaprint-devel
|
||||||
desktop-file-utils
|
desktop-file-utils
|
||||||
update-desktop-files
|
update-desktop-files
|
||||||
@ -149,8 +147,6 @@ commands:
|
|||||||
taglib-devel
|
taglib-devel
|
||||||
libcdio-devel
|
libcdio-devel
|
||||||
libgpod-devel
|
libgpod-devel
|
||||||
libplist-devel
|
|
||||||
libusbmuxd-devel
|
|
||||||
libmtp-devel
|
libmtp-devel
|
||||||
libchromaprint-devel
|
libchromaprint-devel
|
||||||
fftw-devel
|
fftw-devel
|
||||||
@ -213,8 +209,6 @@ commands:
|
|||||||
libchromaprint-devel
|
libchromaprint-devel
|
||||||
libcdio-devel
|
libcdio-devel
|
||||||
libgpod-devel
|
libgpod-devel
|
||||||
libplist-devel
|
|
||||||
libusbmuxd-devel
|
|
||||||
libmtp-devel
|
libmtp-devel
|
||||||
libjpeg-devel
|
libjpeg-devel
|
||||||
cairo-devel
|
cairo-devel
|
||||||
@ -280,8 +274,6 @@ commands:
|
|||||||
lib64gstreamer-plugins-base1.0-devel
|
lib64gstreamer-plugins-base1.0-devel
|
||||||
lib64cdio-devel
|
lib64cdio-devel
|
||||||
lib64gpod-devel
|
lib64gpod-devel
|
||||||
lib64plist-devel
|
|
||||||
lib64usbmuxd-devel
|
|
||||||
lib64mtp-devel
|
lib64mtp-devel
|
||||||
lib64raw1394-devel
|
lib64raw1394-devel
|
||||||
lib64chromaprint-devel
|
lib64chromaprint-devel
|
||||||
@ -335,9 +327,6 @@ commands:
|
|||||||
libcdio-dev
|
libcdio-dev
|
||||||
libmtp-dev
|
libmtp-dev
|
||||||
libgpod-dev
|
libgpod-dev
|
||||||
libimobiledevice-dev
|
|
||||||
libplist-dev
|
|
||||||
libusbmuxd-dev
|
|
||||||
|
|
||||||
|
|
||||||
install_ubuntu_dependencies:
|
install_ubuntu_dependencies:
|
||||||
@ -389,9 +378,6 @@ commands:
|
|||||||
libcdio-dev
|
libcdio-dev
|
||||||
libmtp-dev
|
libmtp-dev
|
||||||
libgpod-dev
|
libgpod-dev
|
||||||
libimobiledevice-dev
|
|
||||||
libplist-dev
|
|
||||||
libusbmuxd-dev
|
|
||||||
|
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
|
34
.github/workflows/ccpp.yml
vendored
34
.github/workflows/ccpp.yml
vendored
@ -53,9 +53,7 @@ jobs:
|
|||||||
libqt5-linguist-devel
|
libqt5-linguist-devel
|
||||||
libcdio-devel
|
libcdio-devel
|
||||||
libgpod-devel
|
libgpod-devel
|
||||||
libplist-devel
|
|
||||||
libmtp-devel
|
libmtp-devel
|
||||||
libusbmuxd-devel
|
|
||||||
libchromaprint-devel
|
libchromaprint-devel
|
||||||
desktop-file-utils
|
desktop-file-utils
|
||||||
update-desktop-files
|
update-desktop-files
|
||||||
@ -123,9 +121,7 @@ jobs:
|
|||||||
libqt5-linguist-devel
|
libqt5-linguist-devel
|
||||||
libcdio-devel
|
libcdio-devel
|
||||||
libgpod-devel
|
libgpod-devel
|
||||||
libplist-devel
|
|
||||||
libmtp-devel
|
libmtp-devel
|
||||||
libusbmuxd-devel
|
|
||||||
libchromaprint-devel
|
libchromaprint-devel
|
||||||
desktop-file-utils
|
desktop-file-utils
|
||||||
update-desktop-files
|
update-desktop-files
|
||||||
@ -201,9 +197,7 @@ jobs:
|
|||||||
libqt5-linguist-devel
|
libqt5-linguist-devel
|
||||||
libcdio-devel
|
libcdio-devel
|
||||||
libgpod-devel
|
libgpod-devel
|
||||||
libplist-devel
|
|
||||||
libmtp-devel
|
libmtp-devel
|
||||||
libusbmuxd-devel
|
|
||||||
libchromaprint-devel
|
libchromaprint-devel
|
||||||
desktop-file-utils
|
desktop-file-utils
|
||||||
update-desktop-files
|
update-desktop-files
|
||||||
@ -281,9 +275,7 @@ jobs:
|
|||||||
libqt5-linguist-devel
|
libqt5-linguist-devel
|
||||||
libcdio-devel
|
libcdio-devel
|
||||||
libgpod-devel
|
libgpod-devel
|
||||||
libplist-devel
|
|
||||||
libmtp-devel
|
libmtp-devel
|
||||||
libusbmuxd-devel
|
|
||||||
libchromaprint-devel
|
libchromaprint-devel
|
||||||
desktop-file-utils
|
desktop-file-utils
|
||||||
update-desktop-files
|
update-desktop-files
|
||||||
@ -363,9 +355,7 @@ jobs:
|
|||||||
qt6-qt5compat-devel
|
qt6-qt5compat-devel
|
||||||
libcdio-devel
|
libcdio-devel
|
||||||
libgpod-devel
|
libgpod-devel
|
||||||
libplist-devel
|
|
||||||
libmtp-devel
|
libmtp-devel
|
||||||
libusbmuxd-devel
|
|
||||||
libchromaprint-devel
|
libchromaprint-devel
|
||||||
desktop-file-utils
|
desktop-file-utils
|
||||||
update-desktop-files
|
update-desktop-files
|
||||||
@ -434,8 +424,6 @@ jobs:
|
|||||||
taglib-devel
|
taglib-devel
|
||||||
libcdio-devel
|
libcdio-devel
|
||||||
libgpod-devel
|
libgpod-devel
|
||||||
libplist-devel
|
|
||||||
libusbmuxd-devel
|
|
||||||
libmtp-devel
|
libmtp-devel
|
||||||
libchromaprint-devel
|
libchromaprint-devel
|
||||||
fftw-devel
|
fftw-devel
|
||||||
@ -518,8 +506,6 @@ jobs:
|
|||||||
libchromaprint-devel
|
libchromaprint-devel
|
||||||
libcdio-devel
|
libcdio-devel
|
||||||
libgpod-devel
|
libgpod-devel
|
||||||
libplist-devel
|
|
||||||
libusbmuxd-devel
|
|
||||||
libmtp-devel
|
libmtp-devel
|
||||||
libjpeg-devel
|
libjpeg-devel
|
||||||
cairo-devel
|
cairo-devel
|
||||||
@ -607,8 +593,6 @@ jobs:
|
|||||||
lib64gstreamer-plugins-base1.0-devel
|
lib64gstreamer-plugins-base1.0-devel
|
||||||
lib64cdio-devel
|
lib64cdio-devel
|
||||||
lib64gpod-devel
|
lib64gpod-devel
|
||||||
lib64plist-devel
|
|
||||||
lib64usbmuxd-devel
|
|
||||||
lib64mtp-devel
|
lib64mtp-devel
|
||||||
lib64raw1394-devel
|
lib64raw1394-devel
|
||||||
lib64chromaprint-devel
|
lib64chromaprint-devel
|
||||||
@ -684,9 +668,6 @@ jobs:
|
|||||||
libcdio-dev
|
libcdio-dev
|
||||||
libmtp-dev
|
libmtp-dev
|
||||||
libgpod-dev
|
libgpod-dev
|
||||||
libimobiledevice-dev
|
|
||||||
libplist-dev
|
|
||||||
libusbmuxd-dev
|
|
||||||
- name: Create Build Environment
|
- name: Create Build Environment
|
||||||
shell: bash
|
shell: bash
|
||||||
run: cmake -E make_directory build
|
run: cmake -E make_directory build
|
||||||
@ -743,9 +724,6 @@ jobs:
|
|||||||
libcdio-dev
|
libcdio-dev
|
||||||
libmtp-dev
|
libmtp-dev
|
||||||
libgpod-dev
|
libgpod-dev
|
||||||
libimobiledevice-dev
|
|
||||||
libplist-dev
|
|
||||||
libusbmuxd-dev
|
|
||||||
- name: Create Build Environment
|
- name: Create Build Environment
|
||||||
shell: bash
|
shell: bash
|
||||||
run: cmake -E make_directory build
|
run: cmake -E make_directory build
|
||||||
@ -807,9 +785,6 @@ jobs:
|
|||||||
libcdio-dev
|
libcdio-dev
|
||||||
libmtp-dev
|
libmtp-dev
|
||||||
libgpod-dev
|
libgpod-dev
|
||||||
libimobiledevice-dev
|
|
||||||
libplist-dev
|
|
||||||
libusbmuxd-dev
|
|
||||||
- name: Create Build Environment
|
- name: Create Build Environment
|
||||||
shell: bash
|
shell: bash
|
||||||
run: cmake -E make_directory build
|
run: cmake -E make_directory build
|
||||||
@ -871,9 +846,6 @@ jobs:
|
|||||||
libcdio-dev
|
libcdio-dev
|
||||||
libmtp-dev
|
libmtp-dev
|
||||||
libgpod-dev
|
libgpod-dev
|
||||||
libimobiledevice-dev
|
|
||||||
libplist-dev
|
|
||||||
libusbmuxd-dev
|
|
||||||
- name: Create Build Environment
|
- name: Create Build Environment
|
||||||
shell: bash
|
shell: bash
|
||||||
run: cmake -E make_directory build
|
run: cmake -E make_directory build
|
||||||
@ -935,9 +907,6 @@ jobs:
|
|||||||
libcdio-dev
|
libcdio-dev
|
||||||
libmtp-dev
|
libmtp-dev
|
||||||
libgpod-dev
|
libgpod-dev
|
||||||
libimobiledevice-dev
|
|
||||||
libplist-dev
|
|
||||||
libusbmuxd-dev
|
|
||||||
- name: Create Build Environment
|
- name: Create Build Environment
|
||||||
shell: bash
|
shell: bash
|
||||||
run: cmake -E make_directory build
|
run: cmake -E make_directory build
|
||||||
@ -980,8 +949,6 @@ jobs:
|
|||||||
gst-libav
|
gst-libav
|
||||||
libcdio
|
libcdio
|
||||||
libmtp
|
libmtp
|
||||||
libimobiledevice
|
|
||||||
libplist
|
|
||||||
create-dmg
|
create-dmg
|
||||||
taglib
|
taglib
|
||||||
|
|
||||||
@ -1045,7 +1012,6 @@ jobs:
|
|||||||
-DENABLE_WIN32_CONSOLE=OFF
|
-DENABLE_WIN32_CONSOLE=OFF
|
||||||
-DENABLE_DBUS=OFF
|
-DENABLE_DBUS=OFF
|
||||||
-DENABLE_LIBGPOD=OFF
|
-DENABLE_LIBGPOD=OFF
|
||||||
-DENABLE_IMOBILEDEVICE=OFF
|
|
||||||
-DENABLE_LIBMTP=OFF
|
-DENABLE_LIBMTP=OFF
|
||||||
-DProtobuf_PROTOC_EXECUTABLE=/usr/src/strawberry-mxe/usr/x86_64-pc-linux-gnu/bin/protoc
|
-DProtobuf_PROTOC_EXECUTABLE=/usr/src/strawberry-mxe/usr/x86_64-pc-linux-gnu/bin/protoc
|
||||||
|
|
||||||
|
@ -23,7 +23,7 @@ before_install:
|
|||||||
brew unlink python@2 || travis_terminate 1;
|
brew unlink python@2 || travis_terminate 1;
|
||||||
brew install glib pkgconfig libffi protobuf protobuf-c qt gettext gnutls fftw sqlite chromaprint zlib taglib;
|
brew install glib pkgconfig libffi protobuf protobuf-c qt gettext gnutls fftw sqlite chromaprint zlib taglib;
|
||||||
brew install gstreamer gst-plugins-base gst-plugins-good gst-plugins-bad gst-plugins-ugly gst-libav;
|
brew install gstreamer gst-plugins-base gst-plugins-good gst-plugins-bad gst-plugins-ugly gst-libav;
|
||||||
brew install libcdio libmtp libimobiledevice libplist;
|
brew install libcdio libmtp;
|
||||||
brew install create-dmg;
|
brew install create-dmg;
|
||||||
brew cask install sparkle;
|
brew cask install sparkle;
|
||||||
sudo ln -s /usr/local/Caskroom/sparkle/$(ls /usr/local/Caskroom/sparkle | head -n1)/Sparkle.framework /Library/Frameworks/Sparkle.framework;
|
sudo ln -s /usr/local/Caskroom/sparkle/$(ls /usr/local/Caskroom/sparkle | head -n1)/Sparkle.framework /Library/Frameworks/Sparkle.framework;
|
||||||
|
@ -126,9 +126,6 @@ pkg_check_modules(LIBPULSE libpulse)
|
|||||||
pkg_check_modules(CHROMAPRINT libchromaprint)
|
pkg_check_modules(CHROMAPRINT libchromaprint)
|
||||||
pkg_check_modules(LIBGPOD libgpod-1.0>=0.7.92)
|
pkg_check_modules(LIBGPOD libgpod-1.0>=0.7.92)
|
||||||
pkg_check_modules(LIBMTP libmtp>=1.0)
|
pkg_check_modules(LIBMTP libmtp>=1.0)
|
||||||
pkg_check_modules(LIBIMOBILEDEVICE libimobiledevice-1.0)
|
|
||||||
pkg_search_module(LIBUSBMUXD libusbmuxd-2.0 libusbmuxd)
|
|
||||||
pkg_search_module(LIBPLIST libplist-2.0 libplist)
|
|
||||||
find_package(Gettext)
|
find_package(Gettext)
|
||||||
find_package(FFTW3)
|
find_package(FFTW3)
|
||||||
|
|
||||||
@ -344,13 +341,6 @@ optional_component(LIBMTP ON "Devices: MTP support"
|
|||||||
DEPENDS "libmtp" LIBMTP_FOUND
|
DEPENDS "libmtp" LIBMTP_FOUND
|
||||||
)
|
)
|
||||||
|
|
||||||
optional_component(IMOBILEDEVICE ON "Devices: iPhone, iPod Touch, iPad and Apple TV support"
|
|
||||||
DEPENDS "libimobiledevice" LIBIMOBILEDEVICE_FOUND
|
|
||||||
DEPENDS "libplist" LIBPLIST_FOUND
|
|
||||||
DEPENDS "libusbmuxd" LIBUSBMUXD_FOUND
|
|
||||||
DEPENDS "libgpod" HAVE_LIBGPOD
|
|
||||||
)
|
|
||||||
|
|
||||||
optional_component(SPARKLE ON "Sparkle integration"
|
optional_component(SPARKLE ON "Sparkle integration"
|
||||||
DEPENDS "macOS" APPLE
|
DEPENDS "macOS" APPLE
|
||||||
DEPENDS "Sparkle" SPARKLE
|
DEPENDS "Sparkle" SPARKLE
|
||||||
|
@ -36,6 +36,7 @@ Unreleased:
|
|||||||
|
|
||||||
Removed features:
|
Removed features:
|
||||||
* Removed Xine engine support.
|
* Removed Xine engine support.
|
||||||
|
* Removed broken imobiledevice (iPhone) support.
|
||||||
|
|
||||||
0.6.13:
|
0.6.13:
|
||||||
|
|
||||||
|
@ -44,7 +44,7 @@ You can also make a one-time payment through [paypal.me/jonaskvinge](https://pay
|
|||||||
* Support for multiple backends
|
* Support for multiple backends
|
||||||
* Audio analyzer
|
* Audio analyzer
|
||||||
* Audio equalizer
|
* Audio equalizer
|
||||||
* Transfer music to iPod, iPhone, MTP or mass-storage USB player
|
* Transfer music to iPod, MTP or mass-storage USB player
|
||||||
* Scrobbler with support for [Last.fm](https://www.last.fm/), [Libre.fm](https://libre.fm/) and [ListenBrainz](https://listenbrainz.org/)
|
* Scrobbler with support for [Last.fm](https://www.last.fm/), [Libre.fm](https://libre.fm/) and [ListenBrainz](https://listenbrainz.org/)
|
||||||
* Subsonic and Tidal streaming support
|
* Subsonic and Tidal streaming support
|
||||||
|
|
||||||
@ -78,7 +78,6 @@ Optional dependencies:
|
|||||||
* Audio CD: [libcdio](https://www.gnu.org/software/libcdio/)
|
* Audio CD: [libcdio](https://www.gnu.org/software/libcdio/)
|
||||||
* MTP devices: [libmtp](http://libmtp.sourceforge.net/)
|
* MTP devices: [libmtp](http://libmtp.sourceforge.net/)
|
||||||
* iPod Classic devices: [libgpod](http://www.gtkpod.org/libgpod/)
|
* iPod Classic devices: [libgpod](http://www.gtkpod.org/libgpod/)
|
||||||
* iPhone, iPod Touch, iPad and Apple TV devices: [libimobiledevice, libplist and libusbmuxd](https://www.libimobiledevice.org/)
|
|
||||||
* Moodbar: [fftw3](http://www.fftw.org/)
|
* Moodbar: [fftw3](http://www.fftw.org/)
|
||||||
|
|
||||||
Either GStreamer or VLC engine is required, but only GStreamer is fully implemented so far.
|
Either GStreamer or VLC engine is required, but only GStreamer is fully implemented so far.
|
||||||
|
3
debian/control
vendored
3
debian/control
vendored
@ -24,10 +24,7 @@ Build-Depends: debhelper (>= 11),
|
|||||||
libgstreamer-plugins-base1.0-dev,
|
libgstreamer-plugins-base1.0-dev,
|
||||||
libcdio-dev,
|
libcdio-dev,
|
||||||
libgpod-dev,
|
libgpod-dev,
|
||||||
libimobiledevice-dev,
|
|
||||||
libmtp-dev,
|
libmtp-dev,
|
||||||
libplist-dev,
|
|
||||||
libusbmuxd-dev,
|
|
||||||
libchromaprint-dev,
|
libchromaprint-dev,
|
||||||
libfftw3-dev
|
libfftw3-dev
|
||||||
Standards-Version: 4.2.1
|
Standards-Version: 4.2.1
|
||||||
|
3
dist/unix/PKGBUILD.in
vendored
3
dist/unix/PKGBUILD.in
vendored
@ -28,9 +28,6 @@ depends=(
|
|||||||
libgpod
|
libgpod
|
||||||
libcdio
|
libcdio
|
||||||
libmtp
|
libmtp
|
||||||
libusbmuxd
|
|
||||||
libplist
|
|
||||||
libimobiledevice
|
|
||||||
fftw
|
fftw
|
||||||
)
|
)
|
||||||
optdepends=(
|
optdepends=(
|
||||||
|
2
dist/unix/strawberry.spec.in
vendored
2
dist/unix/strawberry.spec.in
vendored
@ -106,7 +106,7 @@ Features:
|
|||||||
- Support for multiple backends
|
- Support for multiple backends
|
||||||
- Audio analyzer
|
- Audio analyzer
|
||||||
- Audio equalizer
|
- Audio equalizer
|
||||||
- Transfer music to iPod, iPhone, MTP or mass-storage USB player
|
- Transfer music to iPod, MTP or mass-storage USB player
|
||||||
- Scrobbler with support for Last.fm, Libre.fm and ListenBrainz
|
- Scrobbler with support for Last.fm, Libre.fm and ListenBrainz
|
||||||
- Streaming support for Subsonic
|
- Streaming support for Subsonic
|
||||||
|
|
||||||
|
@ -101,11 +101,8 @@ parts:
|
|||||||
- libgstreamer-plugins-base1.0-dev
|
- libgstreamer-plugins-base1.0-dev
|
||||||
- libvlc-dev
|
- libvlc-dev
|
||||||
- libcdio-dev
|
- libcdio-dev
|
||||||
- libgpod-dev
|
- libgpod-devdev
|
||||||
- libimobiledevice-dev
|
|
||||||
- libmtp-dev
|
- libmtp-dev
|
||||||
- libplist-dev
|
|
||||||
- libusbmuxd-dev
|
|
||||||
- libchromaprint-dev
|
- libchromaprint-dev
|
||||||
- libfftw3-dev
|
- libfftw3-dev
|
||||||
|
|
||||||
@ -131,9 +128,6 @@ parts:
|
|||||||
- libcdio17
|
- libcdio17
|
||||||
- libgpod4
|
- libgpod4
|
||||||
- libmtp9
|
- libmtp9
|
||||||
- libimobiledevice6
|
|
||||||
- libplist3
|
|
||||||
- libusbmuxd4
|
|
||||||
- libvlc5
|
- libvlc5
|
||||||
- libvlccore9
|
- libvlccore9
|
||||||
- libtag1v5
|
- libtag1v5
|
||||||
|
@ -737,21 +737,6 @@ optional_source(HAVE_GIO
|
|||||||
HEADERS device/giolister.h
|
HEADERS device/giolister.h
|
||||||
)
|
)
|
||||||
|
|
||||||
# imobiledevice backend and device
|
|
||||||
optional_source(HAVE_IMOBILEDEVICE
|
|
||||||
SOURCES
|
|
||||||
device/afcdevice.cpp
|
|
||||||
device/afcfile.cpp
|
|
||||||
device/afctransfer.cpp
|
|
||||||
device/ilister.cpp
|
|
||||||
device/imobiledeviceconnection.cpp
|
|
||||||
HEADERS
|
|
||||||
device/afcdevice.h
|
|
||||||
device/afcfile.h
|
|
||||||
device/afctransfer.h
|
|
||||||
device/ilister.h
|
|
||||||
)
|
|
||||||
|
|
||||||
# mtp device
|
# mtp device
|
||||||
optional_source(HAVE_LIBMTP
|
optional_source(HAVE_LIBMTP
|
||||||
SOURCES
|
SOURCES
|
||||||
@ -1035,14 +1020,6 @@ if(HAVE_LIBMTP)
|
|||||||
link_directories(${LIBMTP_LIBRARY_DIRS})
|
link_directories(${LIBMTP_LIBRARY_DIRS})
|
||||||
endif(HAVE_LIBMTP)
|
endif(HAVE_LIBMTP)
|
||||||
|
|
||||||
if(HAVE_IMOBILEDEVICE)
|
|
||||||
link_directories(
|
|
||||||
${LIBUSBMUXD_LIBRARY_DIRS}
|
|
||||||
${LIBPLIST_LIBRARY_DIRS}
|
|
||||||
${LIBIMOBILEDEVICE_LIBRARY_DIRS}
|
|
||||||
)
|
|
||||||
endif(HAVE_IMOBILEDEVICE)
|
|
||||||
|
|
||||||
add_library(strawberry_lib STATIC
|
add_library(strawberry_lib STATIC
|
||||||
${SOURCES}
|
${SOURCES}
|
||||||
${MOC}
|
${MOC}
|
||||||
@ -1163,19 +1140,6 @@ if(HAVE_LIBMTP)
|
|||||||
target_link_libraries(strawberry_lib PRIVATE ${LIBMTP_LIBRARIES})
|
target_link_libraries(strawberry_lib PRIVATE ${LIBMTP_LIBRARIES})
|
||||||
endif(HAVE_LIBMTP)
|
endif(HAVE_LIBMTP)
|
||||||
|
|
||||||
if(HAVE_IMOBILEDEVICE)
|
|
||||||
target_include_directories(strawberry_lib SYSTEM PRIVATE
|
|
||||||
${LIBUSBMUXD_INCLUDE_DIRS}
|
|
||||||
${LIBPLIST_INCLUDE_DIRS}
|
|
||||||
${LIBIMOBILEDEVICE_INCLUDE_DIRS}
|
|
||||||
)
|
|
||||||
target_link_libraries(strawberry_lib PRIVATE
|
|
||||||
${LIBUSBMUXD_LIBRARIES}
|
|
||||||
${LIBPLIST_LIBRARIES}
|
|
||||||
${LIBIMOBILEDEVICE_LIBRARIES}
|
|
||||||
)
|
|
||||||
endif(HAVE_IMOBILEDEVICE)
|
|
||||||
|
|
||||||
|
|
||||||
if(APPLE)
|
if(APPLE)
|
||||||
target_link_libraries(strawberry_lib PRIVATE
|
target_link_libraries(strawberry_lib PRIVATE
|
||||||
|
@ -31,7 +31,6 @@
|
|||||||
#cmakedefine HAVE_X11
|
#cmakedefine HAVE_X11
|
||||||
#cmakedefine HAVE_UDISKS2
|
#cmakedefine HAVE_UDISKS2
|
||||||
#cmakedefine HAVE_ALSA
|
#cmakedefine HAVE_ALSA
|
||||||
#cmakedefine HAVE_IMOBILEDEVICE
|
|
||||||
#cmakedefine HAVE_AUDIOCD
|
#cmakedefine HAVE_AUDIOCD
|
||||||
#cmakedefine HAVE_LIBGPOD
|
#cmakedefine HAVE_LIBGPOD
|
||||||
#cmakedefine HAVE_LIBMTP
|
#cmakedefine HAVE_LIBMTP
|
||||||
|
@ -1,213 +0,0 @@
|
|||||||
/*
|
|
||||||
* Strawberry Music Player
|
|
||||||
* This file was part of Clementine.
|
|
||||||
* Copyright 2010, David Sansome <me@davidsansome.com>
|
|
||||||
*
|
|
||||||
* Strawberry is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* Strawberry is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with Strawberry. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "config.h"
|
|
||||||
|
|
||||||
#include <memory>
|
|
||||||
|
|
||||||
#include <QThread>
|
|
||||||
#include <QFile>
|
|
||||||
#include <QList>
|
|
||||||
#include <QString>
|
|
||||||
#include <QUrl>
|
|
||||||
|
|
||||||
#include "core/application.h"
|
|
||||||
#include "core/utilities.h"
|
|
||||||
#include "core/song.h"
|
|
||||||
#include "afcdevice.h"
|
|
||||||
#include "afcfile.h"
|
|
||||||
#include "afctransfer.h"
|
|
||||||
#include "devicemanager.h"
|
|
||||||
#include "gpodloader.h"
|
|
||||||
#include "imobiledeviceconnection.h"
|
|
||||||
|
|
||||||
AfcDevice::AfcDevice(const QUrl &url, DeviceLister *lister, const QString &unique_id, DeviceManager *manager, Application *app, const int database_id, const bool first_time) : GPodDevice(url, lister, unique_id, manager, app, database_id, first_time), transfer_(nullptr) {}
|
|
||||||
|
|
||||||
AfcDevice::~AfcDevice() {
|
|
||||||
|
|
||||||
Utilities::RemoveRecursive(local_path_);
|
|
||||||
|
|
||||||
if (loader_) {
|
|
||||||
loader_->deleteLater();
|
|
||||||
loader_ = nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (loader_thread_) {
|
|
||||||
loader_thread_->exit();
|
|
||||||
loader_thread_->deleteLater();
|
|
||||||
loader_thread_ = nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
bool AfcDevice::Init() {
|
|
||||||
|
|
||||||
// Make a new temporary directory for the iTunesDB. We copy it off the iPod so that libgpod can have a local directory to use.
|
|
||||||
local_path_ = Utilities::MakeTempDir();
|
|
||||||
InitBackendDirectory(local_path_, first_time_, false);
|
|
||||||
model_->Init();
|
|
||||||
|
|
||||||
if (!loader_thread_) loader_thread_ = new QThread();
|
|
||||||
|
|
||||||
if (url_.isEmpty() || url_.path().isEmpty()) return false;
|
|
||||||
|
|
||||||
transfer_ = new AfcTransfer(url_.host(), local_path_, app_->task_manager(), shared_from_this());
|
|
||||||
transfer_->moveToThread(loader_thread_);
|
|
||||||
|
|
||||||
connect(transfer_, SIGNAL(TaskStarted(int)), SIGNAL(TaskStarted(int)));
|
|
||||||
connect(transfer_, SIGNAL(CopyFinished(bool)), SLOT(CopyFinished(bool)));
|
|
||||||
|
|
||||||
connect(loader_thread_, SIGNAL(started()), transfer_, SLOT(CopyFromDevice()));
|
|
||||||
loader_thread_->start();
|
|
||||||
|
|
||||||
return true;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void AfcDevice::CopyFinished(const bool success) {
|
|
||||||
|
|
||||||
transfer_->deleteLater();
|
|
||||||
transfer_ = nullptr;
|
|
||||||
|
|
||||||
if (!success) {
|
|
||||||
app_->AddError(tr("An error occurred copying the iTunes database from the device"));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Now load the songs from the local database
|
|
||||||
loader_ = new GPodLoader(local_path_, app_->task_manager(), backend_, shared_from_this());
|
|
||||||
loader_->set_music_path_prefix("afc://" + url_.host());
|
|
||||||
loader_->set_song_type(Song::FileType_Stream);
|
|
||||||
loader_->moveToThread(loader_thread_);
|
|
||||||
|
|
||||||
connect(loader_, SIGNAL(Error(QString)), SLOT(LoaderError(QString)));
|
|
||||||
connect(loader_, SIGNAL(TaskStarted(int)), SIGNAL(TaskStarted(int)));
|
|
||||||
connect(loader_, SIGNAL(LoadFinished(Itdb_iTunesDB*, bool)), SLOT(LoadFinished(Itdb_iTunesDB*, bool)));
|
|
||||||
QMetaObject::invokeMethod(loader_, "LoadDatabase");
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
bool AfcDevice::StartCopy(QList<Song::FileType> *supported_types) {
|
|
||||||
|
|
||||||
GPodDevice::StartCopy(supported_types);
|
|
||||||
connection_.reset(new iMobileDeviceConnection(url_.host()));
|
|
||||||
|
|
||||||
return true;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
bool AfcDevice::CopyToStorage(const CopyJob &job) {
|
|
||||||
|
|
||||||
Q_ASSERT(db_);
|
|
||||||
|
|
||||||
Itdb_Track *track = AddTrackToITunesDb(job.metadata_);
|
|
||||||
|
|
||||||
// Get an unused filename on the device
|
|
||||||
QString dest = connection_->GetUnusedFilename(db_, job.metadata_);
|
|
||||||
if (dest.isEmpty()) {
|
|
||||||
itdb_track_remove(track);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Copy the file
|
|
||||||
{
|
|
||||||
QFile source_file(job.source_);
|
|
||||||
AfcFile dest_file(connection_.get(), dest);
|
|
||||||
if (!Utilities::Copy(&source_file, &dest_file))
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
track->transferred = 1;
|
|
||||||
|
|
||||||
// Set the filetype_marker
|
|
||||||
QString suffix = dest.section('.', -1, -1).toUpper();
|
|
||||||
track->filetype_marker = 0;
|
|
||||||
for (int i=0 ; i<4 ; ++i) {
|
|
||||||
track->filetype_marker = track->filetype_marker << 8;
|
|
||||||
if (i >= suffix.length())
|
|
||||||
track->filetype_marker |= ' ';
|
|
||||||
else
|
|
||||||
track->filetype_marker |= suffix[i].toLatin1();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set the filename
|
|
||||||
track->ipod_path = strdup(dest.toUtf8().constData());
|
|
||||||
itdb_filename_fs2ipod(track->ipod_path);
|
|
||||||
|
|
||||||
AddTrackToModel(track, "afc://" + url_.host());
|
|
||||||
|
|
||||||
// Remove the original if it was requested
|
|
||||||
if (job.remove_original_) {
|
|
||||||
QFile::remove(job.source_);
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void AfcDevice::FinishCopy(bool success) {
|
|
||||||
|
|
||||||
// Temporarily unset the GUID so libgpod doesn't lock the device for syncing
|
|
||||||
itdb_device_set_sysinfo(db_->device, "FirewireGuid", nullptr);
|
|
||||||
|
|
||||||
GPodDevice::FinishCopy(success);
|
|
||||||
|
|
||||||
// Close the connection to the device
|
|
||||||
connection_.reset();
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void AfcDevice::FinaliseDatabase() {
|
|
||||||
|
|
||||||
// Set the GUID again to lock the device for syncing
|
|
||||||
itdb_device_set_sysinfo(db_->device, "FirewireGuid", url_.host().toUtf8().constData());
|
|
||||||
|
|
||||||
// Copy the files back to the iPod
|
|
||||||
// No need to start another thread since we're already in the organizer thread
|
|
||||||
AfcTransfer transfer(url_.host(), local_path_, nullptr, shared_from_this());
|
|
||||||
|
|
||||||
itdb_start_sync(db_);
|
|
||||||
bool success = transfer.CopyToDevice(connection_.get());
|
|
||||||
itdb_stop_sync(db_);
|
|
||||||
|
|
||||||
if (!success) {
|
|
||||||
app_->AddError(tr("An error occurred copying the iTunes database onto the device"));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
bool AfcDevice::DeleteFromStorage(const DeleteJob &job) {
|
|
||||||
|
|
||||||
const QString path = job.metadata_.url().toLocalFile();
|
|
||||||
|
|
||||||
if (!RemoveTrackFromITunesDb(path))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
// Remove the file
|
|
||||||
if (afc_remove_path(connection_->afc(), path.toUtf8().constData()) != AFC_E_SUCCESS)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
// Remove it from our collection model
|
|
||||||
songs_to_remove_ << job.metadata_;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
|
|
||||||
}
|
|
@ -1,75 +0,0 @@
|
|||||||
/*
|
|
||||||
* Strawberry Music Player
|
|
||||||
* This file was part of Clementine.
|
|
||||||
* Copyright 2010, David Sansome <me@davidsansome.com>
|
|
||||||
*
|
|
||||||
* Strawberry is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* Strawberry is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with Strawberry. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef AFCDEVICE_H
|
|
||||||
#define AFCDEVICE_H
|
|
||||||
|
|
||||||
#include "config.h"
|
|
||||||
|
|
||||||
#include <memory>
|
|
||||||
|
|
||||||
#include <gpod/itdb.h>
|
|
||||||
|
|
||||||
#include <QObject>
|
|
||||||
#include <QMutex>
|
|
||||||
#include <QList>
|
|
||||||
#include <QString>
|
|
||||||
#include <QStringList>
|
|
||||||
#include <QUrl>
|
|
||||||
|
|
||||||
#include "gpoddevice.h"
|
|
||||||
|
|
||||||
class AfcTransfer;
|
|
||||||
class iMobileDeviceConnection;
|
|
||||||
|
|
||||||
class AfcDevice : public GPodDevice {
|
|
||||||
Q_OBJECT
|
|
||||||
|
|
||||||
public:
|
|
||||||
Q_INVOKABLE AfcDevice(const QUrl &url, DeviceLister *lister, const QString &unique_id, DeviceManager *manager, Application *app, const int database_id, const bool first_time);
|
|
||||||
~AfcDevice() override;
|
|
||||||
|
|
||||||
bool Init() override;
|
|
||||||
|
|
||||||
static QStringList url_schemes() { return QStringList() << "afc"; }
|
|
||||||
|
|
||||||
bool StartCopy(QList<Song::FileType> *supported_types) override;
|
|
||||||
bool CopyToStorage(const CopyJob &job) override;
|
|
||||||
void FinishCopy(const bool success) override;
|
|
||||||
|
|
||||||
bool DeleteFromStorage(const DeleteJob &job) override;
|
|
||||||
|
|
||||||
protected:
|
|
||||||
void FinaliseDatabase() override;
|
|
||||||
|
|
||||||
private slots:
|
|
||||||
void CopyFinished(bool success);
|
|
||||||
|
|
||||||
private:
|
|
||||||
void RemoveRecursive(const QString &path);
|
|
||||||
|
|
||||||
private:
|
|
||||||
AfcTransfer *transfer_;
|
|
||||||
std::shared_ptr<iMobileDeviceConnection> connection_;
|
|
||||||
|
|
||||||
QString local_path_;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif // AFCDEVICE_H
|
|
@ -1,95 +0,0 @@
|
|||||||
#include "config.h"
|
|
||||||
|
|
||||||
#include <libimobiledevice/afc.h>
|
|
||||||
|
|
||||||
#include <QtGlobal>
|
|
||||||
#include <QObject>
|
|
||||||
#include <QIODevice>
|
|
||||||
#include <QString>
|
|
||||||
|
|
||||||
#include "afcfile.h"
|
|
||||||
#include "imobiledeviceconnection.h"
|
|
||||||
|
|
||||||
AfcFile::AfcFile(iMobileDeviceConnection *connection, const QString &path, QObject *parent)
|
|
||||||
: QIODevice(parent),
|
|
||||||
connection_(connection),
|
|
||||||
handle_(0),
|
|
||||||
path_(path)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
AfcFile::~AfcFile() {
|
|
||||||
close();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool AfcFile::open(QIODevice::OpenMode mode) {
|
|
||||||
|
|
||||||
afc_file_mode_t afc_mode;
|
|
||||||
switch (mode) {
|
|
||||||
case ReadOnly:
|
|
||||||
afc_mode = AFC_FOPEN_RDONLY;
|
|
||||||
break;
|
|
||||||
case WriteOnly:
|
|
||||||
afc_mode = AFC_FOPEN_WRONLY;
|
|
||||||
break;
|
|
||||||
case ReadWrite:
|
|
||||||
afc_mode = AFC_FOPEN_RW;
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
afc_mode = AFC_FOPEN_RW;
|
|
||||||
}
|
|
||||||
afc_error_t err = afc_file_open(connection_->afc(), path_.toUtf8().constData(), afc_mode, &handle_);
|
|
||||||
if (err != AFC_E_SUCCESS) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return QIODevice::open(mode);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void AfcFile::close() {
|
|
||||||
|
|
||||||
if (handle_) {
|
|
||||||
afc_file_close(connection_->afc(), handle_);
|
|
||||||
}
|
|
||||||
QIODevice::close();
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
bool AfcFile::seek(qint64 pos) {
|
|
||||||
|
|
||||||
afc_error_t err = afc_file_seek(connection_->afc(), handle_, pos, SEEK_SET);
|
|
||||||
if (err != AFC_E_SUCCESS) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
QIODevice::seek(pos);
|
|
||||||
return true;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
qint64 AfcFile::readData(char *data, qint64 max_size) {
|
|
||||||
|
|
||||||
uint32_t bytes_read = 0;
|
|
||||||
afc_error_t err = afc_file_read(connection_->afc(), handle_, data, max_size, &bytes_read);
|
|
||||||
if (err != AFC_E_SUCCESS) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
return bytes_read;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
qint64 AfcFile::writeData(const char *data, qint64 max_size) {
|
|
||||||
|
|
||||||
uint32_t bytes_written = 0;
|
|
||||||
afc_error_t err = afc_file_write(connection_->afc(), handle_, data, max_size, &bytes_written);
|
|
||||||
if (err != AFC_E_SUCCESS) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
return bytes_written;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
qint64 AfcFile::size() const {
|
|
||||||
return connection_->GetFileInfo(path_, "st_size").toLongLong();
|
|
||||||
}
|
|
@ -1,40 +0,0 @@
|
|||||||
#ifndef AFCFILE_H
|
|
||||||
#define AFCFILE_H
|
|
||||||
|
|
||||||
#include "config.h"
|
|
||||||
|
|
||||||
#include <cstdint>
|
|
||||||
#include <libimobiledevice/afc.h>
|
|
||||||
|
|
||||||
#include <QtGlobal>
|
|
||||||
#include <QObject>
|
|
||||||
#include <QIODevice>
|
|
||||||
#include <QString>
|
|
||||||
|
|
||||||
class iMobileDeviceConnection;
|
|
||||||
|
|
||||||
class AfcFile : public QIODevice {
|
|
||||||
Q_OBJECT
|
|
||||||
|
|
||||||
public:
|
|
||||||
explicit AfcFile(iMobileDeviceConnection* connection, const QString &path, QObject *parent = nullptr);
|
|
||||||
~AfcFile() override;
|
|
||||||
|
|
||||||
// QIODevice
|
|
||||||
void close() override;
|
|
||||||
bool open(OpenMode mode) override;
|
|
||||||
bool seek(qint64 pos) override;
|
|
||||||
qint64 size() const override;
|
|
||||||
|
|
||||||
private:
|
|
||||||
// QIODevice
|
|
||||||
qint64 readData(char *data, qint64 max_size) override;
|
|
||||||
qint64 writeData(const char *data, qint64 max_size) override;
|
|
||||||
|
|
||||||
iMobileDeviceConnection *connection_;
|
|
||||||
uint64_t handle_;
|
|
||||||
|
|
||||||
QString path_;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
|
@ -1,150 +0,0 @@
|
|||||||
/*
|
|
||||||
* Strawberry Music Player
|
|
||||||
* This file was part of Clementine.
|
|
||||||
* Copyright 2010, David Sansome <me@davidsansome.com>
|
|
||||||
*
|
|
||||||
* Strawberry is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* Strawberry is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with Strawberry. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "config.h"
|
|
||||||
|
|
||||||
#include <memory>
|
|
||||||
|
|
||||||
#include <QObject>
|
|
||||||
#include <QDir>
|
|
||||||
#include <QFile>
|
|
||||||
#include <QString>
|
|
||||||
#include <QtDebug>
|
|
||||||
|
|
||||||
#include "core/utilities.h"
|
|
||||||
#include "core/taskmanager.h"
|
|
||||||
#include "afcfile.h"
|
|
||||||
#include "afctransfer.h"
|
|
||||||
#include "imobiledeviceconnection.h"
|
|
||||||
|
|
||||||
AfcTransfer::AfcTransfer(const QString &uuid, const QString &local_destination, TaskManager *task_manager, std::shared_ptr<ConnectedDevice> device)
|
|
||||||
: QObject(nullptr), device_(device), task_manager_(task_manager), uuid_(uuid), local_destination_(local_destination) {
|
|
||||||
|
|
||||||
original_thread_ = thread();
|
|
||||||
|
|
||||||
important_directories_ << "/iTunes_Control/Artwork";
|
|
||||||
important_directories_ << "/iTunes_Control/Device";
|
|
||||||
important_directories_ << "/iTunes_Control/iTunes";
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void AfcTransfer::CopyFromDevice() {
|
|
||||||
|
|
||||||
int task_id = 0;
|
|
||||||
if (task_manager_) {
|
|
||||||
task_id = task_manager_->StartTask(tr("Copying iPod database"));
|
|
||||||
emit TaskStarted(task_id);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Connect to the device
|
|
||||||
|
|
||||||
iMobileDeviceConnection c(uuid_);
|
|
||||||
|
|
||||||
// Copy directories. If one fails we stop.
|
|
||||||
bool success = true;
|
|
||||||
for (const QString &dir : important_directories_) {
|
|
||||||
if (!CopyDirFromDevice(&c, dir)) {
|
|
||||||
success = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (task_manager_) {
|
|
||||||
moveToThread(original_thread_);
|
|
||||||
task_manager_->SetTaskFinished(task_id);
|
|
||||||
emit CopyFinished(success);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
bool AfcTransfer::CopyToDevice(iMobileDeviceConnection *connection) {
|
|
||||||
|
|
||||||
// Connect to the device
|
|
||||||
if (!connection)
|
|
||||||
connection = new iMobileDeviceConnection(uuid_);
|
|
||||||
|
|
||||||
for (const QString &dir : important_directories_)
|
|
||||||
if (!CopyDirToDevice(connection, dir))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
bool AfcTransfer::CopyDirFromDevice(iMobileDeviceConnection *c, const QString &path) {
|
|
||||||
|
|
||||||
for (const QString &filename : c->ReadDirectory(path, QDir::Files | QDir::NoDotAndDotDot)) {
|
|
||||||
if (!CopyFileFromDevice(c, path + "/" + filename))
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (const QString &dir : c->ReadDirectory(path, QDir::Dirs | QDir::NoDotAndDotDot)) {
|
|
||||||
if (!CopyDirFromDevice(c, path + "/" + dir))
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
bool AfcTransfer::CopyDirToDevice(iMobileDeviceConnection *c, const QString &path) {
|
|
||||||
|
|
||||||
QDir dir(local_destination_ + path);
|
|
||||||
|
|
||||||
if (!c->Exists(path)) {
|
|
||||||
c->MkDir(path);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (const QString &i : dir.entryList(QDir::Files | QDir::NoDotAndDotDot)) {
|
|
||||||
if (!CopyFileToDevice(c, path + "/" + i))
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (const QString &i : dir.entryList(QDir::Dirs | QDir::NoDotAndDotDot)) {
|
|
||||||
if (!CopyDirToDevice(c, path + "/" + i))
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
bool AfcTransfer::CopyFileFromDevice(iMobileDeviceConnection *c, const QString &path) {
|
|
||||||
|
|
||||||
QString local_filename = local_destination_ + path;
|
|
||||||
QString local_dir = local_filename.section('/', 0, -2);
|
|
||||||
|
|
||||||
QDir d;
|
|
||||||
d.mkpath(local_dir);
|
|
||||||
|
|
||||||
QFile dest(local_filename);
|
|
||||||
AfcFile source(c, path);
|
|
||||||
|
|
||||||
return Utilities::Copy(&source, &dest);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
bool AfcTransfer::CopyFileToDevice(iMobileDeviceConnection *c, const QString &path) {
|
|
||||||
|
|
||||||
QFile source(local_destination_ + path);
|
|
||||||
AfcFile dest(c, path);
|
|
||||||
|
|
||||||
return Utilities::Copy(&source, &dest);
|
|
||||||
|
|
||||||
}
|
|
@ -1,70 +0,0 @@
|
|||||||
/*
|
|
||||||
* Strawberry Music Player
|
|
||||||
* This file was part of Clementine.
|
|
||||||
* Copyright 2010, David Sansome <me@davidsansome.com>
|
|
||||||
*
|
|
||||||
* Strawberry is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* Strawberry is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with Strawberry. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef AFCTRANSFER_H
|
|
||||||
#define AFCTRANSFER_H
|
|
||||||
|
|
||||||
#include "config.h"
|
|
||||||
|
|
||||||
#include <memory>
|
|
||||||
|
|
||||||
#include <QObject>
|
|
||||||
#include <QThread>
|
|
||||||
#include <QIODevice>
|
|
||||||
#include <QString>
|
|
||||||
#include <QStringList>
|
|
||||||
|
|
||||||
class TaskManager;
|
|
||||||
class ConnectedDevice;
|
|
||||||
class iMobileDeviceConnection;
|
|
||||||
|
|
||||||
class AfcTransfer : public QObject {
|
|
||||||
Q_OBJECT
|
|
||||||
|
|
||||||
public:
|
|
||||||
explicit AfcTransfer(const QString &uuid, const QString &local_destination, TaskManager *task_manager, std::shared_ptr<ConnectedDevice> device);
|
|
||||||
|
|
||||||
bool CopyToDevice(iMobileDeviceConnection *connection);
|
|
||||||
|
|
||||||
public slots:
|
|
||||||
void CopyFromDevice();
|
|
||||||
|
|
||||||
signals:
|
|
||||||
void TaskStarted(int task_id);
|
|
||||||
void CopyFinished(bool success);
|
|
||||||
|
|
||||||
private:
|
|
||||||
bool CopyDirFromDevice(iMobileDeviceConnection *c, const QString &path);
|
|
||||||
bool CopyDirToDevice(iMobileDeviceConnection *c, const QString &path);
|
|
||||||
bool CopyFileFromDevice(iMobileDeviceConnection *c, const QString &path);
|
|
||||||
bool CopyFileToDevice(iMobileDeviceConnection *c, const QString &path);
|
|
||||||
|
|
||||||
private:
|
|
||||||
QThread *original_thread_;
|
|
||||||
std::shared_ptr<ConnectedDevice> device_;
|
|
||||||
TaskManager *task_manager_;
|
|
||||||
QString uuid_;
|
|
||||||
QString local_destination_;
|
|
||||||
|
|
||||||
QStringList important_directories_;
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif // AFCTRANSFER_H
|
|
@ -73,10 +73,6 @@
|
|||||||
#ifdef HAVE_LIBMTP
|
#ifdef HAVE_LIBMTP
|
||||||
# include "mtpdevice.h"
|
# include "mtpdevice.h"
|
||||||
#endif
|
#endif
|
||||||
#ifdef HAVE_IMOBILEDEVICE
|
|
||||||
# include "afcdevice.h"
|
|
||||||
# include "ilister.h"
|
|
||||||
#endif
|
|
||||||
#if defined(Q_OS_MACOS) and defined(HAVE_LIBMTP)
|
#if defined(Q_OS_MACOS) and defined(HAVE_LIBMTP)
|
||||||
# include "macosdevicelister.h"
|
# include "macosdevicelister.h"
|
||||||
#endif
|
#endif
|
||||||
@ -125,9 +121,6 @@ DeviceManager::DeviceManager(Application *app, QObject *parent)
|
|||||||
#if defined(Q_OS_MACOS) and defined(HAVE_LIBMTP)
|
#if defined(Q_OS_MACOS) and defined(HAVE_LIBMTP)
|
||||||
AddLister(new MacOsDeviceLister);
|
AddLister(new MacOsDeviceLister);
|
||||||
#endif
|
#endif
|
||||||
#ifdef HAVE_IMOBILEDEVICE
|
|
||||||
AddLister(new iLister);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if defined(HAVE_AUDIOCD) && defined(HAVE_GSTREAMER)
|
#if defined(HAVE_AUDIOCD) && defined(HAVE_GSTREAMER)
|
||||||
AddDeviceClass<CddaDevice>();
|
AddDeviceClass<CddaDevice>();
|
||||||
@ -143,10 +136,6 @@ DeviceManager::DeviceManager(Application *app, QObject *parent)
|
|||||||
AddDeviceClass<MtpDevice>();
|
AddDeviceClass<MtpDevice>();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef HAVE_IMOBILEDEVICE
|
|
||||||
AddDeviceClass<AfcDevice>();
|
|
||||||
#endif
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
DeviceManager::~DeviceManager() {
|
DeviceManager::~DeviceManager() {
|
||||||
|
@ -1,239 +0,0 @@
|
|||||||
/*
|
|
||||||
* Strawberry Music Player
|
|
||||||
* This file was part of Clementine.
|
|
||||||
* Copyright 2010, David Sansome <me@davidsansome.com>
|
|
||||||
*
|
|
||||||
* Strawberry is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* Strawberry is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with Strawberry. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "config.h"
|
|
||||||
|
|
||||||
#include <QtGlobal>
|
|
||||||
#include <QMutex>
|
|
||||||
#include <QList>
|
|
||||||
#include <QString>
|
|
||||||
#include <QStringList>
|
|
||||||
#include <QUrl>
|
|
||||||
#include <QtDebug>
|
|
||||||
|
|
||||||
#include "ilister.h"
|
|
||||||
#include "imobiledeviceconnection.h"
|
|
||||||
|
|
||||||
iLister::iLister() {}
|
|
||||||
|
|
||||||
iLister::~iLister() {}
|
|
||||||
|
|
||||||
bool iLister::Init() {
|
|
||||||
|
|
||||||
idevice_event_subscribe(&EventCallback, reinterpret_cast<void*>(this));
|
|
||||||
return true;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void iLister::EventCallback(const idevice_event_t *event, void *context) {
|
|
||||||
|
|
||||||
iLister *me = reinterpret_cast<iLister*>(context);
|
|
||||||
|
|
||||||
QString uuid = QString::fromUtf8(event->udid);
|
|
||||||
|
|
||||||
switch (event->event) {
|
|
||||||
case IDEVICE_DEVICE_ADD:
|
|
||||||
me->DeviceAddedCallback(uuid);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case IDEVICE_DEVICE_REMOVE:
|
|
||||||
me->DeviceRemovedCallback(uuid);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void iLister::DeviceAddedCallback(const QString uuid) {
|
|
||||||
|
|
||||||
DeviceInfo info = ReadDeviceInfo(uuid);
|
|
||||||
if (!info.valid) return;
|
|
||||||
|
|
||||||
QString id = UniqueId(uuid);
|
|
||||||
|
|
||||||
QString name = MakeFriendlyName(id);
|
|
||||||
if (info.product_type == "iPhone 3,1" || info.product_type.startsWith("iPad")) {
|
|
||||||
// iPhone 4 and iPad unsupported by libgpod as of 0.7.94.
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
QMutexLocker l(&mutex_);
|
|
||||||
devices_[id] = info;
|
|
||||||
}
|
|
||||||
|
|
||||||
emit DeviceAdded(id);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void iLister::DeviceRemovedCallback(const QString uuid) {
|
|
||||||
|
|
||||||
QString id = UniqueId(uuid);
|
|
||||||
|
|
||||||
{
|
|
||||||
QMutexLocker l(&mutex_);
|
|
||||||
if (!devices_.contains(id))
|
|
||||||
return;
|
|
||||||
|
|
||||||
devices_.remove(id);
|
|
||||||
}
|
|
||||||
|
|
||||||
emit DeviceRemoved(id);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
QString iLister::UniqueId(const QString uuid) {
|
|
||||||
return "ithing/" + uuid;
|
|
||||||
}
|
|
||||||
|
|
||||||
QStringList iLister::DeviceUniqueIDs() {
|
|
||||||
return devices_.keys();
|
|
||||||
}
|
|
||||||
|
|
||||||
QVariantList iLister::DeviceIcons(const QString &id) {
|
|
||||||
Q_UNUSED(id);
|
|
||||||
return QVariantList() << "ipodtouchicon";
|
|
||||||
}
|
|
||||||
|
|
||||||
QString iLister::DeviceManufacturer(const QString &id) {
|
|
||||||
Q_UNUSED(id);
|
|
||||||
return "Apple";
|
|
||||||
}
|
|
||||||
|
|
||||||
QString iLister::DeviceModel(const QString &id) {
|
|
||||||
return LockAndGetDeviceInfo(id, &DeviceInfo::product_type);
|
|
||||||
}
|
|
||||||
|
|
||||||
quint64 iLister::DeviceCapacity(const QString &id) {
|
|
||||||
return LockAndGetDeviceInfo(id, &DeviceInfo::total_bytes);
|
|
||||||
}
|
|
||||||
|
|
||||||
quint64 iLister::DeviceFreeSpace(const QString &id) {
|
|
||||||
return LockAndGetDeviceInfo(id, &DeviceInfo::free_bytes);
|
|
||||||
}
|
|
||||||
|
|
||||||
QVariantMap iLister::DeviceHardwareInfo(const QString &id) {
|
|
||||||
|
|
||||||
QVariantMap ret;
|
|
||||||
ret[tr("Color")] = LockAndGetDeviceInfo(id, &DeviceInfo::colour);
|
|
||||||
ret["IMEI"] = LockAndGetDeviceInfo(id, &DeviceInfo::imei);
|
|
||||||
ret[tr("Password Protected")] = LockAndGetDeviceInfo(id, &DeviceInfo::password_protected);
|
|
||||||
ret[tr("Timezone")] = LockAndGetDeviceInfo(id, &DeviceInfo::timezone);
|
|
||||||
ret[tr("WiFi MAC Address")] = LockAndGetDeviceInfo(id, &DeviceInfo::wifi_mac);
|
|
||||||
ret[tr("Bluetooth MAC Address")] = LockAndGetDeviceInfo(id, &DeviceInfo::bt_mac);
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
QString iLister::MakeFriendlyName(const QString &id) {
|
|
||||||
|
|
||||||
QString name = LockAndGetDeviceInfo(id, &DeviceInfo::name);
|
|
||||||
if (!name.isEmpty()) {
|
|
||||||
return name;
|
|
||||||
}
|
|
||||||
|
|
||||||
QString model_id = LockAndGetDeviceInfo(id, &DeviceInfo::product_type);
|
|
||||||
|
|
||||||
if (model_id.startsWith("iPhone")) {
|
|
||||||
QString version = model_id.right(3);
|
|
||||||
QChar major = version[0];
|
|
||||||
QChar minor = version[2];
|
|
||||||
if (major == '1' && minor == '1') {
|
|
||||||
return "iPhone";
|
|
||||||
}
|
|
||||||
if (major == '1' && minor == '2') {
|
|
||||||
return "iPhone 3G";
|
|
||||||
}
|
|
||||||
if (major == '2' && minor == '1') {
|
|
||||||
return "iPhone 3GS";
|
|
||||||
}
|
|
||||||
if (major == '3' && minor == '1') {
|
|
||||||
return "iPhone 4";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (model_id.startsWith("iPod")) {
|
|
||||||
return "iPod Touch";
|
|
||||||
}
|
|
||||||
else if (model_id.startsWith("iPad")) {
|
|
||||||
return "iPad";
|
|
||||||
}
|
|
||||||
return model_id;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
QList<QUrl> iLister::MakeDeviceUrls(const QString &id) {
|
|
||||||
|
|
||||||
QList<QUrl> ret;
|
|
||||||
|
|
||||||
QString uuid = LockAndGetDeviceInfo(id, &DeviceInfo::uuid);
|
|
||||||
if (uuid.isEmpty())
|
|
||||||
return ret;
|
|
||||||
|
|
||||||
ret << QUrl("afc://" + uuid + "/");
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
iLister::DeviceInfo iLister::ReadDeviceInfo(const QString uuid) {
|
|
||||||
|
|
||||||
DeviceInfo ret;
|
|
||||||
|
|
||||||
iMobileDeviceConnection conn(uuid);
|
|
||||||
if (!conn.is_valid()) return ret;
|
|
||||||
|
|
||||||
ret.valid = conn.is_valid();
|
|
||||||
ret.uuid = uuid;
|
|
||||||
ret.product_type = conn.GetProperty("ProductType").toString();
|
|
||||||
ret.free_bytes = conn.GetProperty("AmountDataAvailable", "com.apple.disk_usage").toULongLong();
|
|
||||||
ret.total_bytes = conn.GetProperty("TotalDataCapacity", "com.apple.disk_usage").toULongLong();
|
|
||||||
ret.name = conn.GetProperty("DeviceName").toString();
|
|
||||||
|
|
||||||
ret.colour = conn.GetProperty("DeviceColor").toString();
|
|
||||||
ret.imei = conn.GetProperty("InternationalMobileEquipmentIdentity").toString();
|
|
||||||
ret.hardware = conn.GetProperty("HardwareModel").toString();
|
|
||||||
ret.password_protected = conn.GetProperty("PasswordProtected").toBool();
|
|
||||||
ret.os_version = conn.GetProperty("ProductVersion").toString();
|
|
||||||
ret.timezone = conn.GetProperty("TimeZone").toString();
|
|
||||||
ret.wifi_mac = conn.GetProperty("WiFiAddress").toString();
|
|
||||||
ret.bt_mac = conn.GetProperty("BluetoothAddress").toString();
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void iLister::UpdateDeviceFreeSpace(const QString &id) {
|
|
||||||
|
|
||||||
{
|
|
||||||
QMutexLocker l(&mutex_);
|
|
||||||
if (!devices_.contains(id))
|
|
||||||
return;
|
|
||||||
|
|
||||||
DeviceInfo &info = devices_[id];
|
|
||||||
iMobileDeviceConnection conn(info.uuid);
|
|
||||||
|
|
||||||
info.free_bytes = conn.GetProperty("AmountDataAvailable", "com.apple.disk_usage").toULongLong();
|
|
||||||
}
|
|
||||||
|
|
||||||
emit DeviceChanged(id);
|
|
||||||
|
|
||||||
}
|
|
@ -1,110 +0,0 @@
|
|||||||
/*
|
|
||||||
* Strawberry Music Player
|
|
||||||
* This file was part of Clementine.
|
|
||||||
* Copyright 2010, David Sansome <me@davidsansome.com>
|
|
||||||
*
|
|
||||||
* Strawberry is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* Strawberry is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with Strawberry. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef ILISTER_H
|
|
||||||
#define ILISTER_H
|
|
||||||
|
|
||||||
#include "config.h"
|
|
||||||
|
|
||||||
#include <libimobiledevice/libimobiledevice.h>
|
|
||||||
|
|
||||||
#include <QtGlobal>
|
|
||||||
#include <QObject>
|
|
||||||
#include <QMutex>
|
|
||||||
#include <QMap>
|
|
||||||
#include <QList>
|
|
||||||
#include <QString>
|
|
||||||
#include <QStringList>
|
|
||||||
|
|
||||||
#include "devicelister.h"
|
|
||||||
|
|
||||||
class iLister : public DeviceLister {
|
|
||||||
Q_OBJECT
|
|
||||||
|
|
||||||
public:
|
|
||||||
explicit iLister();
|
|
||||||
~iLister() override;
|
|
||||||
|
|
||||||
int priority() const override { return 120; }
|
|
||||||
|
|
||||||
QStringList DeviceUniqueIDs() override;
|
|
||||||
QVariantList DeviceIcons(const QString &id) override;
|
|
||||||
QString DeviceManufacturer(const QString &id) override;
|
|
||||||
QString DeviceModel(const QString &id) override;
|
|
||||||
quint64 DeviceCapacity(const QString &id) override;
|
|
||||||
quint64 DeviceFreeSpace(const QString &id) override;
|
|
||||||
QVariantMap DeviceHardwareInfo(const QString &id) override;
|
|
||||||
QString MakeFriendlyName(const QString &id) override;
|
|
||||||
QList<QUrl> MakeDeviceUrls(const QString &id) override;
|
|
||||||
|
|
||||||
public slots:
|
|
||||||
void UpdateDeviceFreeSpace(const QString &id) override;
|
|
||||||
|
|
||||||
private:
|
|
||||||
struct DeviceInfo {
|
|
||||||
DeviceInfo() : valid(false), free_bytes(0), total_bytes(0), password_protected(false) {}
|
|
||||||
|
|
||||||
bool valid;
|
|
||||||
|
|
||||||
QString uuid;
|
|
||||||
QString product_type;
|
|
||||||
quint64 free_bytes;
|
|
||||||
quint64 total_bytes;
|
|
||||||
QString name; // Name given to the iDevice by the user.
|
|
||||||
|
|
||||||
// Extra information.
|
|
||||||
QString colour;
|
|
||||||
QString imei;
|
|
||||||
QString hardware;
|
|
||||||
bool password_protected;
|
|
||||||
QString os_version;
|
|
||||||
QString timezone;
|
|
||||||
QString wifi_mac;
|
|
||||||
QString bt_mac;
|
|
||||||
};
|
|
||||||
|
|
||||||
bool Init() override;
|
|
||||||
|
|
||||||
static void EventCallback(const idevice_event_t *event, void *context);
|
|
||||||
|
|
||||||
void DeviceAddedCallback(const QString uuid);
|
|
||||||
void DeviceRemovedCallback(const QString uuid);
|
|
||||||
|
|
||||||
DeviceInfo ReadDeviceInfo(const QString uuid);
|
|
||||||
static QString UniqueId(const QString uuid);
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
T LockAndGetDeviceInfo(const QString &id, T DeviceInfo::*field);
|
|
||||||
|
|
||||||
private:
|
|
||||||
QMutex mutex_;
|
|
||||||
QMap<QString, DeviceInfo> devices_;
|
|
||||||
};
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
T iLister::LockAndGetDeviceInfo(const QString &id, T DeviceInfo::*field) {
|
|
||||||
QMutexLocker l(&mutex_);
|
|
||||||
if (!devices_.contains(id))
|
|
||||||
return T();
|
|
||||||
|
|
||||||
return devices_[id].*field;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
@ -1,277 +0,0 @@
|
|||||||
/*
|
|
||||||
* Strawberry Music Player
|
|
||||||
* This file was part of Clementine.
|
|
||||||
* Copyright 2010, David Sansome <me@davidsansome.com>
|
|
||||||
*
|
|
||||||
* Strawberry is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* Strawberry is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with Strawberry. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "config.h"
|
|
||||||
|
|
||||||
#include <plist/plist.h>
|
|
||||||
|
|
||||||
#include <libimobiledevice/afc.h>
|
|
||||||
#include <libimobiledevice/libimobiledevice.h>
|
|
||||||
#include <libimobiledevice/lockdown.h>
|
|
||||||
|
|
||||||
#include <QCoreApplication>
|
|
||||||
#include <QDir>
|
|
||||||
#include <QByteArray>
|
|
||||||
#include <QString>
|
|
||||||
#include <QStringList>
|
|
||||||
#include <QUrl>
|
|
||||||
#include <QtDebug>
|
|
||||||
#if QT_VERSION >= QT_VERSION_CHECK(5, 10, 0)
|
|
||||||
# include <QRandomGenerator>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "core/logging.h"
|
|
||||||
#include "imobiledeviceconnection.h"
|
|
||||||
|
|
||||||
iMobileDeviceConnection::iMobileDeviceConnection(const QString uuid) : device_(nullptr), afc_(nullptr) {
|
|
||||||
|
|
||||||
idevice_error_t err = idevice_new(&device_, uuid.toUtf8().constData());
|
|
||||||
if (err != IDEVICE_E_SUCCESS) {
|
|
||||||
qLog(Warning) << "idevice_new error:" << err;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
QByteArray label_ascii = QCoreApplication::applicationName().toUtf8();
|
|
||||||
const char *label = label_ascii.constData();
|
|
||||||
|
|
||||||
lockdownd_client_t lockdown;
|
|
||||||
lockdownd_error_t lockdown_err = lockdownd_client_new_with_handshake(device_, &lockdown, label);
|
|
||||||
if (lockdown_err != LOCKDOWN_E_SUCCESS) {
|
|
||||||
qLog(Warning) << "lockdownd_client_new_with_handshake error:" << lockdown_err;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
lockdownd_service_descriptor_t lockdown_service_desc;
|
|
||||||
lockdown_err = lockdownd_start_service(lockdown, "com.apple.afc", &lockdown_service_desc);
|
|
||||||
if (lockdown_err != LOCKDOWN_E_SUCCESS) {
|
|
||||||
qLog(Warning) << "lockdownd_start_service error:" << lockdown_err;
|
|
||||||
lockdownd_client_free(lockdown);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
afc_error_t afc_err = afc_client_new(device_, lockdown_service_desc, &afc_);
|
|
||||||
if (afc_err != AFC_E_SUCCESS) {
|
|
||||||
qLog(Warning) << "afc_client_new error:" << afc_err;
|
|
||||||
lockdownd_client_free(lockdown);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
lockdownd_client_free(lockdown);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
iMobileDeviceConnection::~iMobileDeviceConnection() {
|
|
||||||
|
|
||||||
if (afc_) {
|
|
||||||
afc_client_free(afc_);
|
|
||||||
}
|
|
||||||
if (device_) {
|
|
||||||
idevice_free(device_);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T, typename F>
|
|
||||||
T GetPListValue(plist_t node, F f) {
|
|
||||||
T ret;
|
|
||||||
f(node, &ret);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
QVariant iMobileDeviceConnection::GetProperty(const QString &property, const QString &domain) {
|
|
||||||
|
|
||||||
if (!device_) return QVariant();
|
|
||||||
|
|
||||||
lockdownd_client_t lockdown;
|
|
||||||
QByteArray label_ascii = QCoreApplication::applicationName().toUtf8();
|
|
||||||
const char *label = label_ascii.constData();
|
|
||||||
|
|
||||||
lockdownd_error_t lockdown_err = lockdownd_client_new_with_handshake(device_, &lockdown, label);
|
|
||||||
if (lockdown_err != LOCKDOWN_E_SUCCESS) {
|
|
||||||
qLog(Warning) << "lockdown error:" << lockdown_err;
|
|
||||||
return QVariant();
|
|
||||||
}
|
|
||||||
|
|
||||||
plist_t node = nullptr;
|
|
||||||
QByteArray domain_ascii = domain.toUtf8();
|
|
||||||
const char *d = domain_ascii.isEmpty() ? nullptr : domain_ascii.constData();
|
|
||||||
//const char *d = domain.isEmpty() ? nullptr : "com.apple.disk_usage";
|
|
||||||
lockdownd_get_value(lockdown, d, property.toUtf8().constData(), &node);
|
|
||||||
lockdownd_client_free(lockdown);
|
|
||||||
|
|
||||||
if (!node) {
|
|
||||||
qLog(Warning) << "get_value failed" << property << domain;
|
|
||||||
return QVariant();
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (plist_get_node_type(node)) {
|
|
||||||
case PLIST_BOOLEAN:
|
|
||||||
return bool(GetPListValue<quint8>(node, plist_get_bool_val));
|
|
||||||
|
|
||||||
case PLIST_UINT:
|
|
||||||
return QVariant::fromValue(GetPListValue<uint64_t>(node, plist_get_uint_val));
|
|
||||||
|
|
||||||
case PLIST_STRING: {
|
|
||||||
char *data = GetPListValue<char*>(node, plist_get_string_val);
|
|
||||||
QString ret = QString::fromUtf8(data);
|
|
||||||
free(data);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
default:
|
|
||||||
qLog(Warning) << "Unhandled PList type";
|
|
||||||
return QVariant();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
QStringList iMobileDeviceConnection::ReadDirectory(const QString &path, QDir::Filters filters) {
|
|
||||||
|
|
||||||
if (!afc_) return QStringList();
|
|
||||||
|
|
||||||
char **list = nullptr;
|
|
||||||
afc_error_t err = afc_read_directory(afc_, path.toUtf8().constData(), &list);
|
|
||||||
if (err != AFC_E_SUCCESS || !list) {
|
|
||||||
return QStringList();
|
|
||||||
}
|
|
||||||
|
|
||||||
QStringList ret;
|
|
||||||
for (char **p = list ; *p != nullptr ; ++p) {
|
|
||||||
QString filename = QString::fromUtf8(*p);
|
|
||||||
free(*p);
|
|
||||||
|
|
||||||
if (filters == QDir::NoFilter)
|
|
||||||
ret << filename;
|
|
||||||
else {
|
|
||||||
if (filters & QDir::NoDotAndDotDot && (filename == "." || filename == ".."))
|
|
||||||
continue;
|
|
||||||
if (!(filters & QDir::Hidden) && filename.startsWith("."))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
QString filetype = GetFileInfo(path + "/" + filename, "st_ifmt");
|
|
||||||
if ((filetype == "S_IFREG" && (filters & QDir::Files)) || (filetype == "S_IFDIR" && (filters & QDir::Dirs)) || (filetype == "S_IFLNK" && (!(filters & QDir::NoSymLinks))))
|
|
||||||
ret << filename;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
free(list);
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
bool iMobileDeviceConnection::MkDir(const QString &path) {
|
|
||||||
|
|
||||||
if (!afc_) return false;
|
|
||||||
|
|
||||||
afc_error_t err = afc_make_directory(afc_, path.toUtf8().constData());
|
|
||||||
return err == AFC_E_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
QString iMobileDeviceConnection::GetFileInfo(const QString &path, const QString &key) {
|
|
||||||
|
|
||||||
if (!afc_) return QString();
|
|
||||||
|
|
||||||
QString ret;
|
|
||||||
char **infolist = nullptr;
|
|
||||||
afc_error_t err = afc_get_file_info(afc_, path.toUtf8().constData(), &infolist);
|
|
||||||
if (err != AFC_E_SUCCESS || !infolist) {
|
|
||||||
qLog(Debug) << "afc_get_file_info error:" << path << err;
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
QString last_key;
|
|
||||||
for (char **p = infolist ; *p != nullptr ; ++p) {
|
|
||||||
if (last_key.isNull()) {
|
|
||||||
last_key = QString::fromUtf8(*p);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
if (last_key == key)
|
|
||||||
ret = QString::fromUtf8(*p);
|
|
||||||
last_key = QString();
|
|
||||||
}
|
|
||||||
free(*p);
|
|
||||||
}
|
|
||||||
free(infolist);
|
|
||||||
return ret;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
bool iMobileDeviceConnection::Exists(const QString &path) {
|
|
||||||
return !GetFileInfo(path, "st_ifmt").isNull();
|
|
||||||
}
|
|
||||||
|
|
||||||
QString iMobileDeviceConnection::GetUnusedFilename(Itdb_iTunesDB *itdb, const Song &metadata) {
|
|
||||||
|
|
||||||
Q_UNUSED(itdb);
|
|
||||||
|
|
||||||
// This function does the same as itdb_cp_get_dest_filename, except it accesses the device's filesystem through imobiledevice.
|
|
||||||
|
|
||||||
// Get the total number of F.. directories
|
|
||||||
int total_musicdirs = 0;
|
|
||||||
for ( ; ; ++total_musicdirs) {
|
|
||||||
QString dir = QString::asprintf("/iTunes_Control/Music/F%02d", total_musicdirs);
|
|
||||||
|
|
||||||
if (!Exists(dir))
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (total_musicdirs <= 0) {
|
|
||||||
qLog(Warning) << "No 'F..'' directories found on iPod";
|
|
||||||
return QString();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Pick one at random
|
|
||||||
#if QT_VERSION >= QT_VERSION_CHECK(5, 10, 0)
|
|
||||||
const int dir_num = QRandomGenerator::global()->bounded(total_musicdirs);
|
|
||||||
#else
|
|
||||||
const int dir_num = qrand() % total_musicdirs;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
QString dir = QString::asprintf("/iTunes_Control/Music/F%02d", dir_num);
|
|
||||||
|
|
||||||
if (!Exists(dir)) {
|
|
||||||
qLog(Warning) << "Music directory doesn't exist:" << dir;
|
|
||||||
return QString();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Use the same file extension as the original file, default to mp3.
|
|
||||||
QString extension = metadata.url().path().section('.', -1, -1).toLower();
|
|
||||||
if (extension.isEmpty())
|
|
||||||
extension = "mp3";
|
|
||||||
|
|
||||||
// Loop until we find an unused filename.
|
|
||||||
// Use the same naming convention as libgpod, which is "libgpod" + 6-digit random number
|
|
||||||
static const int kRandMax = 999999;
|
|
||||||
QString filename;
|
|
||||||
forever {
|
|
||||||
#if QT_VERSION >= QT_VERSION_CHECK(5, 10, 0)
|
|
||||||
filename = QString::asprintf("libgpod%06d", QRandomGenerator::global()->bounded(kRandMax));
|
|
||||||
#else
|
|
||||||
filename = QString::asprintf("libgpod%06d", qrand() % kRandMax);
|
|
||||||
#endif
|
|
||||||
filename += "." + extension;
|
|
||||||
|
|
||||||
if (!Exists(dir + "/" + filename))
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return dir + "/" + filename;
|
|
||||||
|
|
||||||
}
|
|
@ -1,64 +0,0 @@
|
|||||||
/*
|
|
||||||
* Strawberry Music Player
|
|
||||||
* This file was part of Clementine.
|
|
||||||
* Copyright 2010, David Sansome <me@davidsansome.com>
|
|
||||||
*
|
|
||||||
* Strawberry is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* Strawberry is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with Strawberry. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef IMOBILEDEVICECONNECTION_H
|
|
||||||
#define IMOBILEDEVICECONNECTION_H
|
|
||||||
|
|
||||||
#include "config.h"
|
|
||||||
|
|
||||||
#include <libimobiledevice/afc.h>
|
|
||||||
#include <libimobiledevice/libimobiledevice.h>
|
|
||||||
#include <libimobiledevice/lockdown.h>
|
|
||||||
|
|
||||||
#include <gpod/itdb.h>
|
|
||||||
|
|
||||||
#include <QDir>
|
|
||||||
#include <QVariant>
|
|
||||||
#include <QString>
|
|
||||||
#include <QStringList>
|
|
||||||
|
|
||||||
#include "core/song.h"
|
|
||||||
|
|
||||||
class iMobileDeviceConnection {
|
|
||||||
public:
|
|
||||||
explicit iMobileDeviceConnection(const QString uuid);
|
|
||||||
~iMobileDeviceConnection();
|
|
||||||
|
|
||||||
afc_client_t afc() { return afc_; }
|
|
||||||
|
|
||||||
QVariant GetProperty(const QString &property, const QString &domain = QString());
|
|
||||||
QStringList ReadDirectory(const QString &path, QDir::Filters filters = QDir::NoFilter);
|
|
||||||
bool MkDir(const QString &path);
|
|
||||||
|
|
||||||
QString GetFileInfo(const QString &path, const QString &key);
|
|
||||||
bool Exists(const QString &path);
|
|
||||||
|
|
||||||
QString GetUnusedFilename(Itdb_iTunesDB *itdb, const Song &metadata);
|
|
||||||
|
|
||||||
bool is_valid() { return device_ && afc_; }
|
|
||||||
|
|
||||||
private:
|
|
||||||
Q_DISABLE_COPY(iMobileDeviceConnection)
|
|
||||||
|
|
||||||
idevice_t device_;
|
|
||||||
afc_client_t afc_;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif // IMOBILEDEVICECONNECTION_H
|
|
Loading…
x
Reference in New Issue
Block a user