eD2k and Kad through aMule¶
Gextto reaches the eD2k and Kad networks through aMule. amuled
does the networking — servers, Kad, sources, queues, credits, transfers — and
Gextto drives it over aMule's External Connections (EC) protocol, the same
one amulecmd, amuleweb and the remote GUI use: it searches, sends
ed2k:// links, lists and controls the downloads in Downloads, shows the
eD2k page and imports completed files into the library.
The integration is optional and off by default (ed2k_enabled). Gextto does
not ship an eD2k client: you install, configure and run aMule yourself. With
aMule off or unreachable the eD2k features are simply unavailable and torrents
are never affected.
Requirements¶
- aMule with
amuled, running and reachable from Gextto: on the same machine (the usual case) or on another machine of the network. - External connections enabled in aMule, with a password (see below).
- The incoming folder visible at the same path on the machine where Gextto runs, if completed files must be imported into the library. When both run on the same machine this is automatic.
- aMule's TCP and UDP ports open on the router for a High ID and a Kad that is not firewalled, which means more sources. With the default ports that is TCP 4662 and UDP 4672 (Kad and eD2k share the UDP port).
Install aMule¶
Install aMule from your distribution. On Debian and Ubuntu the package is
amule-daemon:
sudo apt install amule-daemon
On the other distributions install the aMule package that ships amuled.
Start it the way the distribution ships it (the package usually provides a
service), or run amuled yourself as the user that owns aMule's configuration
folder. Unless a different --config-dir is used, that folder is ~/.aMule
and the file to edit is ~/.aMule/amule.conf.
[!NOTE] aMule rewrites
amule.confwhen it exits. Edit the file whileamuledis stopped, then start it again, or the changes are lost.
Enable external connections¶
In amule.conf:
[ExternalConnect]
AcceptExternalConnections=1
ECAddress=127.0.0.1
ECPort=4712
ECPassword=<md5 of the password>
ECPasswordis the MD5 hex digest of the password, not the password itself:printf '%s' 'secret' | md5sum. In Gextto the password is entered in clear (amule_password) and hashed by the client at login.ECAddressis the address aMule binds:127.0.0.1accepts connections only from the same machine. If Gextto runs on another host, bind to the interface or to0.0.0.0and restrict port 4712 with the firewall.ECPortis the port Gextto connects to (4712 by default); it must match aMule — external connections (EC) port in Gextto's settings.
Docker¶
With the ngosang/amule image (or any aMule container):
- mount the download share at the same path inside the container and set
INCOMING_DIRandTEMP_DIRto those paths, so the folder aMule reports is valid on the host too; - use a dedicated incoming folder, because aMule shares everything it holds;
- to let aMule open its ports on the router by UPnP, run the container with
network_mode: hostand setUPnPEnabled=1inamule.conf. In bridge mode aMule would ask the router to forward the ports to the container's address, which does not work; - publish the EC port (4712) and set
ECAddress=0.0.0.0if Gextto is outside the container.
A minimal compose.yaml that follows these rules (adapt the paths):
services:
amule:
image: ngosang/amule:latest
container_name: amule
network_mode: host
restart: unless-stopped
environment:
TZ: Europe/Rome
PUID: "1000"
PGID: "1000"
UMASK: "0002"
GUI_PWD: "<EC password in clear>"
INCOMING_DIR: /srv/downloads/amule
TEMP_DIR: /srv/downloads/amule-temp
volumes:
- ./amule-config:/home/amule/.aMule
- /srv/downloads:/srv/downloads
With network_mode: host aMule listens on the host's port 4712 and Gextto
connects to the machine's address (also 127.0.0.1). The container is yours:
Gextto does not create, start or update it; update it with
docker compose pull and docker compose up -d. aMule's category folders
must also live in a mounted volume and have a path that exists: an
Incoming=/incoming left by another image cannot be created in the container
and fills the log with errors.
With aMule in a container, Gextto checks the incoming and temporary folders
inside the container (through /proc/<pid>/root): a folder missing there is
reported on the eD2k page but never created from outside. If the container's
incoming folder is not mounted at the same path on the host, the page says the
import cannot work: fix the Docker mount, not the host folder.
On a network disk¶
Set AllocateFullFile=0 in amule.conf: preallocating a multi-GB part file on
a NAS can block amuled (and its EC answers) for tens of seconds. Gextto copes
with a slow aMule — an add that times out, or that aMule refuses because the
file is already listed, is checked against the download queue and counts as
done when the file is there — but turning the preallocation off avoids the
wait altogether.
Turn it on in Gextto¶
Configuration → eD2k and Kad:
- switch on eD2k and Kad through aMule;
- fill in address (usually
127.0.0.1), EC port (4712) and the password in clear; - save, then open the eD2k page (Discovery → eD2k) and press Connect to join eD2k and start Kad.
The Sources page shows the eD2k and Kad sensor: open (connected to a server with a High ID), limited (firewall/NAT: Low ID, or Kad only), not connected, aMule unreachable or unknown (state not read yet). If the sensor says limited, open aMule's TCP and UDP ports on the router.
When aMule does not answer, the eD2k page says so, explains what to check and offers Retry. Nothing else in Gextto stops working.
The state panel also shows the bytes aMule exchanged in this session and over all time, and whether aMule preallocates files. The preallocation switch is in Configuration → eD2k and Kad → aMule, where it is saved to aMule at once: it is aMule's setting, not one stored in Gextto. The Health page has an eD2k card with the same state, the session and all-time totals and the latest problem lines from aMule's log.
The aMule panel of Settings → eD2k and Kad and the eD2k card of Health say explicitly that the client in use is aMule, with its version, the EC address and Where it runs: on this machine, in a container, on this machine or on another machine. That way an aMule in Docker on the same machine is not confused with one installed on the system or with one on another host.
When amuled runs on Gextto's machine, the header shows an aMule badge with
the daemon's CPU and RAM, updated with the other metrics. With aMule on another
host the badge is absent: those figures are not available through the EC
protocol.
Using it¶
The eD2k page has three tabs: aMule and search (state, servers, search, pasted links), Shared files and aMule log.
Search¶
Three places, all through aMule:
- Manual search (the search box of Downloads and the search page): tick eD2k to add eD2k/Kad results to the torrents.
- eD2k page → Search eD2k and Kad: pick the network and search; aMule collects results for a few seconds.
- Archive: tick Also search eD2k to get a block of eD2k results under the archived releases.
Queries are normalized: accents, typographic apostrophes and parentheses no
longer prevent a search; for an episode, when SxxExx finds nothing Gextto also
tries 1x05, 1x5 and 01x05.
The network is the one chosen in eD2k search network: Kad (default: a distributed network, no server needed), Kad + eD2k servers (both searches, results merged by hash), eD2k servers (global) (every server in aMule's list) or eD2k server (connected) (only the one aMule is connected to). The automatic fallback always searches Kad and the servers together.
Every result shows name, size, MD4 hash and sources (transferring / total),
is parsed like a torrent name (series, episode, quality) and has
Download; already known marks a file aMule already has. The eD2k page
also lists aMule's servers with users, files and ping, and can download a new
server.met or a nodes.dat for Kad from an address.
Paste eD2k links¶
On the eD2k page or in the Downloads search row (the field under the
search box, Open eD2k links), paste one or more ed2k:// links, even mixed
with text: Gextto validates them, shows them as results and Download with
aMule queues them all. A link to a file that is not a video (a pdf, a
program, an archive) is only an aMule download and stays in the incoming
folder, like a torrent added by hand.
Downloads and completion¶
aMule's queue is listed in Downloads next to the torrents and the HTTP
downloads, with progress, speed, sources (transferring / total), pause /
resume / remove and a badge eD2k. ⓘ opens the details: state, sources,
last data received, hash, the ed2k:// link to copy and the file's
priority in aMule (low, normal, high, automatic). The downloads count on
the dashboard and in the menu badge, appear in the TUI list and their traffic
is drawn on the dashboard chart as dashed lines, while the top bar sums
torrents and aMule.
When aMule completes a video, Gextto raises the same completion event a torrent produces, so renaming, the library import, the MediaInfo check, the notification and the media library refresh are shared. The quality gate runs before anything is written to the library, movies included: if the library already holds an equal or better file, the download is discarded (moved to the trash, or deleted according to the cleanup action) and never copied.
aMule 2.3 keeps a finished file in its download queue; aMule 3.x drops it at once, so Gextto finds it among the shared files, also after a restart. Before importing, Gextto waits until the file is actually in the incoming folder, with the expected size and stable: a file aMule is still copying from temp is not treated as ready. eD2k episodes and movies follow the Move episodes/packs into the archive option: when it is on they are moved into the library and removed from the incoming folder (aMule stops sharing them); when it is off they are imported by hardlink or copy and aMule keeps sharing the original. For eD2k the move happens at completion, because seeding is managed by aMule; a hardlink costs no extra space when both folders are on the same filesystem.
Notifications use the same events as torrents: Download started when Gextto itself picks a result (the automatic eD2k fallback included), Download complete with the title, the library path, the size, the duration and the average speed (and the replaced release when it replaced a worse one), Download failed when an automatic eD2k download stalls for the configured days, Torrent error when the import fails. A file discarded as inferior produces only a log line, and a file that is not a video is never registered as a release: if aMule keeps it in its queue you get the plain "manual" completion notice, with aMule 3.x (which drops it at once) no notice at all.
Bandwidth¶
aMule follows Gextto's speed limits (rule, exception, schedule, Auto): they are sent when they change and re-sent every 10 minutes. The eD2k page shows the limits aMule has now.
Automatic fallback¶
Second, separate switch (Use eD2k when torrents find nothing, off by default): in the deep gap-filling pass, only when the torrent episode and season searches found nothing, Gextto searches Kad and the eD2k servers (global search) for the configured name and every alias, and starts a result only with the exact episode, a recognised quality, a video file and at least the source floor set in Minimum sources for the fallback.
Downloads that stall¶
An eD2k download Gextto started by itself that receives nothing for as many days as Give up on a stalled eD2k download after says (7, 0 = never, measured on aMule's "last data received" time, so restarts do not reset it) is cancelled in aMule, its release is blocklisted and the gap is searched again. Downloads added by hand and paused ones are left alone.
Shared files and uploads¶
The Shared files tab lists what aMule shares with the
bytes uploaded in this session and over all time, the requests and accepted
requests (session and since the start), the clients queued for each file, the
file's live upload speed, the last upload and the upload priority, and the
file's ed2k:// link to copy. The counters are aMule's own: the session
figures restart with amuled, the all-time ones are persisted in its
known.met. Below the table, Who is downloading from you lists the clients
in the upload queue with their software, file, speed and queue position. The tab
also shows the current upload rate and queue length, and the shared folders
read-only: the incoming folder plus the extra ones configured in aMule.
Reload shared files asks aMule to rescan its folders, the same as the reload button of its GUI: files you added or removed by hand show up or disappear. Gextto never changes aMule's sharing configuration.
The aMule log tab shows the last lines of amuled's own log, with Refresh
to read them again. The blocks aMule prints for the router's UPnP event
notifications (UPNP_EVENT_RECEIVED with its SID, Key, Property list and
SystemUpdateID lines) are left out: the router sends one every time a port
mapping changes, on any device, and they would fill the tab and push out the
lines that matter. Every other aMule line, the other UPnP ones included, is
shown.
Troubleshooting¶
| Symptom | What to check |
|---|---|
| aMule unreachable on the eD2k page or the Sources sensor | amuled is running; AcceptExternalConnections=1; ECPort and address match Gextto's settings; port 4712 is open in the firewall if aMule is on another machine; ECAddress is not 127.0.0.1 when Gextto connects from elsewhere. |
Wrong password (the page reports authentication failed) |
In Gextto the password is the clear one; ECPassword in amule.conf is its MD5. After changing it, restart amuled. |
| Low ID (badge on the eD2k page) | aMule's TCP port (4662 by default) is not reachable from outside: open it on the router, or enable UPnP in aMule. Fewer sources, slower queues. |
| Kad behind a firewall | aMule's UDP port (4672 by default) is not reachable: open it on the router. Kad works but finds fewer sources. |
| Search returns nothing | the chosen network (Kad only needs Kad to be connected); a search duration that is too short; a Kad firewalled. Kad and the servers index different files, so try Kad + eD2k servers. |
| Download stays queued | normal on eD2k: aMule waits for its turn in the sources' queues. Check sources and the ID; low ID means long queues. |
aMule's log fills with Failed to get file system statistics |
its incoming or temporary folder does not exist (a network disk unmounted, a folder removed): the eD2k page lists the missing folders and Create the folders makes them again. |
aMule's log says Directory '/incoming' couldn't be created (error 13: Permission denied) |
that is the incoming folder of an aMule category, not the main one (which Gextto shows as fine): some Docker images, for example the linuxserver one, leave the categories pointing at /incoming, which does not exist in the container and cannot be created there. Fix or remove those categories in aMule's preferences and restart amuled; Gextto never changes them. The Health page shows the line once. |
HTTP download failed for https://download.db-ip.com (404) and DB-IP download failed for the current month |
this is normal at the start of a month: the new month's IP-to-country database is not published yet, aMule retries with the previous month's file and keeps the one it already has. Nothing to do, and the Health page does not list them as warnings. |
| Files complete in aMule but never appear in the library | the incoming folder is not visible at the same path from Gextto, or is not readable; the file is not a video (it stays in the incoming folder by design); aMule was still preallocating (AllocateFullFile=0 on network disks). |
| The eD2k page shows the integration as off | the switch is off, or the settings were not saved. The page links straight to the setting. |
Reference¶
Settings¶
| Key | Meaning |
|---|---|
ed2k_enabled |
master switch (off) |
amule_host |
host of amuled (127.0.0.1) |
amule_port |
EC port (4712) |
amule_password |
EC password, in clear (secret) |
ed2k_search_network |
kad (default), both (Kad + eD2k servers), global or local |
ed2k_search_timeout_secs |
how long aMule collects results (5–120 s, default 20) |
ed2k_fallback |
automatic gap-filling fallback (off) |
ed2k_min_sources |
source floor of the fallback (3) |
ed2k_stall_days |
give up on an automatic download idle for this many days (7, 0 = never) |
The settings of the earlier integrations (extto's amule_* service options,
gx-ed2k's ed2k_url, ed2k_token, ed2k_upnp, …) are deleted at load;
amule_host, amule_port and amule_password are kept. The API is documented
in API.md (/api/ed2k/status, /api/ed2k/downloads,
/api/ed2k/limits, /api/ed2k/log).
The EC client (internal/amule)¶
- Framing:
flags:uint32 BE | length:uint32 BE | payload. The payload isopcode:uint8 | tagCount:uint16 | tags; a tag isname<<1|hasChildren:uint16 | type:uint8 | length:uint32 | [childCount | children] | data. A tag's length counts its data plus every child with a fixed 7-byte header (+2 when the child has children), independent of the number encoding. - The client never advertises
EC_TAG_CAN_ZLIBorEC_TAG_CAN_UTF8_NUMBERS, so amuled answers with plain packets; the decoder still accepts zlib payloads and UTF-8-encoded numbers. - Login (protocol
0x0204, aMule 2.3.x):EC_OP_AUTH_REQ→EC_OP_AUTH_SALT→EC_OP_AUTH_PASSWDwithMD5(hex(MD5(password)) + hex(MD5(uppercase hex of the salt)))→EC_OP_AUTH_OK. - One connection, requests serialised; a transport error closes it and the request is retried once on a fresh login, so an amuled restart is invisible.
- Operations: status (
EC_OP_STAT_REQwith the connection state), server list, connect/disconnect, server connect/disconnect,server.met/nodes.datfrom URL, Kad start/stop, download queue, add link, pause/resume/delete, clear completed, shared files, search (start, results, progress, stop), preferences (incoming/temp folders, bandwidth limits) and the log. - aMule keeps one search result list: a new search replaces the previous
one, even when another client starts it (aMuleGUI,
amulecmd, an external tool). Gextto serialises its own searches (ed2kSearchMu), so the alias queries of the gap filler run one after the other; if the list is replaced while a search is running (it shrinks or no longer holds a single known hash) the search is restarted and, if the interference continues, refused withErrSearchBusyinstead of returning the other client's files. A Kad search ends when the core reports0xfffeand the result count is stable; a server search is read until the configured duration elapses.
Gextto side¶
| File | Role |
|---|---|
ed2ksearch.go |
settings, shared client with a fail-fast backoff while amuled is down, cached status, search and gap-filling fallback, GET /api/ed2k/status |
ed2k_downloads.go |
download list, add/pause/resume/remove, the session that turns completed files into torrent_finished events, the copy-mode import configuration |
uiweb_v2_ed2k.go |
the eD2k page (status, servers, Kad, search, pasted links) |
web_background.go |
merges aMule's completion events into the torrent event loop, each handled by its own session |
Tests¶
internal/amule: codec (round trip, tag length rule, UTF-8 numbers, zlib, malformed input), login answer, client against the fake coreinternal/amule/amuletest.TestLiveCoreruns against a real amuled whenGEXTTO_AMULE_EC=host:portandGEXTTO_AMULE_PASSWORDare set: status, preferences, servers, add / pause / resume / delete of a link, Kad search, limits, log and a refused wrong password. It is skipped in normal runs.- Gextto:
ed2ksearch_test.go(search, refusal, fallback gate, wrong password, aliases, link add and actions, completion events, copy-mode import) against the fake core.
History¶
Gextto first shipped its own eD2k/Kad daemon, gx-ed2k. Its protocol layer
worked, but the download scheduler (sources, queues, UDP reasks) never reached
the level of a real eMule client, and the measured Kad coverage of missing
episodes was 7–13% (see measurements.md). It was retired in
favour of aMule; the code is kept in the git history, at commit 9f4e2b9.