Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Feature request] add selfhosted webinterface for jdownloader #224

Open
milahu opened this issue Sep 17, 2024 · 0 comments
Open

[Feature request] add selfhosted webinterface for jdownloader #224

milahu opened this issue Sep 17, 2024 · 0 comments

Comments

@milahu
Copy link

milahu commented Sep 17, 2024

Idea

the java gui is too ugly / too heavy for my taste
and the VNC tunnel does not make it better

so i scraped the webapp at my.jdownloader.org
and made it work on localhost in my myjdownloader
to get a selfhosted webinterface for jdownloader

see also
My.JDownloader over localhost
local web interface on LAN

one problem is that my.jdownloader.org is closed-source
so this would require some maintenance to keep it working

im running jdownloader in bubblewrap
which is more lightweight than docker

jdownloader-install-and-run.sh
#!/usr/bin/env bash

dir="$(dirname "$0")"

src="https://github.com/milahu/jdownloader-installed"

# TODO better? ~/.cache? ~/.local? ~/.jdownloader?
dst="$HOME/.config/jdownloader"

if ! [ -e "$dst" ]; then
  echo "creating $dst"
  git clone --depth=1 "$src" "$dst"
else
  echo "keeping $dst"
fi

# patch jdownloader
# dont require MyJDownloader login for headless mode
# so we can run our own MyJDownloader service
"$dir"/jdownloader-patch-core.sh "$dst"

# https://my.jdownloader.org/developers/
# My.JDownloader API Documentation
# Pro Tip: It's possible to access the JDownloader API directly (Bypass our server)
# by enabling the so called 'Deprecated API' in the Advanced Options.
# -> jd will listen on port 3128 -> http://localhost:3128/help
cfg="$dst"/cfg/org.jdownloader.api.RemoteAPIConfig.json
if [ "$(cat "$cfg" | jq -r .deprecatedapienabled)" = "false" ]; then
  cat "$cfg" | jq -c '. * { "deprecatedapienabled": true }' | sponge "$cfg"
fi

jre=$(nix-build --no-out-link '<nixpkgs>' -A jre)

bubblewrap=$(nix-build --no-out-link '<nixpkgs>' -A bubblewrap)

a=($bubblewrap/bin/bwrap)

# FIXME add only required /nix/store paths
a+=(--ro-bind /nix /nix)

# TODO better
a+=(--proc /proc)
a+=(--dev /dev)
a+=(--unshare-pid) # ?
a+=(--new-session) # ?
a+=(--unshare-all)
a+=(--share-net)
a+=(--ro-bind /etc/resolv.conf /etc/resolv.conf)
a+=(--die-with-parent)
#a+=(--dir /run/user/$UID) # tmpfs
#a+=(--dir "$dst") # give access to JDownloader.jar etc
a+=(--bind "$dst" "$dst") # give access to JDownloader.jar etc
a+=(--bind "$HOME/Downloads/jdownloader" "/output") # give access to JDownloader.jar etc
#a+=()

a+=($jre/bin/java)

# see also
# https://aur.archlinux.org/cgit/aur.git/tree/JDownloaderHeadless?h=jdownloader2
# headless mode requires username and password in
# $dst/cfg/org.jdownloader.api.myjdownloader.MyJDownloaderSettings.json
a+=(-Djava.awt.headless=true)

a+=(-jar "$dst/JDownloader.jar")

# no. with "-norestart" jd does not restart after update
#a+=(-norestart)

set -x
exec "${a[@]}"

running jdownloader in headless mode
without a my.jdownloader.org account
requires binary patching of the Core.jar file

jdownloader-patch-core.sh
#!/usr/bin/env bash

# patch jdownloader
# dont require MyJDownloader login for headless mode

# based on
# https://github.com/NixOS/nixpkgs/pull/136998/files#r720864456

set -eux

recaf=$(NIXPKGS_ALLOW_UNFREE=1 nix-build --no-out-link '<nixpkgs>' -A nur.repos.milahu.recaf-bin)
export PATH="$recaf/bin:$PATH"

now=$(date --utc +%Y%m%dT%H%M%SZ)

jdownloader_path="$HOME/.config/jdownloader"
if [ $# != 0 ]; then
  jdownloader_path="$1"
fi

jar_path="$jdownloader_path/Core.jar"
bak_jar_path="$jar_path.bak.$now"

class="org/jdownloader/api/myjdownloader/MyJDownloaderController"
method="isAlwaysConnectRequired()Z"

# note: no whitespace in paths
temp_base=/run/user/$UID/recaf-jdownloader-MyJDownloaderController-isAlwaysConnectRequired
asm_path=$temp_base.asm
recaf_script_path=$temp_base.recaf
temp_jar_path=$temp_base.patched.jar

# disassemble the method to patch
cat >$recaf_script_path <<EOF
disassemble --destination=$asm_path $class $method
EOF
recaf --input="$jar_path" --script=$recaf_script_path

# check if method is patched
if ! grep -q INVOKESTATIC $asm_path; then
  echo "patch was already applied"
  # cleanup
  # TODO trap exit
  rm $recaf_script_path
  rm $asm_path
  exit
fi

# patch the assembly code
# -INVOKESTATIC org/appwork/utils/Application.isHeadless()Z
# -IRETURN
# +EXPR return false;
sed -i '/INVOKESTATIC/d; s/IRETURN/EXPR return false;/' $asm_path

# assemble the patched method
cat >$recaf_script_path <<EOF
assemble $class $method $asm_path
export $temp_jar_path
EOF
recaf --input="$jar_path" --script=$recaf_script_path

echo "replacing $jar_path"
mv "$jar_path" "$bak_jar_path"
mv $temp_jar_path "$jar_path"

# cleanup
# TODO trap exit
rm $recaf_script_path
rm $asm_path
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant