試著把 aniGamerPlus 改成home assistant add-ons版

放上成果 - Home Assistant Add-ons版的巴哈姆特動畫瘋自動下載工具 Home assistant addons 本質上是由「Supervisor」服務管理的預先配置 Docker 容器 所以要先能建構 image 來測試一下 在Terminal

cd /addons/local 
git clone https://github.com/miyouzi/aniGamerPlus.git
cd aniGamerPlus
sed -i 's/python:slim/python:3.9-slim/g' Dockerfile

建立檔案 /addons/local/anigamerplus/config.yaml

name: "aniGamerPlus"
version: 0.0.2
slug: "anigamerplus"
description: "巴哈姆特動畫瘋自動下載工具"
url: "https://github.com/lolimanko/hassio-addons/tree/master/anigamerplus"
arch:
  - aarch64
  - amd64
init: false
ports:
  5000/tcp: 
  5001/tcp: 
ports_description:
  5000/tcp: Web 控制臺
  5001/tcp: SSL Web 控制臺
map:
  - type: addon_config
    read_only: false
    path: /app/configs
  - type: media
    read_only: False
  - type: share
    read_only: false
  - type: ssl
    read_only: false 
ingress: true 
ingress_port: 5000
panel_icon: mdi:television
options:
  cookie: 
  cookie_overwrite: false
  ssl: false
  certfile: fullchain.pem
  keyfile: privkey.pem
schema:
  cookie: str
  cookie_overwrite: bool
  ssl: bool
  certfile: str
  keyfile: str

沒問題就開始進行下一步 修改設定檔存放位址 /addon_config/local_anigamerplus 對應到容器內 /config

sed -i "s/db_path = os.path.join(working_dir, 'aniGamer.db')/db_path = '\/config\/aniGamer.db'/g" aniGamerPlus.py
sed -i "s/logs_dir = os.path.join(Config.get_working_dir(), 'logs')/logs_dir = '\/config\/logs'/g" ColorPrint.py
sed -i "s/config_path = os.path.join(working_dir, 'config.json')/config_path = '\/config\/config.json'/g" Config.py
sed -i "s/sn_list_path = os.path.join(working_dir, 'sn_list.txt')/sn_list_path = '\/config\/sn_list.txt'/g" Config.py
sed -i "s/cookie_path = os.path.join(working_dir, 'cookie.txt')/cookie_path = '\/config\/cookie.txt'/g" Config.py
sed -i "s/logs_dir = os.path.join(working_dir, 'logs')/logs_dir = '\/config\/logs'/g" Config.py
sed -i "s/web_log_path = os.path.join(Config.get_working_dir(), 'logs', 'web.log')/web_log_path = '\/config\/logs\/web.log'/g" Dashboard/Server.py
再來是修改Dashboard中所有絕對位址改成相對位址才能正常用ingress
sed -i "s/\.\.\///g" Dashboard/templates/index.html
sed -i "s/\.\.\///g" Dashboard/templates/login.html
sed -i "s/\.\.\///g" Dashboard/templates/monitor.html
sed -i "s/\.\.\///g" Dashboard/templates/register.html
sed -i "s/url: '\/uploadConfig',/url: 'uploadConfig',/g" Dashboard/static/js/aniGamerPlus.js
sed -i "s/url: '\/manualTask',/url: 'manualTask',/g" Dashboard/static/js/aniGamerPlus.js
sed -i "s/url: '\/sn_list',/url: 'sn_list',/g" Dashboard/static/js/aniGamerPlus.js
sed -i "s/ws+'\/\/'+window.location.host+'\///g" Dashboard/static/js/monitor.js

然後為了直接從設定中修改cookie 還要在docker中安裝bashio 這是能讓docker和Supervisor溝通的函式庫 雖然大部份時間都只用他讀取設定的功能

ARG BUILD_FROM=python:3.9-slim
# hadolint ignore=DL3006
FROM ${BUILD_FROM}

ENV \
    LANG="C.UTF-8" \
    DEBIAN_FRONTEND="noninteractive" \
    CURL_CA_BUNDLE="/etc/ssl/certs/ca-certificates.crt" \
    S6_BEHAVIOUR_IF_STAGE2_FAILS=2 \
    S6_CMD_WAIT_FOR_SERVICES_MAXTIME=0 \
    S6_CMD_WAIT_FOR_SERVICES=1 \
    S6_SERVICES_READYTIME=50

# Set shell
SHELL ["/bin/bash", "-o", "pipefail", "-c"]

# Base system
WORKDIR /usr/src

ARG TARGETARCH
ARG BASHIO_VERSION=0.17.5
ARG TEMPIO_VERSION=2024.11.2
ARG S6_OVERLAY_VERSION=3.2.2.0

RUN \
    set -x \
    && if [ -z "${TARGETARCH}" ]; then \
            echo "TARGETARCH is not set, please use Docker BuildKit for the build." && exit 1; \
        fi \
    && case "${TARGETARCH}" in \
            amd64) TEMPIO_ARCH="amd64"; S6_ARCH="x86_64" ;; \
            arm64) TEMPIO_ARCH="aarch64"; S6_ARCH="aarch64" ;; \
            *) echo "Unsupported TARGETARCH: ${TARGETARCH}" && exit 1 ;; \
        esac \
    && apt-get update && apt-get install -y --no-install-recommends \
        bash \
        jq \
        tzdata \
        curl \
        ca-certificates \
        xz-utils \
    && mkdir -p /usr/share/man/man1 \
    \
    && curl -L -f -s "https://github.com/just-containers/s6-overlay/releases/download/v${S6_OVERLAY_VERSION}/s6-overlay-${S6_ARCH}.tar.xz" \
        | tar Jxvf - -C / \
    && curl -L -f -s "https://github.com/just-containers/s6-overlay/releases/download/v${S6_OVERLAY_VERSION}/s6-overlay-noarch.tar.xz" \
        | tar Jxvf - -C / \
    && curl -L -f -s "https://github.com/just-containers/s6-overlay/releases/download/v${S6_OVERLAY_VERSION}/s6-overlay-symlinks-arch.tar.xz" \
        | tar Jxvf - -C / \
    && curl -L -f -s "https://github.com/just-containers/s6-overlay/releases/download/v${S6_OVERLAY_VERSION}/s6-overlay-symlinks-noarch.tar.xz" \
        | tar Jxvf - -C / \
    && mkdir -p /etc/fix-attrs.d \
    && mkdir -p /etc/services.d \
    \
    && curl -L -f -s -o /usr/bin/tempio \
        "https://github.com/home-assistant/tempio/releases/download/${TEMPIO_VERSION}/tempio_${TEMPIO_ARCH}" \
    && chmod a+x /usr/bin/tempio \
    \
    && mkdir -p /usr/src/bashio \
    && curl -L -f -s "https://github.com/hassio-addons/bashio/archive/v${BASHIO_VERSION}.tar.gz" \
        | tar -xzf - --strip 1 -C /usr/src/bashio \
    && mv /usr/src/bashio/lib /usr/lib/bashio \
    && ln -s /usr/lib/bashio/bashio /usr/bin/bashio \
    \
    && rm -rf '/var/lib/apt/lists/*' && rm -rf '/usr/src/*'

# S6-Overlay



RUN apt update && \
    apt install -y g++ gcc make libevent-dev libffi-dev libxml2-dev libxslt-dev zlib1g-dev ffmpeg && \
    rm -rf '/var/lib/apt/lists/*'

WORKDIR /
COPY . .

RUN pip3 install --no-cache-dir -r requirements.txt

COPY run.sh /
RUN chmod a+x /run.sh
CMD [ "/run.sh" ]

ENTRYPOINT ["/init"]

LABEL \
    io.hass.type="base" \
    io.hass.base.name="debian"

新增run.sh

#!/usr/bin/with-contenv bashio
cookie=$(bashio::config 'cookie')

cookie_overwrite=$(bashio::config 'cookie_overwrite')

ssl=$(bashio::config 'ssl')

certfile=$(bashio::config 'certfile')

keyfile=$(bashio::config 'keyfile')

if [ -f "/config/cookie.txt" ]; then
    
    echo "cookie exist."
    if [ $cookie_overwrite == true ]; then
        echo $cookie > '/config/cookie.txt'
        echo "cookie overwrited  ."
    fi
else
    
    echo $cookie > '/config/cookie.txt'
    echo "cookie create."
fi

exec python3 -u aniGamerPlus.py --bashio $ssl $certfile $keyfile

最後是SSL部分 ingress 無法使用SSL 直接新增在Server.py修改run()新增run_ssl()

def run():
    settings = Config.read_settings()  # 读取配置

    if settings['dashboard']['BasicAuth']:
        # BasicAuth 配置
        app.config['BASIC_AUTH_USERNAME'] = settings['dashboard']['username']  # BasicAuth user
        app.config['BASIC_AUTH_PASSWORD'] = settings['dashboard']['password']  # BasicAuth password
        app.config['BASIC_AUTH_FORCE'] = True  # 全站验证
        basic_auth = BasicAuth(app)

    port = settings['dashboard']['port']
    host = settings['dashboard']['host']


    server = WSGIServer((host, 5000), app, handler_class=WebSocketHandler)

    server.serve_forever()
def run_ssl():
    settings = Config.read_settings()  # 读取配置

    if settings['dashboard']['BasicAuth']:
        # BasicAuth 配置
        app.config['BASIC_AUTH_USERNAME'] = settings['dashboard']['username']  # BasicAuth user
        app.config['BASIC_AUTH_PASSWORD'] = settings['dashboard']['password']  # BasicAuth password
        app.config['BASIC_AUTH_FORCE'] = True  # 全站验证
        basic_auth = BasicAuth(app)

    port = settings['dashboard']['port']
    host = settings['dashboard']['host']



    server = WSGIServer((host, 5001), app, handler_class=WebSocketHandler, certfile='/ssl/'+sys.argv[3], keyfile='/ssl/'+sys.argv[4])
        
    wrap_socket = server.wrap_socket
    wrap_socket_and_handle = server.wrap_socket_and_handle

        # 处理一些浏览器(比如Chrome)尝试 SSL v3 访问时报错
    def my_wrap_socket(sock, **_kwargs):
        try:
                # print('my_wrap_socket')
            return wrap_socket(sock, **_kwargs)
        except ssl.SSLError:
                # print('my_wrap_socket ssl.SSLError')
            pass

        # 此方法依赖上面的返回值, 因此当尝试访问 SSL v3 时, 这个也会出错
    def my_wrap_socket_and_handle(client_socket, address):
        try:
                # print('my_wrap_socket_and_handle')
            return wrap_socket_and_handle(client_socket, address)
        except AttributeError:
                # print('my_wrap_socket_and_handle AttributeError')
            pass

    server.wrap_socket = my_wrap_socket
    server.wrap_socket_and_handle = my_wrap_socket_and_handle

    

    server.serve_forever()

aniGamerPlus.py中

if len(sys.argv) > 1:

改為:

if sys.argv[1] == '--bashio':  
        err_print(0,'bashio輸入模式', '', no_sn=True, display_time=False, status=2)
    elif len(sys.argv) > 1 :

以及

def run_dashboard():
    # 检测端口是否占用
    if not port_is_available(settings['dashboard']['port']):
        err_print(0, 'Web控制面板啓動失敗', 'Port已被占用! 請到配置文件更換', status=1, no_sn=True)
        return

    from Dashboard.Server import run as dashboard
    server = threading.Thread(target=dashboard)
    server.daemon = True
    server.start()
    if settings['dashboard']['SSL']:
        dashboard_address = 'https://'
    else:
        dashboard_address = 'http://'
    if settings['dashboard']['host'] == '0.0.0.0':
        host = Config.get_local_ip()
        dashboard_address = '【開放外部訪問】訪問地址: ' + dashboard_address
    else:
        host = settings['dashboard']['host']
        dashboard_address = '訪問地址: ' + dashboard_address

    dashboard_address = dashboard_address + host + ':' + str(settings['dashboard']['port'])
    err_print(0, 'Web控制面板已啓動', dashboard_address, no_sn=True, status=2)

改為

def run_dashboard():
    # 检测端口是否占用
    if not port_is_available(settings['dashboard']['port']):
        err_print(0, 'Web控制面板啓動失敗', 'Port已被占用! 請到配置文件更換', status=1, no_sn=True)
        return
    #dashboard_address = ''
    if settings['dashboard']['host'] == '0.0.0.0':
        host = Config.get_local_ip()
    else:
        host = settings['dashboard']['host']
    from Dashboard.Server import run as dashboard
    
    server = threading.Thread(target=dashboard)
    server.daemon = True
    server.start()
    err_print(0, 'Web控制面板已啓動', no_sn=True, status=2)

    #if settings['dashboard']['SSL']:
    if sys.argv[2] == 'true' :    
        from Dashboard.Server import run_ssl as dashboard_SSL
        Server_SSL = threading.Thread(target=dashboard_SSL)
        Server_SSL.daemon = True
        Server_SSL.start()
        err_print(0, 'SSL Web控制面板已啓動', no_sn=True, status=2)
這樣如果設定中ssl開啟 就執行兩個Dashboard 至於其他人怎麼做到在ingress裡用ssl的 我就懶得研究了