dandels / dmodman

TUI downloader & update checker for Nexusmods.com
MIT License
43 stars 0 forks source link

Exporting finished download to another application or script #8

Closed jotoho closed 1 year ago

jotoho commented 1 year ago

I realized that my initial description for this issue was too rambly and too narrowly focused on my own code, so I'll try again:

Is there some way to easily "export" a completed download to another terminal command for further processing? If not, how bothersome would something like that be to implement into dmodman?

What I'd be ideally looking for would be some way to give dmodman a template command and have it execute that on the desired file(s) after filling in some variable(s).

For my usecase it would at minimum need to be able to fill-in the path location of the completed download into the command.

Ideally, providing additional metadata (like full mod name, mod author and the URL to the applicable nexusmods page) might be useful as well.

If this is not something you'd like to work on yourself, I fully understand. In that case I would appreciate it if you could give some guidance on what work would be needed if I wanted to implement it into dmodman (or a personal fork thereof) myself.

Original issue description (click to expand)

Hi! I just became aware of this project a few hours ago through it's entry on the API key page of nexusmods and immediately had an idea I would like your opinion on. For some context: Due to the long-time lack of useful software for game modding on Linux, I have recently begun working on a CLI tool called modfs to help me cleanly mod my games (primarily Elder Scrolls). You can find it here under the AGPLv3-only license: https://github.com/jotoho/modfs The tasks of modfs are roughly: - to import mod files provided by the user - to store mods (and different mod versions installed at once) separate from each other, each in their own subdirectory - to allow basic managing of installed mods - to deploy active mods in the desired version into the game files using overlayfs - to prevent damage to the mod and game files - to avoid different mods permanently overwriting each other So when I just discovered this repository, I couldn't help noticing that dmodman and modfs may be able to complement each other well - dmodman interacting with nexusmods and downloading mod files and modfs storing the files and managing the actual install / deployment process. I haven't gotten around to using dmodman yet but I imagine the ideal scenario would be where you could select a downloaded file, press a button/keybind and dmodman calls the `modfs.py import` command with the appropriate parameters and flags. To finally get to my question: How complicated do you think it would be, to add an export functionality like that into dmodman? From the modfs side of things, I believe dmodman would need three pieces of information from the user to be able to do this: - the path to the modfs.py script - the path to the modfs instance directory to use - the user's desired mod_id for this mod (The mod id is a short string that may contain lower-case letters a to z and the ten digits. It acts as the unique identifier of a given mod, both internally and in user commands.) The script and instance locations would be tedious to type in by hand every time, so it would probably make more sense to have it stored in some configuration, or pass it to dpodman via CLI argument or environment variable. The mod id might be different for every operation, so the user would have to provide that per export at runtime. As things stand, the executed command would ideally look similar to this: ```sh python3 /path/to/modfs.py --instance /path/to/instance/directory import /path/to/directory-or-archive.zip ``` Optionally, the following flags could be inserted between `import` and `` to teach modfs the correct metadata for this mod: - `--set-name`: the full name of the mod - `--set-author`: the username of the author on nexusmods - `--set-link`: the URL of the mod's page on nexusmods If you aren't interested in adding a feature like this, I might look into doing it myself in a personal fork or for a pull request. Thanks for taking the time to read this :slightly_smiling_face:

jotoho commented 1 year ago

I reworked the description for this issue. Apologies, if the previous one was too self-centred of me or otherwise offensive in some way.

dandels commented 1 year ago

Ugh, thinking about this exposes so much cruft in my code. Sorry for the slow response, I have limited time/energy because of IRL reasons (contributors wanted). I started writing a response multiple times but your edited post does indeed make it simpler.

I've been thinking of mod installation and overlayfs as dmodman features, but they were out of scope for the initial release. I especially dread the thought of implementing a fomod installer, although I'd love to get to that point.

I do like the idea of configuring external commands to be ran somehow, but dynamic arguments is nontrivial. Mod & file metadata is scattered around multiple different API requests and I have to maintain mappings between them.

Before I get into the implementation details of dmodman, note that it creates .json files next to downloaded files that look like this:

{
  "game": "morrowind",
  "file_name": "Performance-friendly Snow Particles for OpenMW-53233-1-0-1689682484.rar",
  "mod_id": 53233,
  "file_id": 1000039190,
  "update_status": {
    "UpToDate": 1689682484
  }
}

so you might find it easier to simply watch for changes to dmodman's download directory. This metadata is used to look up the correct json files in ~/.local/share/dmodman, which you could consider reading directly rather than having dmodman pass the data to you.

Mod page URLs are only provided by the API when you use the mod search API, but the URL can be generated by knowing the domain name and mod id of a mod, like in this example. The code is unwieldy because dmodman is async/multithreaded and basically everything has to be wrapped in Arcs and RwLocks, but it provides an example of running external commands and passing them metadata. It's also where you'd add new keybinds if you wanted to run your program through a keybind rather than automatically.

Author information isn't fetched by dmodman since there's no use for it, but the code for it exists as adding new API endpoints is straighforward. The Queriable trait needs to be in scope, and then you call ModInfo::request() a bit like in this example, passing it the domain name (game) and mod id in the vec. It's a bit convoluted to use because each API endpoint has different parameters, yet they share the same code for requesting it.

I'll gladly answer questions, although in my own time. Happy hacking!

jotoho commented 1 year ago

Thank you. I'll reopen this issue if I have follow-up questions.