parent
d3664dcf78
commit
171575256c
|
@ -95,9 +95,7 @@ commands:
|
|||
libqt5-linguist-devel
|
||||
libcdio-devel
|
||||
libgpod-devel
|
||||
libplist-devel
|
||||
libmtp-devel
|
||||
libusbmuxd-devel
|
||||
libchromaprint-devel
|
||||
desktop-file-utils
|
||||
update-desktop-files
|
||||
|
@ -149,8 +147,6 @@ commands:
|
|||
taglib-devel
|
||||
libcdio-devel
|
||||
libgpod-devel
|
||||
libplist-devel
|
||||
libusbmuxd-devel
|
||||
libmtp-devel
|
||||
libchromaprint-devel
|
||||
fftw-devel
|
||||
|
@ -213,8 +209,6 @@ commands:
|
|||
libchromaprint-devel
|
||||
libcdio-devel
|
||||
libgpod-devel
|
||||
libplist-devel
|
||||
libusbmuxd-devel
|
||||
libmtp-devel
|
||||
libjpeg-devel
|
||||
cairo-devel
|
||||
|
@ -280,8 +274,6 @@ commands:
|
|||
lib64gstreamer-plugins-base1.0-devel
|
||||
lib64cdio-devel
|
||||
lib64gpod-devel
|
||||
lib64plist-devel
|
||||
lib64usbmuxd-devel
|
||||
lib64mtp-devel
|
||||
lib64raw1394-devel
|
||||
lib64chromaprint-devel
|
||||
|
@ -335,9 +327,6 @@ commands:
|
|||
libcdio-dev
|
||||
libmtp-dev
|
||||
libgpod-dev
|
||||
libimobiledevice-dev
|
||||
libplist-dev
|
||||
libusbmuxd-dev
|
||||
|
||||
|
||||
install_ubuntu_dependencies:
|
||||
|
@ -389,9 +378,6 @@ commands:
|
|||
libcdio-dev
|
||||
libmtp-dev
|
||||
libgpod-dev
|
||||
libimobiledevice-dev
|
||||
libplist-dev
|
||||
libusbmuxd-dev
|
||||
|
||||
|
||||
jobs:
|
||||
|
|
|
@ -53,9 +53,7 @@ jobs:
|
|||
libqt5-linguist-devel
|
||||
libcdio-devel
|
||||
libgpod-devel
|
||||
libplist-devel
|
||||
libmtp-devel
|
||||
libusbmuxd-devel
|
||||
libchromaprint-devel
|
||||
desktop-file-utils
|
||||
update-desktop-files
|
||||
|
@ -123,9 +121,7 @@ jobs:
|
|||
libqt5-linguist-devel
|
||||
libcdio-devel
|
||||
libgpod-devel
|
||||
libplist-devel
|
||||
libmtp-devel
|
||||
libusbmuxd-devel
|
||||
libchromaprint-devel
|
||||
desktop-file-utils
|
||||
update-desktop-files
|
||||
|
@ -201,9 +197,7 @@ jobs:
|
|||
libqt5-linguist-devel
|
||||
libcdio-devel
|
||||
libgpod-devel
|
||||
libplist-devel
|
||||
libmtp-devel
|
||||
libusbmuxd-devel
|
||||
libchromaprint-devel
|
||||
desktop-file-utils
|
||||
update-desktop-files
|
||||
|
@ -281,9 +275,7 @@ jobs:
|
|||
libqt5-linguist-devel
|
||||
libcdio-devel
|
||||
libgpod-devel
|
||||
libplist-devel
|
||||
libmtp-devel
|
||||
libusbmuxd-devel
|
||||
libchromaprint-devel
|
||||
desktop-file-utils
|
||||
update-desktop-files
|
||||
|
@ -363,9 +355,7 @@ jobs:
|
|||
qt6-qt5compat-devel
|
||||
libcdio-devel
|
||||
libgpod-devel
|
||||
libplist-devel
|
||||
libmtp-devel
|
||||
libusbmuxd-devel
|
||||
libchromaprint-devel
|
||||
desktop-file-utils
|
||||
update-desktop-files
|
||||
|
@ -434,8 +424,6 @@ jobs:
|
|||
taglib-devel
|
||||
libcdio-devel
|
||||
libgpod-devel
|
||||
libplist-devel
|
||||
libusbmuxd-devel
|
||||
libmtp-devel
|
||||
libchromaprint-devel
|
||||
fftw-devel
|
||||
|
@ -518,8 +506,6 @@ jobs:
|
|||
libchromaprint-devel
|
||||
libcdio-devel
|
||||
libgpod-devel
|
||||
libplist-devel
|
||||
libusbmuxd-devel
|
||||
libmtp-devel
|
||||
libjpeg-devel
|
||||
cairo-devel
|
||||
|
@ -607,8 +593,6 @@ jobs:
|
|||
lib64gstreamer-plugins-base1.0-devel
|
||||
lib64cdio-devel
|
||||
lib64gpod-devel
|
||||
lib64plist-devel
|
||||
lib64usbmuxd-devel
|
||||
lib64mtp-devel
|
||||
lib64raw1394-devel
|
||||
lib64chromaprint-devel
|
||||
|
@ -684,9 +668,6 @@ jobs:
|
|||
libcdio-dev
|
||||
libmtp-dev
|
||||
libgpod-dev
|
||||
libimobiledevice-dev
|
||||
libplist-dev
|
||||
libusbmuxd-dev
|
||||
- name: Create Build Environment
|
||||
shell: bash
|
||||
run: cmake -E make_directory build
|
||||
|
@ -743,9 +724,6 @@ jobs:
|
|||
libcdio-dev
|
||||
libmtp-dev
|
||||
libgpod-dev
|
||||
libimobiledevice-dev
|
||||
libplist-dev
|
||||
libusbmuxd-dev
|
||||
- name: Create Build Environment
|
||||
shell: bash
|
||||
run: cmake -E make_directory build
|
||||
|
@ -807,9 +785,6 @@ jobs:
|
|||
libcdio-dev
|
||||
libmtp-dev
|
||||
libgpod-dev
|
||||
libimobiledevice-dev
|
||||
libplist-dev
|
||||
libusbmuxd-dev
|
||||
- name: Create Build Environment
|
||||
shell: bash
|
||||
run: cmake -E make_directory build
|
||||
|
@ -871,9 +846,6 @@ jobs:
|
|||
libcdio-dev
|
||||
libmtp-dev
|
||||
libgpod-dev
|
||||
libimobiledevice-dev
|
||||
libplist-dev
|
||||
libusbmuxd-dev
|
||||
- name: Create Build Environment
|
||||
shell: bash
|
||||
run: cmake -E make_directory build
|
||||
|
@ -935,9 +907,6 @@ jobs:
|
|||
libcdio-dev
|
||||
libmtp-dev
|
||||
libgpod-dev
|
||||
libimobiledevice-dev
|
||||
libplist-dev
|
||||
libusbmuxd-dev
|
||||
- name: Create Build Environment
|
||||
shell: bash
|
||||
run: cmake -E make_directory build
|
||||
|
@ -980,8 +949,6 @@ jobs:
|
|||
gst-libav
|
||||
libcdio
|
||||
libmtp
|
||||
libimobiledevice
|
||||
libplist
|
||||
create-dmg
|
||||
taglib
|
||||
|
||||
|
@ -1045,7 +1012,6 @@ jobs:
|
|||
-DENABLE_WIN32_CONSOLE=OFF
|
||||
-DENABLE_DBUS=OFF
|
||||
-DENABLE_LIBGPOD=OFF
|
||||
-DENABLE_IMOBILEDEVICE=OFF
|
||||
-DENABLE_LIBMTP=OFF
|
||||
-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 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 libcdio libmtp libimobiledevice libplist;
|
||||
brew install libcdio libmtp;
|
||||
brew install create-dmg;
|
||||
brew cask install sparkle;
|
||||
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(LIBGPOD libgpod-1.0>=0.7.92)
|
||||
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(FFTW3)
|
||||
|
||||
|
@ -344,13 +341,6 @@ optional_component(LIBMTP ON "Devices: MTP support"
|
|||
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"
|
||||
DEPENDS "macOS" APPLE
|
||||
DEPENDS "Sparkle" SPARKLE
|
||||
|
|
|
@ -36,6 +36,7 @@ Unreleased:
|
|||
|
||||
Removed features:
|
||||
* Removed Xine engine support.
|
||||
* Removed broken imobiledevice (iPhone) support.
|
||||
|
||||
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
|
||||
* Audio analyzer
|
||||
* 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/)
|
||||
* Subsonic and Tidal streaming support
|
||||
|
||||
|
@ -78,7 +78,6 @@ Optional dependencies:
|
|||
* Audio CD: [libcdio](https://www.gnu.org/software/libcdio/)
|
||||
* MTP devices: [libmtp](http://libmtp.sourceforge.net/)
|
||||
* 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/)
|
||||
|
||||
Either GStreamer or VLC engine is required, but only GStreamer is fully implemented so far.
|
||||
|
|
|
@ -24,10 +24,7 @@ Build-Depends: debhelper (>= 11),
|
|||
libgstreamer-plugins-base1.0-dev,
|
||||
libcdio-dev,
|
||||
libgpod-dev,
|
||||
libimobiledevice-dev,
|
||||
libmtp-dev,
|
||||
libplist-dev,
|
||||
libusbmuxd-dev,
|
||||
libchromaprint-dev,
|
||||
libfftw3-dev
|
||||
Standards-Version: 4.2.1
|
||||
|
|
|
@ -28,9 +28,6 @@ depends=(
|
|||
libgpod
|
||||
libcdio
|
||||
libmtp
|
||||
libusbmuxd
|
||||
libplist
|
||||
libimobiledevice
|
||||
fftw
|
||||
)
|
||||
optdepends=(
|
||||
|
|
|
@ -106,7 +106,7 @@ Features:
|
|||
- Support for multiple backends
|
||||
- Audio analyzer
|
||||
- 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
|
||||
- Streaming support for Subsonic
|
||||
|
||||
|
|
|
@ -101,11 +101,8 @@ parts:
|
|||
- libgstreamer-plugins-base1.0-dev
|
||||
- libvlc-dev
|
||||
- libcdio-dev
|
||||
- libgpod-dev
|
||||
- libimobiledevice-dev
|
||||
- libgpod-devdev
|
||||
- libmtp-dev
|
||||
- libplist-dev
|
||||
- libusbmuxd-dev
|
||||
- libchromaprint-dev
|
||||
- libfftw3-dev
|
||||
|
||||
|
@ -131,9 +128,6 @@ parts:
|
|||
- libcdio17
|
||||
- libgpod4
|
||||
- libmtp9
|
||||
- libimobiledevice6
|
||||
- libplist3
|
||||
- libusbmuxd4
|
||||
- libvlc5
|
||||
- libvlccore9
|
||||
- libtag1v5
|
||||
|
|
|
@ -737,21 +737,6 @@ optional_source(HAVE_GIO
|
|||
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
|
||||
optional_source(HAVE_LIBMTP
|
||||
SOURCES
|
||||
|
@ -1035,14 +1020,6 @@ if(HAVE_LIBMTP)
|
|||
link_directories(${LIBMTP_LIBRARY_DIRS})
|
||||
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
|
||||
${SOURCES}
|
||||
${MOC}
|
||||
|
@ -1163,19 +1140,6 @@ if(HAVE_LIBMTP)
|
|||
target_link_libraries(strawberry_lib PRIVATE ${LIBMTP_LIBRARIES})
|
||||
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)
|
||||
target_link_libraries(strawberry_lib PRIVATE
|
||||
|
|
|
@ -31,7 +31,6 @@
|
|||
#cmakedefine HAVE_X11
|
||||
#cmakedefine HAVE_UDISKS2
|
||||
#cmakedefine HAVE_ALSA
|
||||
#cmakedefine HAVE_IMOBILEDEVICE
|
||||
#cmakedefine HAVE_AUDIOCD
|
||||
#cmakedefine HAVE_LIBGPOD
|
||||
#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
|
||||
# include "mtpdevice.h"
|
||||
#endif
|
||||
#ifdef HAVE_IMOBILEDEVICE
|
||||
# include "afcdevice.h"
|
||||
# include "ilister.h"
|
||||
#endif
|
||||
#if defined(Q_OS_MACOS) and defined(HAVE_LIBMTP)
|
||||
# include "macosdevicelister.h"
|
||||
#endif
|
||||
|
@ -125,9 +121,6 @@ DeviceManager::DeviceManager(Application *app, QObject *parent)
|
|||
#if defined(Q_OS_MACOS) and defined(HAVE_LIBMTP)
|
||||
AddLister(new MacOsDeviceLister);
|
||||
#endif
|
||||
#ifdef HAVE_IMOBILEDEVICE
|
||||
AddLister(new iLister);
|
||||
#endif
|
||||
|
||||
#if defined(HAVE_AUDIOCD) && defined(HAVE_GSTREAMER)
|
||||
AddDeviceClass<CddaDevice>();
|
||||
|
@ -143,10 +136,6 @@ DeviceManager::DeviceManager(Application *app, QObject *parent)
|
|||
AddDeviceClass<MtpDevice>();
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_IMOBILEDEVICE
|
||||
AddDeviceClass<AfcDevice>();
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
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…
Reference in New Issue