#!/bin/zsh # ./install.zsh $HOST repos_v='{}' function at-repos-env() { host=$1 if [ -z "$1" ];then host=syu.is fi did=did:plc:6qyecktefllvenje24fcxnie icon=https://git.syui.ai/ai/at/raw/branch/main/icons/Logotype.tsx repos=( https://github.com/did-method-plc/did-method-plc https://github.com/bluesky-social/indigo https://github.com/bluesky-social/atproto https://github.com/bluesky-social/social-app https://github.com/bluesky-social/feed-generator https://github.com/bluesky-social/ozone https://github.com/bluesky-social/jetstream ) services=( bsky plc pds jetstream bgs ozone social-app ) d=${0:a:h} dh=${0:a:h:h} name=${host%%.*} domain=${host##*.} dport=5000 } function at-repos-json() { f=~/.config/atproto/token.json j="{ \"did\": \"did:plc:6qyecktefllvenje24fcxnie\", \"didDoc\": { \"service\": [ { \"serviceEndpoint\": \"https://syu.is\" } ] }, \"handle\": \"ai.syu.is\", \"accessJwt\": \"xxx\" }" if [ ! -f "$f" ];then mkdir -p ~/.config/atproto echo $j >> $f fi echo $f } function at-repos-token() { at-repos-json if [ -z "$host" ] && [ -f $f ];then host=`cat $f|jq -r ".didDoc.service.[].serviceEndpoint"` handle=`cat $f|jq -r ".handle"` did=`cat $f|jq -r ".did"` token=`cat $f|jq -r ".token"` host=${host##*/} fi name=${host%%.*} domain=${host##*.} } function at-repos-clone() { if [ ! -d $d/repos ];then mkdir -p $d/repos fi cd $d/repos for ((i=1; i<=${#repos}; i++)); do repo=${repos[$i]} echo $repo if [ ! -d $d/repos/${repo##*/} ];then git clone $repo fi done if [ ! -f $d/repos/feed-generator/Dockerfile ] && [ -f $d/docker/feed/Dockerfile ];then cp -rf $d/docker/feed/Dockerfile $d/repos/feed-generator/ fi } function at-repos-pull() { cd $d/repos for ((i=1; i<=${#repos}; i++)); do repo=${repos[$i]} echo $repo if [ -d $d/repos/${repo##*/} ];then cd $d/repos/${repo##*/} git stash if ! git pull;then rm -rf $d/repos/${repo##*/} at-repos-clone fi fi rv=$(echo "$repos_v" | jq -r ".[\"${repo##*/}\"]") if [ "$rv" != "null" ];then cd $d/repos/${repo##*/} git reset --hard $rv cd .. fi done cd $d } function at-repos-social-app-icon() { curl -sL https://raw.githubusercontent.com/bluesky-social/social-app/main/src/view/icons/Logotype.tsx -o $d/repos/social-app/src/view/icons/Logotype.tsx if [ -d $d/icons ];then mkdir -p $d/icons fi cp -rf $d/repos/social-app/src/view/icons/Logotype.tsx $d/icons/ } function at-repos-social-app-icon-origin() { curl -sL $icon -o $d/icons/Logotype.tsx } function at-repos-social-app-avatar-write() { did_admin=did:plc:6qyecktefllvenje24fcxnie dt=$d/repos/social-app/src cd $dt f=$dt/lib/constants.ts sed -i "s#export const BSKY_SERVICE = 'https://bsky.social'#export const BSKY_SERVICE = 'https://${host}'#g" $f sed -i "s#export const BSKY_SERVICE_DID = 'did:web:bsky.social'#export const BSKY_SERVICE_DID = 'did:web:${host}'#g" $f sed -i "s#export const PUBLIC_BSKY_SERVICE = 'https://public.api.bsky.app'#export const PUBLIC_BSKY_SERVICE = 'https://bsky.${host}'#g" $f sed -i "s#export const PUBLIC_APPVIEW = 'https://api.bsky.app'#export const PUBLIC_APPVIEW = 'https://bsky.${host}'#g" $f sed -i "s#export const PUBLIC_APPVIEW_DID = 'did:web:api.bsky.app'#export const PUBLIC_APPVIEW_DID = 'did:web:bsky.${host}'#g" $f # Disable external services (CORS fix) f=$dt/state/geolocation/const.ts curl -sL https://raw.githubusercontent.com/bluesky-social/social-app/refs/heads/main/src/state/geolocation/const.ts -o $f cat > $f << 'GEOEOF' import {type GeolocationStatus} from '#/state/geolocation/types' import {BAPP_CONFIG_DEV_URL, IS_DEV} from '#/env' import {type Device} from '#/storage' export const IPCC_URL = `https://bsky.app/ipcc` // Disabled for self-hosted environment to avoid CORS errors export const BAPP_CONFIG_URL_PROD = null export const BAPP_CONFIG_URL = null export const GEOLOCATION_CONFIG_URL = BAPP_CONFIG_URL export const DEFAULT_GEOLOCATION_CONFIG: Device['geolocation'] = { countryCode: undefined, regionCode: undefined, ageRestrictedGeos: [], ageBlockedGeos: [], } export const DEFAULT_GEOLOCATION_STATUS: GeolocationStatus = { countryCode: undefined, regionCode: undefined, isAgeRestrictedGeo: false, isAgeBlockedGeo: false, } GEOEOF # Add null check to geolocation config.ts to prevent fetch(null) errors f=$dt/state/geolocation/config.ts curl -sL https://raw.githubusercontent.com/bluesky-social/social-app/refs/heads/main/src/state/geolocation/config.ts -o $f # Add null check at the beginning of getGeolocationConfig function (after line with 'url: string,') sed -i "s/): Promise {/): Promise {\n if (!url) return undefined/" $f # Disable Statsig (CORS fix) f=$dt/lib/statsig/statsig.tsx sed -i "s#api: 'https://events.bsky.app/v2'#api: '' // Disabled for self-hosted#g" $f # Disable SDK initialization to prevent statsigapi.net connections sed -i "s#const SDK_KEY = 'client-SXJakO39w9vIhl3D44u8UupyzFl4oZ2qPIkjwcvuPsV'#const SDK_KEY = '' // Disabled for self-hosted#g" $f f=$dt/view/icons/Logotype.tsx o=$d/icons/Logotype.tsx cp -rf $o $f f=$dt/view/com/util/UserAvatar.tsx curl -sL https://raw.githubusercontent.com/bluesky-social/social-app/refs/heads/main/src/view/com/util/UserAvatar.tsx -o $f sed -i "s#/img/avatar/plain/#https://cdn.web.syu.is/img/avatar/plain/#g" $f sed -i "s#/img/avatar_thumbnail/plain/#https://bsky.${host}/img/avatar/plain/#g" $f sed -i "s#source={{uri: avatar}}#source={{ uri: hackModifyThumbnailPath(avatar, 1 > 0), }}#g" $f curl -sL https://raw.githubusercontent.com/bluesky-social/social-app/refs/heads/main/src/lib/strings/url-helpers.ts -o $dt/lib/strings/url-helpers.ts sed -i "s#https://go.web.syu.is/redirect?u=\${encodeURIComponent(url)}#\${url}#g" $dt/lib/strings/url-helpers.ts grep -R $did_admin .|cut -d : -f 1|sort -u|xargs sed -i "s/${did_admin}/${did}/g" } function at-repos-atproto-service-bsky-api-patch() { # https://github.com/itaru2622/bluesky-selfhost-env/blob/master/patching/105-atproto-services-for-docker.diff f=$d/repos/atproto/services/bsky/api.js curl -sL https://raw.githubusercontent.com/bluesky-social/atproto/refs/heads/main/services/bsky/api.js -o $f d_=$d/repos/atproto p_=$d/patching/4367-atproto-services-bsky-api.diff echo "applying patch: under ${f} for ${p_}" pushd ${d_} patch -p1 < ${p_} popd } function at-repos-atproto-service-pds-index-patch() { f=$d/repos/atproto/services/pds/index.js curl -sL https://raw.githubusercontent.com/bluesky-social/atproto/refs/heads/main/services/pds/index.js -o $f d_=$d/repos/atproto p_=$d/patching/4367-atproto-services-pds-index.diff echo "applying patch: under ${f} for ${p_}" pushd ${d_} patch -p1 < ${p_} popd } function at-repos-social-app-agent-patch() { f=$d/repos/social-app/src/state/session/agent.ts p_=$d/patching/8980-social-app-disable-proxy.diff d_=$d/repos/social-app echo "applying patch: under ${f} for ${p_}" pushd ${d_} patch -p1 < ${p_} popd } function at-repos-social-app-disable-external-services-patch() { f=$d/repos/social-app/src/state/geolocation/const.ts p_=$d/patching/8980-social-app-disable-external-services.diff d_=$d/repos/social-app echo "applying patch: under ${f} for ${p_}" pushd ${d_} patch -p1 < ${p_} popd } function at-repos-atproto-service-ozone-api-patch() { f=$d/repos/atproto/services/ozone/api.js d_=$d/repos/atproto p_=$d/patching/130-atproto-ozone-enable-daemon-v2.patch echo "applying patch: under ${f} for ${p_}" pushd ${d_} patch -p1 < ${p_} popd } function at-repos-ozone-patch() { #DOMAIN=syu.is cd $d/repos d_=$d/repos/ozone rm -rf ${d_} p_=$d/patching/120-ozone-runtimeEnvVars.diff git clone https://github.com/bluesky-social/ozone cd ${d_} pushd ${d_} echo "applying patch: under ${d_} for ${p_}" patch -p1 < ${p_} popd p_=$d/patching/122-ozone-enable-daemon.diff echo "applying patch: under ${d_} for ${p_}" pushd ${d_} patch -p1 < ${p_} popd p_=$d/patching/121-ozone-constants-fix.patch echo "applying patch: under ${d_} for ${p_}" pushd ${d_} patch -p1 < ${p_} || true popd } function at-repos-build-docker-atproto() { cd $d docker image prune -a if [ -z "$1" ];then for ((i=1; i<=${#services}; i++)); do service=${services[$i]} docker compose build --no-cache $service done else docker compose build --no-cache $1 fi } function at-repos-push-reset() { docker restart registry docker stop registry docker rm registry docker volume rm registry-data 2>/dev/null || true docker run -d -p ${dport}:${dport} --name registry \ --restart=always \ -v registry-data:/var/lib/registry \ registry:2 sleep 3 docker run -d -p ${dport}:${dport} --name registry --restart=always registry:2 } function at-repos-push-docker() { if [ -z "$1" ];then for ((i=1; i<=${#services}; i++)); do service=${services[$i]} docker tag at-${service}:latest localhost:${dport}/${service}:latest docker push localhost:${dport}/${service}:latest if [ "$service" = "ozone" ];then docker tag at-${service}:latest localhost:${dport}/${service}-web:latest docker push localhost:${dport}/${service}-web:latest fi done else docker tag at-${1}:latest localhost:${dport}/${1}:latest docker push localhost:${dport}/${1}:latest fi } function at-repos-pull-docker() { cd $d docker image prune -a docker compose up -d --pull always } at-repos-env case "`cat /etc/hostname`" in at) at-repos-pull-docker exit ;; *) at-repos-push-reset at-repos-clone at-repos-pull at-repos-social-app-icon at-repos-social-app-icon-origin at-repos-social-app-avatar-write at-repos-social-app-agent-patch at-repos-social-app-disable-external-services-patch at-repos-atproto-service-bsky-api-patch at-repos-atproto-service-pds-index-patch at-repos-atproto-service-ozone-api-patch at-repos-ozone-patch if [ -n "$1" ];then at-repos-build-docker-atproto $1 at-repos-push-docker $1 exit fi at-repos-build-docker-atproto at-repos-push-docker cd $d; docker compose down ;; esac