Feature Request: 在EhViewer中使用SMB网络存储#2645
Open
HicirTech wants to merge 29 commits into
Open
Conversation
…try, sort FAB, and 7-second SMB timeout issue#2644
…d cancel issue#2644
Snapshot the application context up front and post the Toast through a main-thread Handler instead of calling getActivity().runOnUiThread() from the worker. The previous code would NPE if the user navigated away from the Settings screen while the SMB probe was still running. issue#2644
Grammar fix; the previous string read 'SMB Setting' which is grammatically odd as a Settings header. zh-* variants already used the correct localised form. issue#2644
Move the 'Share Configuration' and 'Credentials' section headers in the SMB settings screen out of hardcoded XML strings into proper @string resources, with zh-rCN / zh-rTW / zh-rHK translations. issue#2644
Java evaluates arguments left-to-right. The previous one-liner copyStream(child.openInputStream(), targetFile.getOutputStream()) leaks the already-open input stream if getOutputStream() throws. Open the source into a local first and guard the SMB output open with try/catch + closeQuietly. Same pattern applied to the cover download path. issue#2644
If mkdirs() returns false (disk full, permissions, etc.) the cache directory was still latched into the volatile sCacheDir, poisoning every subsequent cacheFileFor() with a path under a non-existent dir. Each fetchOne() would then silently fail with FileNotFoundException, with no log and no retry because PREFETCHED_GIDS already fired. Check the return value, log, and skip the memoise so a later call can retry. issue#2644
finalizeDownloadedGallery runs on IoThreadPoolExecutor, but the same GalleryInfo instance is held by SmbDirectDownloader.active and read from the main thread (notifications, task snapshots). Writing a non-volatile, non-synchronized field from a background thread was a data race. Resolve the page count into a local and thread it through a new writeMetadataWithDetail overload; enrichWithGalleryTags takes the fallback explicitly. The shared info instance is now read-only on the finalize path. issue#2644
Move the hardcoded title/body fragments in SmbDirectDownloader.updateNotification ('Move to SMB', 'SMB save', 'waiting', 'Starting…', '(+N batches)' etc.) into @string resources with zh-rCN / zh-rTW / zh-rHK translations. updateNotification resolves them via appContext.getString, falling back to EhApplication.getInstance() before the service has latched a context.
issue#2644
The two IOException messages thrown from SmbStorage.testConnection ('Host and share name must be configured' / 'Share not accessible') are surfaced to the user via the Settings toast, so move them into @string resources with zh-rCN / zh-rTW / zh-rHK translations.
issue#2644
The reload() Runnable runs on a worker pool and posts back via SimpleHandler; both can fire after onDestroyView has detached the scene. Calling Fragment.getString in that window throws IllegalStateException, swallowing the timeout / error toast we tried to surface. Snapshot the application context at dispatch time and route every string lookup through it instead. issue#2644
The field is written by start() / attachService() from any thread that calls the downloader (background download executor, service binder thread) and read on the main thread by pumpOnMainThread / updateNotification. Without volatile a stale null could be cached on a reader thread, silently suppressing the foreground service start or notification refresh. issue#2644
Previously resume() silently dropped the request if appContext was still null, making the absence of a UI update look like a bug. Log the bail so it is visible in logcat, and snapshot appContext into a local to avoid a TOCTOU between the null-check and the start() call. issue#2644
readAll() previously held the only reference to the SMB InputStream; if it threw mid-read the stream leaked. Wrap getInputStream() in try-with-resources so the SMB handle is always released, even on partial reads. issue#2644
All routing decisions now go through isGidMarkedSmbTarget(); a workspace-wide search confirms zero remaining callers. Dropping the stub also removes the misleading docstring that hinted callers might still need it. issue#2644
readAll() was using BufferedReader.readLine() which strips every line terminator. Single-line JSON files survive but any future pretty-printed payload would silently corrupt. Switch to byte-buffered reads decoded as UTF-8 so the returned String matches the file's exact contents. issue#2644
NAS share names commonly contain spaces or other URL-reserved characters; jcifs requires them percent-encoded in the smb URL. Use URLEncoder and convert its form-encoded plus back to %20 for URL-grammar compliance. issue#2644
deleteGalleryFolder previously called getGalleryDir(info), which mkdirs() any missing share root or gallery directory and then immediately tried to delete what it had just created. It also called SmbFile.delete() directly, but jcifs-ng raises SmbException (STATUS_DIRECTORY_NOT_EMPTY) on a non-empty directory, so cancellation of a partially-downloaded gallery left orphan files on the share. Build the SmbFile references without auto-creating them and walk the tree depth-first. Per-entry failures are logged and skipped so siblings still get cleaned up; the final parent delete propagates IOException if anything remained. issue#2644
Feat: Enable SMB Share in EhViewer
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Close #2644
总而言之
让 EhViewer 能把画廊直接存到 SMB share 里,而不是占手机的存储。NAS 用户可以多端共用同一份下载,看的时候直接从 share 拉,不再依赖于E绅士
加了一层 SMB storage(
SmbStorage/SmbDirectDownloader),跟现有的 DownloadManager 平行。两条线完全不互相干扰:原来的下载该写手机还是写手机,SMB 走自己的后台 service + 前台通知。哪个画廊用 SMB 路径是按 gid 标记的,不是全局 flag, 这样普通下载和SMB下载在同一设备上同时下载不会混淆。设置里多了两个开关
Save Galleries to SMB,关了所有 SMB 功能消失(包括左边的菜单入口, ,开启后详情页的 Download 会弹个对话框问要下到手机还是下到 SMB。Save Galleries to SMB开启的情况下, 用户自行决定要不要打开「Auto Download to SMB」。Auto打开后: 打开画廊第一页 , 触发smb后台排队下载下载本身复用了 SpiderQueen(MODE_DOWNLOAD),靠 SpiderDen 路由把所有写出去的 page / spider info / cover 都改写到 SMB: SpiderQueen 自带 existence check,相当于断点续传
左边新增的 Local Inventory 是什么 (虽然我依旧不知道这个名字对不对, Local指的是LAN中的local, 不过要是有更好的名字的话请在PR中回复, 我可以去改)
行为类似 Favourites,但内容直接从 SMB share 上的
metadata.json读出来渲染。点 thumbnail 进 reader(也是从 share 流式读图),点卡片其他地方进详情页, 详情页完全离线渲染:tags 从 metadata 重建、preview 直接读 share 上的原图缩略、cover 也走 smb share,整个详情页不发任何网络请求。smb share 上一时连不上会显示 sad pandroid 错误(7 秒超时)
smb share里没东西也是 sad pandroid, 和原有的ehViewer行为一致
排序加了个 FAB(下载时间 / 发布时间 / 标题 / 类别)属于是粘性设置
其他事情:
没启用 SMB 的话
完全没区别 EhViewer 原来的所有功能都没动,下载路径、Downloads 页、Favorites 页都是原样
已知 todo
设置里只能配一个 share,issue 里提的「多个 share 位置」目前需要改设置切换 —— 下个 PR 处理