Summary
Two gaps in the amuleapi REST API around single-file information:
GET /api/v0/downloads/{hash} exposes only a subset of what the aMule desktop File
Details dialog (CFileDetailDialog) shows.
- There is no single-file endpoint for shared files at all —
/api/v0/shared/{hash}
only accepts PATCH, and GET /api/v0/shared returns just a lean list (7 of the 12
columns of the desktop shared-files table).
This issue (a) wires the missing download-detail fields through, and (b) adds a new
GET /api/v0/shared/{hash} detail endpoint that returns all available info for a
shared file. GET /shared (the list) is left unchanged.
Most values are already shipped by amuled over EC — the refresher just drops them; the
rest are trivially computed in the amuleapi backend.
Effort: webapi-only. No amuled or EC-protocol changes.
Part A — GET /downloads/{hash} detail fields
Extend FileSnapshot::DownloadSide (src/webapi/State.h:96), decode the tags in
src/webapi/Refresher.cpp (MergeDownloadTags), and emit the fields in
WriteDownloadObject (src/webapi/Api.cpp:1595). All download-side tags are already
emitted by CEC_PartFile_Tag (src/ECSpecialCoreTags.cpp:151-212).
New fields (inside the download object unless noted):
| JSON field |
Meaning |
EC tag |
Backing method (ECSpecialCoreTags.cpp) |
last_seen_complete |
unix ts; 0 = unknown |
EC_TAG_PARTFILE_LAST_SEEN_COMP |
lastseencomplete (:174) |
last_changed |
unix ts of last change |
EC_TAG_PARTFILE_LAST_RECV |
GetLastChangeDatetime() (:175) |
download_active_time |
seconds actively downloading |
EC_TAG_PARTFILE_DOWNLOAD_ACTIVE |
GetDlActiveTime() (:176) |
available_part_count |
parts available across sources |
EC_TAG_PARTFILE_AVAILABLE_PARTS |
GetAvailablePartCount() (:177) |
part_count |
total parts |
derive ceil(size / PARTSIZE) (already computed at Api.cpp:1564) |
— |
remaining_time |
ETA seconds; -1 = unknown/stalled |
computed in amuleapi (see below) |
— |
hashing_progress |
part currently being hashed |
EC_TAG_PARTFILE_HASHED_PART_COUNT |
GetHashingProgress() (:178) |
lost_to_corruption |
bytes lost to corruption |
EC_TAG_PARTFILE_LOST_CORRUPTION |
GetLostDueToCorruption() (:180) |
gained_by_compression |
bytes saved by compression |
EC_TAG_PARTFILE_GAINED_COMPRESSION |
GetGainDueToCompression() (:181) |
saved_by_ich |
packets recovered by I.C.H. |
EC_TAG_PARTFILE_SAVED_ICH |
TotalPacketsSavedDueToICH() (:182) |
aich_hash |
AICH master hash (also on GET /shared/{hash}) |
EC_TAG_KNOWNFILE_AICH_MASTERHASH |
GetAICHMasterHash() (:226) |
met_file |
.part.met basename |
EC_TAG_KNOWNFILE_FILENAME |
GetCachedPartMetBasename() (:246) |
partmet_id |
numeric partfile id |
EC_TAG_PARTFILE_PARTMETID |
GetPartMetNumber() (:203) |
queued_count |
clients queued (also on GET /shared/{hash}) |
EC_TAG_KNOWNFILE_ON_QUEUE |
GetQueuedCount() (:236) |
remaining_time (computed in the backend)
The desktop getTimeRemaining() (src/PartFile.cpp:4423) computes ETA as
(size - size_done) / (speed), returning -1 when the speed is ~0. There is no EC tag
for it, but amuleapi already has size, size_done and speed_bps in the snapshot, so it
computes remaining_time server-side — no amuled/EC change needed.
File Details coverage notes
- The "Filepart-Count" line in the dialog shows
PartCount (HashCount). part_count is
covered; hash_count (GetHashCount()) has no standalone EC tag — a minor, derivable
gap, not blocking.
- The dialog's "Cleanup" button is a pure client-side filename-beautifier heuristic
(src/FileDetailDialog.cpp:415-505) — no API data; a client implements it locally.
- These fields back the "General", "Transfer" and "Intelligent Corruption Handling" boxes
of CFileDetailDialog (src/FileDetailDialog.cpp:151-192).
Part B — new GET /shared/{hash} (shared-file detail)
GET /shared (the list) stays exactly as it is. Add a new detail endpoint that returns
all available info for a single shared file — the goal is one call that gives a client
everything about a file.
- Routing:
/api/v0/shared/{hash} currently maps only PATCH → HandleSharedPatch
(src/webapi/Api.cpp:851-855). Add a GET branch → a new HandleSharedDetail +
WriteSharedDetailObject, mirroring the download detail path (Api.cpp:2204 /
HandleDownloadDetail).
- Base fields: everything
WriteSharedObject (Api.cpp:1701) already emits —
hash, name, ed2k_link, size, priority, priority_auto, complete_sources, xfer{session,total}, requests{session,total}, accepts{session,total}.
- Plus the following detail fields (the shared-files table gaps + shared-applicable
identity fields):
| JSON field |
GUI column / meaning |
Source |
Kind |
file_type |
Type |
computed in amuleapi backend from the filename extension (same categorization as GetFiletypeByName, src/SharedFilesCtrl.cpp:595): "Audio", "Video", "Archive", "Program", "Document"… |
backend-computed |
share_ratio |
Share Ratio |
computed in amuleapi backend as xfer.total / size (mirrors src/SharedFilesCtrl.cpp:623); 0 when size == 0 |
backend-computed |
path |
Directory Path |
EC_TAG_KNOWNFILE_FILENAME → GetFilePath().GetPrintable() ("[PartFile]" for a shared partfile, src/SharedFilesCtrl.cpp:657-660) |
webapi-only decode |
complete_sources_range { low, high } |
Complete Sources range |
EC_TAG_KNOWNFILE_COMPLETE_SOURCES_LOW / _HIGH (src/ECSpecialCoreTags.cpp:232-233); the < N / N - M display (src/SharedFilesCtrl.cpp:638-652) — complements scalar complete_sources |
webapi-only decode |
aich_hash |
— |
EC_TAG_KNOWNFILE_AICH_MASTERHASH (ECSpecialCoreTags.cpp:226) |
webapi-only decode |
part_count |
— |
derive ceil(size / PARTSIZE) |
backend-computed |
queued_count |
— |
EC_TAG_KNOWNFILE_ON_QUEUE (ECSpecialCoreTags.cpp:236) |
webapi-only decode |
The "Obtained Parts" availability-bar column is intentionally excluded — it is the only
shared-table column that would need a new EC tag, and it is ~100% for complete shared files.
Acceptance criteria
GET /downloads/{hash} returns all Part-A fields with correct values for an active
download; remaining_time is -1 when paused/stalled.
GET /shared/{hash} exists (new) and returns every GET /shared field plus the
Part-B detail fields for a shared file; share_ratio is 0 when size == 0; path is
"[PartFile]" for a shared partfile.
GET /shared (the list) is unchanged.
- No regressions in the existing download-list / download-detail / shared-list payloads.
Summary
Two gaps in the amuleapi REST API around single-file information:
GET /api/v0/downloads/{hash}exposes only a subset of what the aMule desktop FileDetails dialog (
CFileDetailDialog) shows./api/v0/shared/{hash}only accepts
PATCH, andGET /api/v0/sharedreturns just a lean list (7 of the 12columns of the desktop shared-files table).
This issue (a) wires the missing download-detail fields through, and (b) adds a new
GET /api/v0/shared/{hash}detail endpoint that returns all available info for ashared file.
GET /shared(the list) is left unchanged.Most values are already shipped by amuled over EC — the refresher just drops them; the
rest are trivially computed in the amuleapi backend.
Effort: webapi-only. No amuled or EC-protocol changes.
Part A —
GET /downloads/{hash}detail fieldsExtend
FileSnapshot::DownloadSide(src/webapi/State.h:96), decode the tags insrc/webapi/Refresher.cpp(MergeDownloadTags), and emit the fields inWriteDownloadObject(src/webapi/Api.cpp:1595). All download-side tags are alreadyemitted by
CEC_PartFile_Tag(src/ECSpecialCoreTags.cpp:151-212).New fields (inside the
downloadobject unless noted):ECSpecialCoreTags.cpp)last_seen_completeEC_TAG_PARTFILE_LAST_SEEN_COMPlastseencomplete(:174)last_changedEC_TAG_PARTFILE_LAST_RECVGetLastChangeDatetime()(:175)download_active_timeEC_TAG_PARTFILE_DOWNLOAD_ACTIVEGetDlActiveTime()(:176)available_part_countEC_TAG_PARTFILE_AVAILABLE_PARTSGetAvailablePartCount()(:177)part_countceil(size / PARTSIZE)(already computed atApi.cpp:1564)remaining_time-1= unknown/stalledhashing_progressEC_TAG_PARTFILE_HASHED_PART_COUNTGetHashingProgress()(:178)lost_to_corruptionEC_TAG_PARTFILE_LOST_CORRUPTIONGetLostDueToCorruption()(:180)gained_by_compressionEC_TAG_PARTFILE_GAINED_COMPRESSIONGetGainDueToCompression()(:181)saved_by_ichEC_TAG_PARTFILE_SAVED_ICHTotalPacketsSavedDueToICH()(:182)aich_hashGET /shared/{hash})EC_TAG_KNOWNFILE_AICH_MASTERHASHGetAICHMasterHash()(:226)met_file.part.metbasenameEC_TAG_KNOWNFILE_FILENAMEGetCachedPartMetBasename()(:246)partmet_idEC_TAG_PARTFILE_PARTMETIDGetPartMetNumber()(:203)queued_countGET /shared/{hash})EC_TAG_KNOWNFILE_ON_QUEUEGetQueuedCount()(:236)remaining_time(computed in the backend)The desktop
getTimeRemaining()(src/PartFile.cpp:4423) computes ETA as(size - size_done) / (speed), returning-1when the speed is ~0. There is no EC tagfor it, but amuleapi already has
size,size_doneandspeed_bpsin the snapshot, so itcomputes
remaining_timeserver-side — no amuled/EC change needed.File Details coverage notes
PartCount (HashCount).part_countiscovered;
hash_count(GetHashCount()) has no standalone EC tag — a minor, derivablegap, not blocking.
(
src/FileDetailDialog.cpp:415-505) — no API data; a client implements it locally.of
CFileDetailDialog(src/FileDetailDialog.cpp:151-192).Part B — new
GET /shared/{hash}(shared-file detail)GET /shared(the list) stays exactly as it is. Add a new detail endpoint that returnsall available info for a single shared file — the goal is one call that gives a client
everything about a file.
/api/v0/shared/{hash}currently maps onlyPATCH→HandleSharedPatch(
src/webapi/Api.cpp:851-855). Add aGETbranch → a newHandleSharedDetail+WriteSharedDetailObject, mirroring the download detail path (Api.cpp:2204/HandleDownloadDetail).WriteSharedObject(Api.cpp:1701) already emits —hash, name, ed2k_link, size, priority, priority_auto, complete_sources, xfer{session,total}, requests{session,total}, accepts{session,total}.identity fields):
file_typeGetFiletypeByName,src/SharedFilesCtrl.cpp:595):"Audio","Video","Archive","Program","Document"…share_ratioxfer.total / size(mirrorssrc/SharedFilesCtrl.cpp:623);0whensize == 0pathEC_TAG_KNOWNFILE_FILENAME→GetFilePath().GetPrintable()("[PartFile]"for a shared partfile,src/SharedFilesCtrl.cpp:657-660)complete_sources_range{ low, high }EC_TAG_KNOWNFILE_COMPLETE_SOURCES_LOW/_HIGH(src/ECSpecialCoreTags.cpp:232-233); the< N/N - Mdisplay (src/SharedFilesCtrl.cpp:638-652) — complements scalarcomplete_sourcesaich_hashEC_TAG_KNOWNFILE_AICH_MASTERHASH(ECSpecialCoreTags.cpp:226)part_countceil(size / PARTSIZE)queued_countEC_TAG_KNOWNFILE_ON_QUEUE(ECSpecialCoreTags.cpp:236)The "Obtained Parts" availability-bar column is intentionally excluded — it is the only
shared-table column that would need a new EC tag, and it is ~100% for complete shared files.
Acceptance criteria
GET /downloads/{hash}returns all Part-A fields with correct values for an activedownload;
remaining_timeis-1when paused/stalled.GET /shared/{hash}exists (new) and returns everyGET /sharedfield plus thePart-B detail fields for a shared file;
share_ratiois0whensize == 0;pathis"[PartFile]"for a shared partfile.GET /shared(the list) is unchanged.