commit f159a507af408e8e4a8d534cf8a64a6f03f953f4 Author: kenzuya Date: Tue Mar 10 17:42:34 2026 +0700 Add files diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..5728663 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,53 @@ +FROM archlinux:latest + +ARG SHAKA_PACKAGER_URL="https://github.com/shaka-project/shaka-packager/releases/download/v2.6.1/packager-linux-x64" +ARG UNSHACKLE_REPO_URL +ARG UNSHACKLE_APP_DIR="/opt/unshackle" + +ENV LANG=C.UTF-8 \ + LC_ALL=C.UTF-8 \ + TS_STATE_DIR=/var/lib/tailscale \ + TS_SOCKET=/var/run/tailscale/tailscaled.sock \ + START_TAILSCALED=1 \ + UNSHACKLE_APP_DIR="${UNSHACKLE_APP_DIR}" + +RUN pacman -Syu --noconfirm && \ + pacman -S --noconfirm --needed \ + aria2 \ + bash \ + ca-certificates \ + curl \ + fish \ + fuse3 \ + git \ + iproute2 \ + iptables \ + less \ + procps-ng \ + python \ + rclone \ + tailscale \ + uv && \ + pacman -Scc --noconfirm + +RUN mkdir -p /var/lib/tailscale /var/run/tailscale /workspace "${UNSHACKLE_APP_DIR}" + +RUN curl -L "${SHAKA_PACKAGER_URL}" -o /tmp/packager-linux-x64 && \ + install -Dm755 /tmp/packager-linux-x64 /usr/local/bin/packager && \ + ln -sf /usr/local/bin/packager /usr/local/bin/shaka-packager && \ + rm -f /tmp/packager-linux-x64 + +RUN git clone "${UNSHACKLE_REPO_URL}" "${UNSHACKLE_APP_DIR}" + +WORKDIR ${UNSHACKLE_APP_DIR} + +RUN uv sync --frozen + +COPY docker/entrypoint.sh /usr/local/bin/container-entrypoint.sh +COPY docker/fish/unshackle-venv.fish /etc/fish/conf.d/unshackle-venv.fish +RUN chmod +x /usr/local/bin/container-entrypoint.sh + +ENV PATH="${UNSHACKLE_APP_DIR}/.venv/bin:${PATH}" + +ENTRYPOINT ["/usr/local/bin/container-entrypoint.sh"] +CMD ["fish"] diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..4da2761 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,47 @@ +services: + unshackle: + build: + context: . + dockerfile: Dockerfile + args: + SHAKA_PACKAGER_URL: https://github.com/shaka-project/shaka-packager/releases/download/v2.6.1/packager-linux-x64 + UNSHACKLE_REPO_URL: https://oauth2:f8c4a9d0472d2b8d0170e78a76b57c62e97cd3bb@gitea.soay-dory.ts.net/unshackle-dl/unshackle.git + UNSHACKLE_APP_DIR: /opt/unshackle + container_name: unshackle + hostname: unshackle + working_dir: /opt/unshackle + stdin_open: true + tty: true + environment: + START_TAILSCALED: "1" + START_RCLONE: "1" + TS_STATE_DIR: /var/lib/tailscale + TS_SOCKET: /var/run/tailscale/tailscaled.sock + TS_AUTHKEY: tskey-auth-kjHgE6GKB611CNTRL-oK3BfNaC2FSDFkSERE2WFS4BPJngTVbv + TS_EXTRA_ARGS: ${TS_EXTRA_ARGS:-} + TS_UP_ARGS: ${TS_UP_ARGS:---ssh} + RCLONE_CONFIG: /etc/rclone/rclone.conf + RCLONE_REMOTE: "ketuakenzuya:" + RCLONE_MOUNT_DIR: /mnt/ketuakenzuya + RCLONE_CACHE_DIR: /tmp/rclone + RCLONE_CACHE_MAX_SIZE: 4G + RCLONE_EXTRA_ARGS: ${RCLONE_EXTRA_ARGS:-} + UNSHACKLE_APP_DIR: /opt/unshackle + cap_add: + - NET_ADMIN + - NET_RAW + - SYS_ADMIN + devices: + - /dev/net/tun:/dev/net/tun + - /dev/fuse:/dev/fuse + security_opt: + - apparmor:unconfined + volumes: + - .:/workspace + - /tmp:/tmp + - ./docker/rclone.conf:/etc/rclone/rclone.conf + - tailscale-state:/var/lib/tailscale + command: fish + +volumes: + tailscale-state: diff --git a/docker/entrypoint.sh b/docker/entrypoint.sh new file mode 100644 index 0000000..409ed75 --- /dev/null +++ b/docker/entrypoint.sh @@ -0,0 +1,97 @@ +#!/usr/bin/env bash +set -euo pipefail + +STATE_DIR="${TS_STATE_DIR:-/var/lib/tailscale}" +SOCKET="${TS_SOCKET:-/var/run/tailscale/tailscaled.sock}" +RCLONE_CONFIG="${RCLONE_CONFIG:-/etc/rclone/rclone.conf}" +RCLONE_REMOTE="${RCLONE_REMOTE:-ketuakenzuya:}" +RCLONE_MOUNT_DIR="${RCLONE_MOUNT_DIR:-/mnt/ketuakenzuya}" +RCLONE_CACHE_DIR="${RCLONE_CACHE_DIR:-/tmp/rclone}" +RCLONE_CACHE_MAX_SIZE="${RCLONE_CACHE_MAX_SIZE:-4G}" + +mkdir -p \ + "$STATE_DIR" \ + "$(dirname "$SOCKET")" \ + "$RCLONE_MOUNT_DIR" \ + "$RCLONE_CACHE_DIR" + +extra_args=() +if [[ -n "${TS_EXTRA_ARGS:-}" ]]; then + # shellcheck disable=SC2206 + extra_args=( ${TS_EXTRA_ARGS} ) +fi + +up_args=() +if [[ -n "${TS_UP_ARGS:-}" ]]; then + # shellcheck disable=SC2206 + up_args=( ${TS_UP_ARGS} ) +fi + +declare -a bg_pids=() + +cleanup() { + for pid in "${bg_pids[@]}"; do + kill "$pid" 2>/dev/null || true + done + + for pid in "${bg_pids[@]}"; do + wait "$pid" 2>/dev/null || true + done +} +trap cleanup EXIT + +if [[ "${START_TAILSCALED:-1}" == "1" ]]; then + if [[ ! -c /dev/net/tun ]]; then + echo "warning: /dev/net/tun tidak tersedia, tailscaled tidak dijalankan" >&2 + else + tailscaled \ + --state="${STATE_DIR}/tailscaled.state" \ + --socket="$SOCKET" \ + "${extra_args[@]}" & + bg_pids+=( "$!" ) + + if [[ -n "${TS_AUTHKEY:-}" || ${#up_args[@]} -gt 0 ]]; then + for _ in {1..30}; do + if tailscale --socket="$SOCKET" status >/dev/null 2>&1; then + break + fi + sleep 1 + done + + tailscale up \ + --socket="$SOCKET" \ + ${TS_AUTHKEY:+--authkey="$TS_AUTHKEY"} \ + "${up_args[@]}" + fi + fi +fi + +extra_rclone_args=() +if [[ -n "${RCLONE_EXTRA_ARGS:-}" ]]; then + # shellcheck disable=SC2206 + extra_rclone_args=( ${RCLONE_EXTRA_ARGS} ) +fi + +if [[ "${START_RCLONE:-1}" == "1" ]]; then + if [[ ! -c /dev/fuse ]]; then + echo "warning: /dev/fuse tidak tersedia, rclone mount tidak dijalankan" >&2 + elif [[ ! -f "$RCLONE_CONFIG" ]]; then + echo "warning: config rclone tidak ditemukan di $RCLONE_CONFIG, mount tidak dijalankan" >&2 + else + rclone mount \ + --config "$RCLONE_CONFIG" \ + --cache-dir "$RCLONE_CACHE_DIR" \ + --vfs-cache-mode full \ + --vfs-cache-max-size "$RCLONE_CACHE_MAX_SIZE" \ + "${extra_rclone_args[@]}" \ + "$RCLONE_REMOTE" \ + "$RCLONE_MOUNT_DIR" & + bg_pids+=( "$!" ) + fi +fi + +if [[ $# -eq 0 ]]; then + exec fish +fi + +exec "$@" diff --git a/docker/fish/unshackle-venv.fish b/docker/fish/unshackle-venv.fish new file mode 100644 index 0000000..cc32288 --- /dev/null +++ b/docker/fish/unshackle-venv.fish @@ -0,0 +1,3 @@ +if test -f /opt/unshackle/.venv/bin/activate.fish + source /opt/unshackle/.venv/bin/activate.fish +end diff --git a/docker/rclone.conf b/docker/rclone.conf new file mode 100644 index 0000000..69d29ca --- /dev/null +++ b/docker/rclone.conf @@ -0,0 +1,25 @@ +[Kenzuya-Drive] +type = drive +token = {"access_token":"ya29.a0AfB_byC1Q968bYjCUHBS9ZapXYolipvgFutwUSVfw0pmqMBUrovkKEqklK8f-q-mQmjnVx6sF84dFnqba4opkDmqQFfa5cku2fWJEKggQGQ32-O8WSQb7v374FM3jeIy-shZGqzMOO3gT406DeFHpf6kME2zWbHQ0_2TaCgYKAS4SARMSFQHGX2Mivt4xa4dOq8WugShFzvLkUg0171","token_type":"Bearer","refresh_token":"1//0geUqgMWTDXuCCgYIARAAGBASNwF-L9Irvx77Ew1oXQt3GgCD0Pe_XU_dPrrit5dg9FcODwtn8XR0rZlCywUgA8bQW9CgHjJnxuE","expiry":"2024-01-14T00:08:13.4396591+07:00"} +team_drive = + +[samlekom7225] +type = drive +token = {"access_token":"ya29.a0AQQ_BDSuPNTZGoLrHG9B22-BbjQ0ABm1tn5djZouV1z-dvemkeJjinp46I4HfS7pu1_ske9Uj4GNksy8MbPCVoWE0bQyBtcKPZFhpovb4Ig9SN2fQSTos2vEEeEyQq4IF7a-LL1zrANcJwLUzWOhmMUWFaJGyLXsf56DMFcQiZNNCmxZ1GyapSbN_RKZQKDgZcXPo9NeUwaCgYKAckSARASFQHGX2Mi9xBB9p8F1A4BczLbI3fzjw0209","token_type":"Bearer","refresh_token":"1//0gGYpJMT-YdmGCgYIARAAGBASNwF-L9IrxB4YzT0VMX2323xqJ5rRCSKSYUxG6EJnWDkgGAmnpsqsfUIeBgQCIt53c3oG46M0U_s","expiry":"2025-09-27T11:25:57.549990864Z","expires_in":3599} +team_drive = + +[manusiabiasa7225] +type = drive +token = {"access_token":"ya29.a0AS3H6NzOxL6lFsvTt6z3_vUyT4MgV0Uz7pKr6E7AlMyJte_XwmG-lHSu7FhfT3-oS-5yW0HBDB8ivI9MqsWTlrwwTHoyciRd5X-9N-Zq3qM_nCbRuimeZiUrwIB2mD4eYd-Wpu5P0qpu28Fa-KkGZ8nqCqoPCMbgtK8gYbbPyoIaCgYKATYSARUSFQHGX2MikXvvpJKtYScwt7oolm7g5A0178","token_type":"Bearer","refresh_token":"1//0g0fAYLjPI9W9CgYIARAAGBASNwF-L9Ir1WG0ZfOVEraWomqHWtf7mjFWxFFKnubbwz_el52ZKCiecygI-s0Kh0ZDY3O1KXMLcAI","expiry":"2025-08-01T00:32:47.641261661Z"} +team_drive = + +[maskenzuya] +type = drive +token = {"access_token":"ya29.a0ATkoCc548BNfJo1sUp0J_yLg-fsWeOmoL4k951BiA2AwVIwmdG7kQBApEXP5I1YQWKNy_jsQO6rvCOdwe_00_fX9QXOb4sna5U9cFbtGK93U2q7WcEd7nxg2fxeKl7w_aR6yanJ6SO9c_JwgpErTO7s5mDnCuM7Hu5LPG_mND2ta23hZcVbtXReeebE5S6BvxeoyCP86wQaCgYKAQsSARQSFQHGX2Miq1fYC2Be50191U9B3rPR5A0209","token_type":"Bearer","refresh_token":"1//0gaYzi2c_icLYCgYIARAAGBASNwF-L9IrwjUcto84AkbxLTHwMHEy-NbjE8J8OettG8B-iwURL8ZNoMpmXEnXniTU-aP1kQt8bgs","expiry":"2026-03-06T03:43:13.080112856+07:00","expires_in":3599} +team_drive = + +[ketuakenzuya] +type = drive +token = {"access_token":"ya29.a0ATkoCc7OeqSFyK0VtO45OuWDjatekS8Avwf1ilzj3ZaAfC6lmmTWwZ8hlpwG-WeXPwQ6LAjV82f4_OYkoinmcFlAOZgMBvN2x_I2D4esHxLfxlHQK5cgiEZMYlNOOQ6Pt1sQuax5xeTgi588mCNU7B2ecAU_4zxkXwBeuwqb1BdKrYv9O4Rq09BCarJYGH8mTor49GHfVwaCgYKAYUSARMSFQHGX2Mi1_DsxQhMr8MHifl0pgnZvw0209","token_type":"Bearer","refresh_token":"1//0gEwdJqyr-PpWCgYIARAAGBASNwF-L9Ir_tyLJKmiZ-4ms72S9Pr1Dy-hzD91KVS4uaoTe6T2BJ-DVH3lMd94FlT4yZYEAOCqX_o","expiry":"2026-03-06T03:43:41.268825918+07:00","expires_in":3599} +team_drive = +