Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 474f4f7714 | |||
| 846f743a5b |
@@ -1,5 +1,5 @@
|
|||||||
cmake_minimum_required(VERSION 3.25)
|
cmake_minimum_required(VERSION 3.25)
|
||||||
project(OmniMTP VERSION 1.0.1
|
project(OmniMTP VERSION 1.0.2
|
||||||
DESCRIPTION "Nintendo Switch MTP Client for macOS"
|
DESCRIPTION "Nintendo Switch MTP Client for macOS"
|
||||||
LANGUAGES CXX OBJCXX OBJC C
|
LANGUAGES CXX OBJCXX OBJC C
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -83,6 +83,8 @@ private:
|
|||||||
void start_download(uint32_t handle, uint32_t storage_id,
|
void start_download(uint32_t handle, uint32_t storage_id,
|
||||||
const std::string& filename, uint64_t size);
|
const std::string& filename, uint64_t size);
|
||||||
void start_upload(const fs::path& src_path, uint64_t file_size);
|
void start_upload(const fs::path& src_path, uint64_t file_size);
|
||||||
|
// Recursively create a remote folder and enqueue files under parent_handle.
|
||||||
|
void upload_local_tree(const fs::path& dir, uint32_t parent_handle, uint32_t storage_id);
|
||||||
// Recursively download an MTP association (folder) into dest (must hold device_mtx_).
|
// Recursively download an MTP association (folder) into dest (must hold device_mtx_).
|
||||||
void download_remote_tree(uint32_t handle, uint32_t storage_id, const fs::path& dest);
|
void download_remote_tree(uint32_t handle, uint32_t storage_id, const fs::path& dest);
|
||||||
|
|
||||||
|
|||||||
@@ -275,6 +275,49 @@ void App::start_upload(const fs::path& src, uint64_t sz) {
|
|||||||
src.filename().string(), sz);
|
src.filename().string(), sz);
|
||||||
set_status("status.uploading", {src.filename().string()});
|
set_status("status.uploading", {src.filename().string()});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void App::upload_local_tree(const fs::path& dir, uint32_t parent_handle, uint32_t storage_id) {
|
||||||
|
if (!engine_ || !ops_) return;
|
||||||
|
const std::string name = dir.filename().string();
|
||||||
|
if (name.empty() || name == "." || name == "..") return;
|
||||||
|
|
||||||
|
uint32_t dir_handle = 0;
|
||||||
|
try {
|
||||||
|
std::lock_guard lock(device_mtx_);
|
||||||
|
if (!ops_) return;
|
||||||
|
dir_handle = ops_->create_directory(storage_id, parent_handle, name);
|
||||||
|
} catch (const std::exception& e) {
|
||||||
|
set_status("status.listing_error", {e.what()});
|
||||||
|
return;
|
||||||
|
} catch (...) {
|
||||||
|
set_status("status.listing_error", {"Failed to create folder: " + name});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (dir_handle == 0) {
|
||||||
|
set_status("status.listing_error", {"Failed to create folder: " + name});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::error_code ec;
|
||||||
|
for (fs::directory_iterator it(dir, ec), end; !ec && it != end; it.increment(ec)) {
|
||||||
|
const auto& entry = *it;
|
||||||
|
const std::string child_name = entry.path().filename().string();
|
||||||
|
if (child_name.empty() || child_name == "." || child_name == "..") continue;
|
||||||
|
// Skip macOS clutter that Switch MTP installers don't need.
|
||||||
|
if (child_name == ".DS_Store" || child_name.rfind("._", 0) == 0) continue;
|
||||||
|
|
||||||
|
std::error_code st_ec;
|
||||||
|
if (entry.is_directory(st_ec)) {
|
||||||
|
upload_local_tree(entry.path(), dir_handle, storage_id);
|
||||||
|
} else if (entry.is_regular_file(st_ec)) {
|
||||||
|
auto sz = entry.file_size(st_ec);
|
||||||
|
if (st_ec) continue;
|
||||||
|
engine_->enqueue_upload(entry.path().string(), dir_handle, storage_id,
|
||||||
|
child_name, sz);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void App::set_status(const std::string& key, std::vector<std::string> args, float dur) {
|
void App::set_status(const std::string& key, std::vector<std::string> args, float dur) {
|
||||||
status_key_ = key;
|
status_key_ = key;
|
||||||
status_args_ = std::move(args);
|
status_args_ = std::move(args);
|
||||||
@@ -381,13 +424,8 @@ void App::process_finder_drops() {
|
|||||||
drops.swap(finder_drops_);
|
drops.swap(finder_drops_);
|
||||||
}
|
}
|
||||||
for (auto& dropped : drops) {
|
for (auto& dropped : drops) {
|
||||||
fs::path p(dropped);
|
if (connected_.load())
|
||||||
std::error_code ec;
|
do_upload(dropped);
|
||||||
if (fs::is_directory(p, ec)) continue;
|
|
||||||
if (!ec && connected_.load()) {
|
|
||||||
auto sz = fs::file_size(p, ec);
|
|
||||||
if (!ec) start_upload(p, sz);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -419,8 +457,17 @@ void App::set_active_storage(uint32_t id) {
|
|||||||
}
|
}
|
||||||
void App::request_refresh_remote() { refresh_remote(); }
|
void App::request_refresh_remote() { refresh_remote(); }
|
||||||
void App::do_upload(const std::string& src) {
|
void App::do_upload(const std::string& src) {
|
||||||
|
if (!connected_.load() || !engine_ || remote_nav_stack_.empty()) return;
|
||||||
fs::path p(src);
|
fs::path p(src);
|
||||||
std::error_code ec;
|
std::error_code ec;
|
||||||
|
if (fs::is_directory(p, ec)) {
|
||||||
|
const auto& top = remote_nav_stack_.back();
|
||||||
|
set_status("status.uploading", {p.filename().string()});
|
||||||
|
upload_local_tree(p, top.handle, top.storage_id);
|
||||||
|
remote_needs_refresh_ = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (ec) return;
|
||||||
auto sz = fs::file_size(p, ec);
|
auto sz = fs::file_size(p, ec);
|
||||||
if (!ec) start_upload(p, sz);
|
if (!ec) start_upload(p, sz);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -410,7 +410,7 @@ static NSString* OmniPreferredDownloadURL(NSDictionary* release) {
|
|||||||
dispatch_async(dispatch_get_main_queue(), ^{
|
dispatch_async(dispatch_get_main_queue(), ^{
|
||||||
NSOpenPanel* panel = [NSOpenPanel openPanel];
|
NSOpenPanel* panel = [NSOpenPanel openPanel];
|
||||||
panel.canChooseFiles = YES;
|
panel.canChooseFiles = YES;
|
||||||
panel.canChooseDirectories = NO;
|
panel.canChooseDirectories = YES;
|
||||||
panel.allowsMultipleSelection = YES;
|
panel.allowsMultipleSelection = YES;
|
||||||
[panel beginWithCompletionHandler:^(NSModalResponse r) {
|
[panel beginWithCompletionHandler:^(NSModalResponse r) {
|
||||||
if (r == NSModalResponseOK) {
|
if (r == NSModalResponseOK) {
|
||||||
@@ -872,9 +872,10 @@ static const CGFloat kTrafficLightInset = 72.0;
|
|||||||
NSString* path = url.path;
|
NSString* path = url.path;
|
||||||
if (!path) continue;
|
if (!path) continue;
|
||||||
BOOL isDir = NO;
|
BOOL isDir = NO;
|
||||||
if ([fm fileExistsAtPath:path isDirectory:&isDir] && !isDir)
|
if ([fm fileExistsAtPath:path isDirectory:&isDir]) {
|
||||||
_app->do_upload(path.UTF8String);
|
self->_app->do_upload(path.UTF8String);
|
||||||
handled = YES;
|
handled = YES;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return handled;
|
return handled;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user