add social-app-custom
This commit is contained in:
97
README.md
97
README.md
@@ -1,11 +1,12 @@
|
|||||||
# at
|
# at
|
||||||
|
|
||||||
https://github.com/bluesky-social/atproto
|
- https://github.com/bluesky-social/atproto
|
||||||
|
- https://github.com/bluesky-social/atproto/discussions/2026
|
||||||
|
|
||||||
|word|name|example|
|
|word|name|example|
|
||||||
|---|---|---|
|
|---|---|---|
|
||||||
|at|uri|at://ai.syu.is|
|
|at|uri|at://example.com|
|
||||||
|@|user|@ai.syu.is|
|
|@|user|@example.com|
|
||||||
|[at]proto|repo|`git@github.com:bluesky-social/atproto`|
|
|[at]proto|repo|`git@github.com:bluesky-social/atproto`|
|
||||||
|[at]mosphere|system|pds, bsky(appview), ozone, bgs, plc|
|
|[at]mosphere|system|pds, bsky(appview), ozone, bgs, plc|
|
||||||
|[a]uthenticated [t]ransfer|protocol|[did](https://www.w3.org/TR/did-core/)|
|
|[a]uthenticated [t]ransfer|protocol|[did](https://www.w3.org/TR/did-core/)|
|
||||||
@@ -14,16 +15,13 @@ https://github.com/bluesky-social/atproto
|
|||||||
|
|
||||||
## account
|
## account
|
||||||
|
|
||||||
[@ai.syu.is](https://web.syu.is/profile/ai.syu.is)
|
- [ai@syu.is](https://syu.is/profile/did:plc:6qyecktefllvenje24fcxnie)
|
||||||
|
- [ai@bsky.app](https://bsky.app/profile/did:plc:6qyecktefllvenje24fcxnie)
|
||||||
- https://plc.syu.is/did:plc:6qyecktefllvenje24fcxnie
|
- https://plc.syu.is/did:plc:6qyecktefllvenje24fcxnie
|
||||||
- https://plc.directory/did:plc:ytvoptig4ddshmwdsjmhtcym
|
- https://plc.directory/did:plc:6qyecktefllvenje24fcxnie
|
||||||
|
|
||||||
[@yui.syui.ai](https://bsky.app/profile/did:plc:4hqjfn7m6n5hno3doamuhgef)
|
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
$ curl -sL syu.is/xrpc/_health
|
$ curl -sL syu.is/xrpc/_health
|
||||||
{"version":"0.4.65"}
|
|
||||||
|
|
||||||
# latest
|
# latest
|
||||||
# https://github.com/bluesky-social/atproto/blob/main/packages/pds/package.json
|
# https://github.com/bluesky-social/atproto/blob/main/packages/pds/package.json
|
||||||
@@ -31,10 +29,11 @@ $ curl -sL https://raw.githubusercontent.com/bluesky-social/atproto/refs/heads/m
|
|||||||
```
|
```
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
$ curl -sL "syu.is/xrpc/com.atproto.repo.describeRepo?repo=ai.syu.is" |jq -r .did
|
$ handle=ai.syui.ai
|
||||||
|
$ curl -sL "syu.is/xrpc/com.atproto.repo.describeRepo?repo=${handle}" |jq -r .did
|
||||||
did:plc:6qyecktefllvenje24fcxnie
|
did:plc:6qyecktefllvenje24fcxnie
|
||||||
|
|
||||||
$ curl -sL "syu.is/xrpc/com.atproto.repo.listRecords?repo=ai.syu.is&collection=app.bsky.feed.post&reverse=true&limit=1"
|
$ curl -sL "syu.is/xrpc/com.atproto.repo.listRecords?repo=${handle}&collection=app.bsky.feed.post&reverse=true&limit=1"
|
||||||
{"records":[{"uri":"at://did:plc:6qyecktefllvenje24fcxnie/app.bsky.feed.post/3l6s2riuouk2j","cid":"bafyreibjohl7va4upkibw5twaxdd4jg3l6rmfatu4dpjjfd5xkb2ijtlx4","value":{"text":"hello","$type":"app.bsky.feed.post","langs":["ja"],"createdAt":"2024-10-18T13:21:39.809Z"}}],"cursor":"3l6s2riuouk2j"}
|
{"records":[{"uri":"at://did:plc:6qyecktefllvenje24fcxnie/app.bsky.feed.post/3l6s2riuouk2j","cid":"bafyreibjohl7va4upkibw5twaxdd4jg3l6rmfatu4dpjjfd5xkb2ijtlx4","value":{"text":"hello","$type":"app.bsky.feed.post","langs":["ja"],"createdAt":"2024-10-18T13:21:39.809Z"}}],"cursor":"3l6s2riuouk2j"}
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -46,80 +45,4 @@ $ curl -sL "syu.is/xrpc/com.atproto.repo.listRecords?repo=ai.syu.is&collection=a
|
|||||||
- https://feed.syu.is/xrpc/app.bsky.feed.getFeedSkeleton?feed=at://did:plc:4hqjfn7m6n5hno3doamuhgef/app.bsky.feed.generator/cmd
|
- https://feed.syu.is/xrpc/app.bsky.feed.getFeedSkeleton?feed=at://did:plc:4hqjfn7m6n5hno3doamuhgef/app.bsky.feed.generator/cmd
|
||||||
- https://desc.syu.is/xrpc/app.bsky.feed.getFeedSkeleton?feed=at://did:plc:6qyecktefllvenje24fcxnie/app.bsky.feed.generator/cmd
|
- https://desc.syu.is/xrpc/app.bsky.feed.getFeedSkeleton?feed=at://did:plc:6qyecktefllvenje24fcxnie/app.bsky.feed.generator/cmd
|
||||||
|
|
||||||
## link
|
|
||||||
|
|
||||||
- https://github.com/bluesky-social/atproto
|
|
||||||
- https://github.com/itaru2622/bluesky-selfhost-env
|
|
||||||
- https://github.com/bluesky-social/atproto/discussions/2026
|
|
||||||
|
|
||||||
## self-host
|
|
||||||
|
|
||||||
currently, bsky and bsync require patches to function properly. additionally, social-app is not displaying avatars. for components that are not working, it's recommended to use [itaru2622/bluesky-selfhost-env](https://github.com/itaru2622/bluesky-selfhost-env). this repository provides an environment for self-hosting bluesky.
|
|
||||||
|
|
||||||
- bsky = appview
|
|
||||||
- ozone = mod
|
|
||||||
|
|
||||||
|name|service|patch|
|
|
||||||
|---|---|---|
|
|
||||||
|pds|https://github.com/bluesky-social/atproto/blob/main/services/pds/Dockerfile||
|
|
||||||
|bsky|https://github.com/bluesky-social/atproto/blob/main/services/bsky/Dockerfile|[itaru2622/bluesky-atproto-bsky](https://github.com/itaru2622/bluesky-selfhost-env/blob/master/patching/105-atproto-services-for-docker.diff)|
|
|
||||||
|bsync|https://github.com/bluesky-social/atproto/blob/main/services/bsync/Dockerfile||
|
|
||||||
|ozone|https://github.com/bluesky-social/atproto/blob/main/services/ozone/Dockerfile||
|
|
||||||
|plc|https://github.com/did-method-plc/did-method-plc/tree/main/packages/server||
|
|
||||||
|bgs|https://github.com/bluesky-social/indigo/tree/main/cmd/bigsky||
|
|
||||||
|feed|https://github.com/bluesky-social/feed-generator||
|
|
||||||
|web|https://github.com/bluesky-social/social-app|[bluesky-selfhost-env](https://github.com/itaru2622/bluesky-selfhost-env/blob/master/patching/160-social-app-disable-hackModifyThumbnailPath.diff)|
|
|
||||||
|
|
||||||
```sh
|
|
||||||
# BSKY_IMG_URI_ENDPOINT, BSKY_BLOB_CACHE_LOC
|
|
||||||
# avatar link example
|
|
||||||
1. https://appview.${host}/img/avatar/plain/${did}/${cid}@jpeg
|
|
||||||
2. https://${host}/xrpc/com.atproto.sync.getBlob?did=${did}&cid=${cid}
|
|
||||||
```
|
|
||||||
|
|
||||||
docker compose will not be published unless you write ports. it is only valid internally. add ports only for what you want to publish.
|
|
||||||
|
|
||||||
## api
|
|
||||||
|
|
||||||
```sh
|
|
||||||
# create account
|
|
||||||
url=https://${pds}/xrpc/com.atproto.server.createAccount
|
|
||||||
json="{\"email\": \"$email\", \"handle\": \"$handle\", \"password\": \"$password\"}"
|
|
||||||
curl -X POST -H "Content-Type: application/json" -d $json -sL $url
|
|
||||||
```
|
|
||||||
|
|
||||||
change `src/pds/handle` to use a name of 3 characters or less. also, you cannot create an account with a name of 3 characters or less from social-app (web client). please create it from api.
|
|
||||||
|
|
||||||
- [/atproto/packages/pds/src/handle/index.ts](https://github.com/bluesky-social/atproto/blame/d4d5a6edba972c0e9976289bde8bc0b42ff547ca/packages/pds/src/handle/index.ts#L86-L88)
|
|
||||||
|
|
||||||
```sh
|
|
||||||
# invite code
|
|
||||||
admin_password=xxx
|
|
||||||
url=https://$host/xrpc/com.atproto.server.createInviteCode
|
|
||||||
json="{\"useCount\":1}"
|
|
||||||
curl -X POST -u admin:${admin_password} -H "Content-Type: application/json" -d "$json" -sL $url
|
|
||||||
```
|
|
||||||
|
|
||||||
## oauth
|
|
||||||
|
|
||||||
```sh
|
|
||||||
# https://github.com/bluesky-social/cookbook/tree/main/python-oauth-web-app
|
|
||||||
$ cd ./repos/cookbook/python-oauth-web-app
|
|
||||||
$ rye sync
|
|
||||||
$ rye run python3 -c 'import secrets; print(secrets.token_hex())'|xargs echo FLASK_SECRET_KEY|tr -d ' ' >> .env
|
|
||||||
$ rye run python3 generate_jwk.py |xargs echo FLASK_CLIENT_SECRET_JWK|tr -d ' ' >> .env
|
|
||||||
$ cat .env
|
|
||||||
$ rye run flask run
|
|
||||||
```
|
|
||||||
|
|
||||||
please access `127.0.0.1:5000`. it may not work if you use localhost.
|
|
||||||
|
|
||||||
also, oauth doesn't work on localhost. use [ngrok](https://ngrok.com/), [tailscale](https://tailscale.com/), [cloudflare](https://github.com/cloudflare/cloudflared).
|
|
||||||
|
|
||||||
```sh
|
|
||||||
$ ngrok http http://localhost:5000
|
|
||||||
```
|
|
||||||
|
|
||||||
```sh
|
|
||||||
$ cloudflared tunnel --url http://localhost:5000
|
|
||||||
```
|
|
||||||
|
|||||||
@@ -48,8 +48,7 @@ services:
|
|||||||
- ./envs/pds
|
- ./envs/pds
|
||||||
volumes:
|
volumes:
|
||||||
- ./data/pds/:/data/
|
- ./data/pds/:/data/
|
||||||
- ./repos/atproto/services/pds/index.js:/app/run-pds.js
|
command: node --enable-source-maps index.js
|
||||||
command: ['node', '--enable-source-maps', '/app/run-pds.js']
|
|
||||||
depends_on:
|
depends_on:
|
||||||
database:
|
database:
|
||||||
condition: service_healthy
|
condition: service_healthy
|
||||||
@@ -66,8 +65,7 @@ services:
|
|||||||
user: root
|
user: root
|
||||||
volumes:
|
volumes:
|
||||||
- ./data/bsky/:/data/
|
- ./data/bsky/:/data/
|
||||||
- ./repos/atproto/services/bsky/api.js:/app/run-bsky.js
|
command: node --enable-source-maps api.js
|
||||||
command: ['node', '--enable-source-maps', '/app/run-bsky.js']
|
|
||||||
depends_on:
|
depends_on:
|
||||||
database:
|
database:
|
||||||
condition: service_healthy
|
condition: service_healthy
|
||||||
|
|||||||
4
envs/bgs
4
envs/bgs
@@ -2,5 +2,5 @@ DATABASE_URL=postgres://postgres:postgres@database/bgs
|
|||||||
CARSTORE_DATABASE_URL=postgres://postgres:postgres@database/carstore
|
CARSTORE_DATABASE_URL=postgres://postgres:postgres@database/carstore
|
||||||
DATA_DIR=/data
|
DATA_DIR=/data
|
||||||
ATP_PLC_HOST=https://plc.${host}
|
ATP_PLC_HOST=https://plc.${host}
|
||||||
|
BGS_NEW_PDS_PER_DAY_LIMIT=1000
|
||||||
BGS_ADMIN_KEY
|
BGS_ADMIN_KEY=
|
||||||
|
|||||||
2
envs/pds
2
envs/pds
@@ -6,6 +6,8 @@ PDS_BLOBSTORE_DISK_LOCATION=/data/img/static
|
|||||||
PDS_BSKY_APP_VIEW_DID=did:web:bsky.${host}
|
PDS_BSKY_APP_VIEW_DID=did:web:bsky.${host}
|
||||||
PDS_BSKY_APP_VIEW_URL=https://bsky.${host}
|
PDS_BSKY_APP_VIEW_URL=https://bsky.${host}
|
||||||
PDS_CRAWLERS=https://bgs.${host}
|
PDS_CRAWLERS=https://bgs.${host}
|
||||||
|
PDS_SEQUENCER_ENABLED=true
|
||||||
|
PDS_SEQUENCER_DB_LOCATION=/data/sequencer.sqlite
|
||||||
PDS_DEV_MODE=true
|
PDS_DEV_MODE=true
|
||||||
PDS_DID_PLC_URL=https://plc.${host}
|
PDS_DID_PLC_URL=https://plc.${host}
|
||||||
PDS_ENABLE_DID_DOC_WITH_SESSION=true
|
PDS_ENABLE_DID_DOC_WITH_SESSION=true
|
||||||
|
|||||||
131
install.zsh
131
install.zsh
@@ -18,6 +18,8 @@ function at-repos-env() {
|
|||||||
https://github.com/bluesky-social/ozone
|
https://github.com/bluesky-social/ozone
|
||||||
https://github.com/bluesky-social/jetstream
|
https://github.com/bluesky-social/jetstream
|
||||||
)
|
)
|
||||||
|
services=( bsky plc pds jetstream bgs ozone social-app )
|
||||||
|
img=( bsky plc pds jetstream bgs ozone social-app ozone-web ozone-daemon )
|
||||||
d=${0:a:h}
|
d=${0:a:h}
|
||||||
dh=${0:a:h:h}
|
dh=${0:a:h:h}
|
||||||
name=${host%%.*}
|
name=${host%%.*}
|
||||||
@@ -108,7 +110,53 @@ function at-repos-social-app-avatar-write() {
|
|||||||
grep -R syu.is .|cut -d : -f 1|sort -u|xargs sed -i "s/syu.is/${host}/g"
|
grep -R syu.is .|cut -d : -f 1|sort -u|xargs sed -i "s/syu.is/${host}/g"
|
||||||
grep -R web.syu.is .|cut -d : -f 1|sort -u|xargs sed -i "s/web.syu.is/web.${host}/g"
|
grep -R web.syu.is .|cut -d : -f 1|sort -u|xargs sed -i "s/web.syu.is/web.${host}/g"
|
||||||
f=$dt/lib/constants.ts
|
f=$dt/lib/constants.ts
|
||||||
sed -i "s/public.api.web/bsky/g" $f
|
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<Device\['geolocation'\]> {/): Promise<Device['geolocation']> {\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
|
f=$dt/view/icons/Logotype.tsx
|
||||||
o=$d/icons/Logotype.tsx
|
o=$d/icons/Logotype.tsx
|
||||||
cp -rf $o $f
|
cp -rf $o $f
|
||||||
@@ -156,6 +204,16 @@ function at-repos-social-app-agent-patch() {
|
|||||||
popd
|
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-ozone-patch() {
|
function at-repos-ozone-patch() {
|
||||||
#DOMAIN=syu.is
|
#DOMAIN=syu.is
|
||||||
cd $d/repos
|
cd $d/repos
|
||||||
@@ -180,48 +238,40 @@ function at-repos-ozone-patch() {
|
|||||||
function at-repos-build-docker-atproto() {
|
function at-repos-build-docker-atproto() {
|
||||||
cd $d
|
cd $d
|
||||||
docker image prune -a
|
docker image prune -a
|
||||||
docker compose build --no-cache bsky plc pds jetstream bgs ozone
|
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-build-docker-social() {
|
function at-repos-push-reset() {
|
||||||
cd $d
|
|
||||||
docker compose build --no-cache social-app
|
|
||||||
}
|
|
||||||
|
|
||||||
function at-repos-build-docker-tag() {
|
|
||||||
docker restart registry
|
docker restart registry
|
||||||
docker stop registry
|
docker stop registry
|
||||||
docker rm registry
|
docker rm registry
|
||||||
docker volume rm registry-data 2>/dev/null || true
|
docker volume rm registry-data 2>/dev/null || true
|
||||||
docker run -d -p 5000:5000 --name registry \
|
docker run -d -p ${dport}:${dport} --name registry \
|
||||||
--restart=always \
|
--restart=always \
|
||||||
-v registry-data:/var/lib/registry \
|
-v registry-data:/var/lib/registry \
|
||||||
registry:2
|
registry:2
|
||||||
sleep 3
|
sleep 3
|
||||||
|
|
||||||
docker run -d -p ${dport}:${dport} --name registry --restart=always registry:2
|
docker run -d -p ${dport}:${dport} --name registry --restart=always registry:2
|
||||||
docker tag at-pds:latest localhost:${dport}/pds:latest
|
}
|
||||||
docker tag at-ozone-web:latest localhost:${dport}/ozone-web:latest
|
|
||||||
docker tag at-bgs:latest localhost:${dport}/bgs:latest
|
|
||||||
docker tag at-jetstream:latest localhost:${dport}/jetstream:latest
|
|
||||||
docker tag at-bsky:latest localhost:${dport}/bsky:latest
|
|
||||||
docker tag at-ozone-daemon:latest localhost:${dport}/ozone-daemon:latest
|
|
||||||
docker tag at-ozone:latest localhost:${dport}/ozone:latest
|
|
||||||
docker tag at-plc:latest localhost:${dport}/plc:latest
|
|
||||||
docker tag at-social-app:latest localhost:${dport}/social-app:latest
|
|
||||||
|
|
||||||
docker push localhost:${dport}/pds:latest
|
function at-repos-push-docker() {
|
||||||
docker push localhost:${dport}/ozone-web:latest
|
if [ -z "$1" ];then
|
||||||
docker push localhost:${dport}/bgs:latest
|
for ((i=1; i<=${#img}; i++)); do
|
||||||
docker push localhost:${dport}/jetstream:latest
|
img=${imgs[$i]}
|
||||||
docker push localhost:${dport}/bsky:latest
|
docker tag at-${img}:latest localhost:${dport}/${img}:latest
|
||||||
docker push localhost:${dport}/ozone-daemon:latest
|
docker push localhost:${dport}/${img}:latest
|
||||||
docker push localhost:${dport}/ozone:latest
|
done
|
||||||
docker push localhost:${dport}/plc:latest
|
else
|
||||||
docker push localhost:${dport}/social-app:latest
|
docker tag at-${1}:latest localhost:${dport}/${1}:latest
|
||||||
|
docker push localhost:${dport}/${1}:latest
|
||||||
cd $d
|
fi
|
||||||
docker compose down
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function at-repos-pull-docker() {
|
function at-repos-pull-docker() {
|
||||||
@@ -230,24 +280,37 @@ function at-repos-pull-docker() {
|
|||||||
docker compose up -d --pull always
|
docker compose up -d --pull always
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function at-origin-social-app() {
|
||||||
|
cp -rf $d/social-app-custom $d/repos/social-app
|
||||||
|
}
|
||||||
|
|
||||||
at-repos-env
|
at-repos-env
|
||||||
|
|
||||||
case "`cat /etc/hostname`" in
|
case "`cat /etc/hostname`" in
|
||||||
at)
|
at)
|
||||||
at-repos-pull-docker
|
at-repos-pull-docker
|
||||||
|
exit
|
||||||
;;
|
;;
|
||||||
*)
|
*)
|
||||||
|
at-repos-push-reset
|
||||||
at-repos-clone
|
at-repos-clone
|
||||||
at-repos-pull
|
at-repos-pull
|
||||||
at-repos-social-app-icon
|
at-repos-social-app-icon
|
||||||
at-repos-social-app-icon-origin
|
at-repos-social-app-icon-origin
|
||||||
at-repos-social-app-avatar-write
|
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-bsky-api-patch
|
||||||
at-repos-atproto-service-pds-index-patch
|
at-repos-atproto-service-pds-index-patch
|
||||||
at-repos-social-app-agent-patch
|
|
||||||
at-repos-ozone-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-build-docker-atproto
|
||||||
at-repos-build-docker-social
|
at-repos-push-docker
|
||||||
|
cd $d; docker compose down
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
17
patching/8980-social-app-disable-external-services.diff
Normal file
17
patching/8980-social-app-disable-external-services.diff
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
--- a/src/state/geolocation/const.ts
|
||||||
|
+++ b/src/state/geolocation/const.ts
|
||||||
|
@@ -3,9 +3,10 @@ import {BAPP_CONFIG_DEV_URL, IS_DEV} from '#/env'
|
||||||
|
import {type Device} from '#/storage'
|
||||||
|
|
||||||
|
export const IPCC_URL = `https://bsky.app/ipcc`
|
||||||
|
-export const BAPP_CONFIG_URL_PROD = `https://ip.bsky.app/config`
|
||||||
|
-export const BAPP_CONFIG_URL = IS_DEV
|
||||||
|
- ? (BAPP_CONFIG_DEV_URL ?? BAPP_CONFIG_URL_PROD)
|
||||||
|
- : BAPP_CONFIG_URL_PROD
|
||||||
|
+// Disabled for self-hosted environment to avoid CORS errors
|
||||||
|
+// export const BAPP_CONFIG_URL_PROD = `https://ip.bsky.app/config`
|
||||||
|
+// export const BAPP_CONFIG_URL = IS_DEV
|
||||||
|
+// ? (BAPP_CONFIG_DEV_URL ?? BAPP_CONFIG_URL_PROD)
|
||||||
|
+// : BAPP_CONFIG_URL_PROD
|
||||||
|
+export const BAPP_CONFIG_URL = null
|
||||||
|
export const GEOLOCATION_CONFIG_URL = BAPP_CONFIG_URL
|
||||||
0
social-app-custom/.keep
Normal file
0
social-app-custom/.keep
Normal file
134
social-app-custom/AppInfo.tsx
Normal file
134
social-app-custom/AppInfo.tsx
Normal file
@@ -0,0 +1,134 @@
|
|||||||
|
import React from 'react'
|
||||||
|
import {View, Text, StyleSheet, Pressable, Linking} from 'react-native'
|
||||||
|
|
||||||
|
interface AppInfoProps {
|
||||||
|
onLinkPress?: (url: string) => void
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function AppInfo({onLinkPress}: AppInfoProps) {
|
||||||
|
const handleLinkPress = (url: string) => {
|
||||||
|
if (onLinkPress) {
|
||||||
|
onLinkPress(url)
|
||||||
|
} else {
|
||||||
|
Linking.openURL(url)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<View style={styles.container}>
|
||||||
|
<View style={styles.section}>
|
||||||
|
<Text style={styles.sectionTitle}>About This App</Text>
|
||||||
|
<Text style={styles.paragraph}>
|
||||||
|
This is a customized AT Protocol social networking client. It allows you to
|
||||||
|
connect to any Personal Data Server (PDS) and participate in the decentralized
|
||||||
|
social network.
|
||||||
|
</Text>
|
||||||
|
</View>
|
||||||
|
|
||||||
|
<View style={styles.section}>
|
||||||
|
<Text style={styles.sectionTitle}>Key Features</Text>
|
||||||
|
<View style={styles.list}>
|
||||||
|
<Text style={styles.listItem}>• Connect to any AT Protocol PDS</Text>
|
||||||
|
<Text style={styles.listItem}>• Post text, images, and videos</Text>
|
||||||
|
<Text style={styles.listItem}>• Follow users and view timelines</Text>
|
||||||
|
<Text style={styles.listItem}>• Customize feeds and moderation settings</Text>
|
||||||
|
<Text style={styles.listItem}>• Direct messaging support</Text>
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
|
||||||
|
<View style={styles.section}>
|
||||||
|
<Text style={styles.sectionTitle}>Open Source</Text>
|
||||||
|
<Text style={styles.paragraph}>
|
||||||
|
This application is based on the Bluesky social-app, licensed under the MIT
|
||||||
|
License. The original source code is available at:
|
||||||
|
</Text>
|
||||||
|
<Pressable
|
||||||
|
onPress={() =>
|
||||||
|
handleLinkPress('https://github.com/bluesky-social/social-app')
|
||||||
|
}>
|
||||||
|
<Text style={styles.link}>github.com/bluesky-social/social-app</Text>
|
||||||
|
</Pressable>
|
||||||
|
</View>
|
||||||
|
|
||||||
|
<View style={styles.section}>
|
||||||
|
<Text style={styles.sectionTitle}>AT Protocol</Text>
|
||||||
|
<Text style={styles.paragraph}>
|
||||||
|
This app uses the AT Protocol (Authenticated Transfer Protocol), an open and
|
||||||
|
decentralized standard for social applications.
|
||||||
|
</Text>
|
||||||
|
<Pressable onPress={() => handleLinkPress('https://atproto.com')}>
|
||||||
|
<Text style={styles.link}>atproto.com</Text>
|
||||||
|
</Pressable>
|
||||||
|
</View>
|
||||||
|
|
||||||
|
<View style={styles.section}>
|
||||||
|
<Text style={styles.sectionTitle}>License</Text>
|
||||||
|
<Text style={styles.paragraph}>
|
||||||
|
Copyright 2023–2025 Bluesky Social PBC
|
||||||
|
</Text>
|
||||||
|
<Text style={styles.paragraph}>
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software.
|
||||||
|
</Text>
|
||||||
|
<Text style={styles.paragraph}>
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND.
|
||||||
|
</Text>
|
||||||
|
</View>
|
||||||
|
|
||||||
|
<View style={styles.section}>
|
||||||
|
<Text style={styles.sectionTitle}>Contact</Text>
|
||||||
|
<Pressable onPress={() => handleLinkPress('https://syu.is')}>
|
||||||
|
<Text style={styles.link}>https://syu.is</Text>
|
||||||
|
</Pressable>
|
||||||
|
</View>
|
||||||
|
|
||||||
|
<View style={styles.section}>
|
||||||
|
<Text style={styles.versionText}>Version 1.0.0</Text>
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
const styles = StyleSheet.create({
|
||||||
|
container: {
|
||||||
|
flex: 1,
|
||||||
|
},
|
||||||
|
section: {
|
||||||
|
marginBottom: 24,
|
||||||
|
},
|
||||||
|
sectionTitle: {
|
||||||
|
fontSize: 20,
|
||||||
|
fontWeight: '600',
|
||||||
|
color: '#1d1d1f',
|
||||||
|
marginBottom: 12,
|
||||||
|
},
|
||||||
|
paragraph: {
|
||||||
|
fontSize: 15,
|
||||||
|
lineHeight: 22,
|
||||||
|
color: '#3a3a3c',
|
||||||
|
marginBottom: 8,
|
||||||
|
},
|
||||||
|
list: {
|
||||||
|
marginLeft: 8,
|
||||||
|
marginTop: 8,
|
||||||
|
},
|
||||||
|
listItem: {
|
||||||
|
fontSize: 15,
|
||||||
|
lineHeight: 24,
|
||||||
|
color: '#3a3a3c',
|
||||||
|
},
|
||||||
|
link: {
|
||||||
|
fontSize: 15,
|
||||||
|
color: '#007aff',
|
||||||
|
textDecorationLine: 'underline',
|
||||||
|
marginTop: 8,
|
||||||
|
},
|
||||||
|
versionText: {
|
||||||
|
fontSize: 13,
|
||||||
|
color: '#8e8e93',
|
||||||
|
fontStyle: 'italic',
|
||||||
|
},
|
||||||
|
})
|
||||||
95
social-app-custom/LicenseNotice.tsx
Normal file
95
social-app-custom/LicenseNotice.tsx
Normal file
@@ -0,0 +1,95 @@
|
|||||||
|
import React from 'react'
|
||||||
|
import {View, Text, StyleSheet, Pressable, Linking} from 'react-native'
|
||||||
|
|
||||||
|
export default function LicenseNotice() {
|
||||||
|
return (
|
||||||
|
<View style={styles.container}>
|
||||||
|
<Text style={styles.title}>Open Source Licenses</Text>
|
||||||
|
|
||||||
|
<View style={styles.section}>
|
||||||
|
<Text style={styles.projectName}>Bluesky Social App</Text>
|
||||||
|
<Text style={styles.license}>MIT License</Text>
|
||||||
|
<Text style={styles.copyright}>Copyright 2023–2025 Bluesky Social PBC</Text>
|
||||||
|
|
||||||
|
<Text style={styles.licenseText}>
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
</Text>
|
||||||
|
|
||||||
|
<Text style={styles.licenseText}>
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
</Text>
|
||||||
|
|
||||||
|
<Text style={styles.licenseText}>
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
|
</Text>
|
||||||
|
|
||||||
|
<Pressable
|
||||||
|
onPress={() =>
|
||||||
|
Linking.openURL('https://github.com/bluesky-social/social-app')
|
||||||
|
}>
|
||||||
|
<Text style={styles.link}>View Source Code</Text>
|
||||||
|
</Pressable>
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
const styles = StyleSheet.create({
|
||||||
|
container: {
|
||||||
|
flex: 1,
|
||||||
|
padding: 16,
|
||||||
|
},
|
||||||
|
title: {
|
||||||
|
fontSize: 24,
|
||||||
|
fontWeight: 'bold',
|
||||||
|
marginBottom: 20,
|
||||||
|
color: '#1d1d1f',
|
||||||
|
},
|
||||||
|
section: {
|
||||||
|
marginBottom: 24,
|
||||||
|
padding: 16,
|
||||||
|
backgroundColor: '#f5f5f7',
|
||||||
|
borderRadius: 8,
|
||||||
|
},
|
||||||
|
projectName: {
|
||||||
|
fontSize: 18,
|
||||||
|
fontWeight: '600',
|
||||||
|
marginBottom: 8,
|
||||||
|
color: '#1d1d1f',
|
||||||
|
},
|
||||||
|
license: {
|
||||||
|
fontSize: 14,
|
||||||
|
fontWeight: '500',
|
||||||
|
color: '#007aff',
|
||||||
|
marginBottom: 4,
|
||||||
|
},
|
||||||
|
copyright: {
|
||||||
|
fontSize: 13,
|
||||||
|
color: '#3a3a3c',
|
||||||
|
marginBottom: 12,
|
||||||
|
},
|
||||||
|
licenseText: {
|
||||||
|
fontSize: 12,
|
||||||
|
lineHeight: 18,
|
||||||
|
color: '#3a3a3c',
|
||||||
|
marginBottom: 12,
|
||||||
|
},
|
||||||
|
link: {
|
||||||
|
fontSize: 14,
|
||||||
|
color: '#007aff',
|
||||||
|
textDecorationLine: 'underline',
|
||||||
|
marginTop: 8,
|
||||||
|
},
|
||||||
|
})
|
||||||
163
social-app-custom/PrivacyContent.tsx
Normal file
163
social-app-custom/PrivacyContent.tsx
Normal file
@@ -0,0 +1,163 @@
|
|||||||
|
import React from 'react'
|
||||||
|
import {View, Text, StyleSheet, Pressable, Linking} from 'react-native'
|
||||||
|
|
||||||
|
interface PrivacyContentProps {
|
||||||
|
onLinkPress?: (url: string) => void
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function PrivacyContent({onLinkPress}: PrivacyContentProps) {
|
||||||
|
const handleLinkPress = (url: string) => {
|
||||||
|
if (onLinkPress) {
|
||||||
|
onLinkPress(url)
|
||||||
|
} else {
|
||||||
|
Linking.openURL(url)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<View style={styles.container}>
|
||||||
|
<View style={styles.section}>
|
||||||
|
<Text style={styles.sectionTitle}>Introduction</Text>
|
||||||
|
<Text style={styles.paragraph}>
|
||||||
|
This Privacy Policy explains how this AT Protocol client application
|
||||||
|
(hereinafter referred to as "the App") handles personal information.
|
||||||
|
Please read this policy carefully before using the App.
|
||||||
|
</Text>
|
||||||
|
</View>
|
||||||
|
|
||||||
|
<View style={styles.section}>
|
||||||
|
<Text style={styles.sectionTitle}>Information We Collect</Text>
|
||||||
|
<Text style={styles.paragraph}>
|
||||||
|
The App may collect and use the following information:
|
||||||
|
</Text>
|
||||||
|
|
||||||
|
<Text style={styles.subTitle}>1. Information Collected Automatically</Text>
|
||||||
|
<View style={styles.list}>
|
||||||
|
<Text style={styles.listItem}>• Device information (model, OS version)</Text>
|
||||||
|
<Text style={styles.listItem}>• App usage data (sessions, features used)</Text>
|
||||||
|
<Text style={styles.listItem}>• Crash logs and performance data</Text>
|
||||||
|
</View>
|
||||||
|
|
||||||
|
<Text style={styles.subTitle}>2. Information Provided by Users</Text>
|
||||||
|
<View style={styles.list}>
|
||||||
|
<Text style={styles.listItem}>
|
||||||
|
• DID (Decentralized Identifier) and handle for authentication
|
||||||
|
</Text>
|
||||||
|
<Text style={styles.listItem}>• Posts, media, and social interactions</Text>
|
||||||
|
<Text style={styles.listItem}>• Profile information (avatar, display name, bio)</Text>
|
||||||
|
</View>
|
||||||
|
|
||||||
|
<View style={styles.highlight}>
|
||||||
|
<Text style={styles.highlightText}>
|
||||||
|
Important: Your data is stored on your chosen PDS (Personal Data Server).
|
||||||
|
This app does not store your content on our servers.
|
||||||
|
</Text>
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
|
||||||
|
<View style={styles.section}>
|
||||||
|
<Text style={styles.sectionTitle}>How We Use Your Information</Text>
|
||||||
|
<View style={styles.list}>
|
||||||
|
<Text style={styles.listItem}>
|
||||||
|
• To provide AT Protocol social networking features
|
||||||
|
</Text>
|
||||||
|
<Text style={styles.listItem}>• To improve app performance and user experience</Text>
|
||||||
|
<Text style={styles.listItem}>• To diagnose and fix technical issues</Text>
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
|
||||||
|
<View style={styles.section}>
|
||||||
|
<Text style={styles.sectionTitle}>Data Sharing</Text>
|
||||||
|
<Text style={styles.paragraph}>
|
||||||
|
The App interacts with your chosen PDS and AppView services. Your posts and
|
||||||
|
profile information are shared according to the AT Protocol specification and
|
||||||
|
your privacy settings.
|
||||||
|
</Text>
|
||||||
|
</View>
|
||||||
|
|
||||||
|
<View style={styles.section}>
|
||||||
|
<Text style={styles.sectionTitle}>Your Rights</Text>
|
||||||
|
<Text style={styles.paragraph}>
|
||||||
|
You have the right to access, modify, or delete your data through your PDS.
|
||||||
|
You can also switch to a different PDS at any time while maintaining your
|
||||||
|
identity.
|
||||||
|
</Text>
|
||||||
|
</View>
|
||||||
|
|
||||||
|
<View style={styles.section}>
|
||||||
|
<Text style={styles.sectionTitle}>Contact</Text>
|
||||||
|
<Text style={styles.paragraph}>
|
||||||
|
For questions about this Privacy Policy, please contact:
|
||||||
|
</Text>
|
||||||
|
<Pressable onPress={() => handleLinkPress('https://syu.is')}>
|
||||||
|
<Text style={styles.link}>https://syu.is</Text>
|
||||||
|
</Pressable>
|
||||||
|
</View>
|
||||||
|
|
||||||
|
<View style={styles.section}>
|
||||||
|
<Text style={styles.lastUpdated}>Last Updated: December 3, 2025</Text>
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
const styles = StyleSheet.create({
|
||||||
|
container: {
|
||||||
|
flex: 1,
|
||||||
|
},
|
||||||
|
section: {
|
||||||
|
marginBottom: 24,
|
||||||
|
},
|
||||||
|
sectionTitle: {
|
||||||
|
fontSize: 20,
|
||||||
|
fontWeight: '600',
|
||||||
|
color: '#1d1d1f',
|
||||||
|
marginBottom: 12,
|
||||||
|
},
|
||||||
|
subTitle: {
|
||||||
|
fontSize: 16,
|
||||||
|
fontWeight: '500',
|
||||||
|
color: '#1d1d1f',
|
||||||
|
marginTop: 12,
|
||||||
|
marginBottom: 8,
|
||||||
|
},
|
||||||
|
paragraph: {
|
||||||
|
fontSize: 15,
|
||||||
|
lineHeight: 22,
|
||||||
|
color: '#3a3a3c',
|
||||||
|
marginBottom: 8,
|
||||||
|
},
|
||||||
|
list: {
|
||||||
|
marginLeft: 8,
|
||||||
|
marginTop: 8,
|
||||||
|
},
|
||||||
|
listItem: {
|
||||||
|
fontSize: 15,
|
||||||
|
lineHeight: 24,
|
||||||
|
color: '#3a3a3c',
|
||||||
|
},
|
||||||
|
highlight: {
|
||||||
|
backgroundColor: '#fff3cd',
|
||||||
|
borderLeftWidth: 4,
|
||||||
|
borderLeftColor: '#ffc107',
|
||||||
|
padding: 12,
|
||||||
|
marginTop: 12,
|
||||||
|
borderRadius: 4,
|
||||||
|
},
|
||||||
|
highlightText: {
|
||||||
|
fontSize: 14,
|
||||||
|
lineHeight: 20,
|
||||||
|
color: '#856404',
|
||||||
|
},
|
||||||
|
link: {
|
||||||
|
fontSize: 15,
|
||||||
|
color: '#007aff',
|
||||||
|
textDecorationLine: 'underline',
|
||||||
|
marginTop: 8,
|
||||||
|
},
|
||||||
|
lastUpdated: {
|
||||||
|
fontSize: 13,
|
||||||
|
color: '#8e8e93',
|
||||||
|
fontStyle: 'italic',
|
||||||
|
},
|
||||||
|
})
|
||||||
42
social-app-custom/PrivacyPolicy.screen.tsx
Normal file
42
social-app-custom/PrivacyPolicy.screen.tsx
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
import React from 'react'
|
||||||
|
import {View} from 'react-native'
|
||||||
|
import {msg} from '@lingui/macro'
|
||||||
|
import {useLingui} from '@lingui/react'
|
||||||
|
import {useFocusEffect} from '@react-navigation/native'
|
||||||
|
|
||||||
|
import {usePalette} from '#/lib/hooks/usePalette'
|
||||||
|
import {
|
||||||
|
type CommonNavigatorParams,
|
||||||
|
type NativeStackScreenProps,
|
||||||
|
} from '#/lib/routes/types'
|
||||||
|
import {s} from '#/lib/styles'
|
||||||
|
import {useSetMinimalShellMode} from '#/state/shell'
|
||||||
|
import {ScrollView} from '#/view/com/util/Views'
|
||||||
|
import * as Layout from '#/components/Layout'
|
||||||
|
import {ViewHeader} from '../com/util/ViewHeader'
|
||||||
|
import PrivacyContent from '#/components/custom/PrivacyContent'
|
||||||
|
|
||||||
|
type Props = NativeStackScreenProps<CommonNavigatorParams, 'PrivacyPolicy'>
|
||||||
|
export const PrivacyPolicyScreen = (_props: Props) => {
|
||||||
|
const pal = usePalette('default')
|
||||||
|
const {_} = useLingui()
|
||||||
|
const setMinimalShellMode = useSetMinimalShellMode()
|
||||||
|
|
||||||
|
useFocusEffect(
|
||||||
|
React.useCallback(() => {
|
||||||
|
setMinimalShellMode(false)
|
||||||
|
}, [setMinimalShellMode]),
|
||||||
|
)
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Layout.Screen>
|
||||||
|
<ViewHeader title={_(msg`Privacy Policy`)} />
|
||||||
|
<ScrollView style={[s.hContentRegion, pal.view]}>
|
||||||
|
<View style={[s.p20]}>
|
||||||
|
<PrivacyContent />
|
||||||
|
</View>
|
||||||
|
<View style={s.footerSpacer} />
|
||||||
|
</ScrollView>
|
||||||
|
</Layout.Screen>
|
||||||
|
)
|
||||||
|
}
|
||||||
38
social-app-custom/Support.screen.tsx
Normal file
38
social-app-custom/Support.screen.tsx
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
import React from 'react'
|
||||||
|
import {msg} from '@lingui/macro'
|
||||||
|
import {useLingui} from '@lingui/react'
|
||||||
|
import {useFocusEffect} from '@react-navigation/native'
|
||||||
|
|
||||||
|
import {usePalette} from '#/lib/hooks/usePalette'
|
||||||
|
import {
|
||||||
|
type CommonNavigatorParams,
|
||||||
|
type NativeStackScreenProps,
|
||||||
|
} from '#/lib/routes/types'
|
||||||
|
import {s} from '#/lib/styles'
|
||||||
|
import {useSetMinimalShellMode} from '#/state/shell'
|
||||||
|
import {ViewHeader} from '#/view/com/util/ViewHeader'
|
||||||
|
import {ScrollView} from '#/view/com/util/Views'
|
||||||
|
import * as Layout from '#/components/Layout'
|
||||||
|
import AppInfo from '#/components/custom/AppInfo'
|
||||||
|
|
||||||
|
type Props = NativeStackScreenProps<CommonNavigatorParams, 'Support'>
|
||||||
|
export const SupportScreen = (_props: Props) => {
|
||||||
|
const pal = usePalette('default')
|
||||||
|
const setMinimalShellMode = useSetMinimalShellMode()
|
||||||
|
const {_} = useLingui()
|
||||||
|
|
||||||
|
useFocusEffect(
|
||||||
|
React.useCallback(() => {
|
||||||
|
setMinimalShellMode(false)
|
||||||
|
}, [setMinimalShellMode]),
|
||||||
|
)
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Layout.Screen>
|
||||||
|
<ViewHeader title={_(msg`App Info`)} />
|
||||||
|
<ScrollView style={[s.hContentRegion, pal.view]}>
|
||||||
|
<AppInfo />
|
||||||
|
</ScrollView>
|
||||||
|
</Layout.Screen>
|
||||||
|
)
|
||||||
|
}
|
||||||
9
social-app-custom/app.config.patch.js
Normal file
9
social-app-custom/app.config.patch.js
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
// Aiat app configuration overrides
|
||||||
|
module.exports = {
|
||||||
|
name: 'Aiat',
|
||||||
|
slug: 'aiat',
|
||||||
|
scheme: 'aiat',
|
||||||
|
owner: 'syui', // Your Expo account
|
||||||
|
bundleIdentifier: 'ai.syui.at',
|
||||||
|
// Icon will be set separately
|
||||||
|
}
|
||||||
44
social-app-custom/bin/build.zsh
Executable file
44
social-app-custom/bin/build.zsh
Executable file
@@ -0,0 +1,44 @@
|
|||||||
|
#!/bin/zsh
|
||||||
|
set -e
|
||||||
|
|
||||||
|
d=~/ai/at/repos/social-app
|
||||||
|
APP_NAME=Aiat
|
||||||
|
PKG=aiat
|
||||||
|
TEAM_NAME=
|
||||||
|
TEAM_ID=
|
||||||
|
CERT="Apple Distribution: ${TEAM_NAME} (${TEAM_ID})"
|
||||||
|
MAIL=user@example.com
|
||||||
|
KEY_CHAIN=EXAMPLE
|
||||||
|
|
||||||
|
cd $d
|
||||||
|
# npx expo prebuild --clean
|
||||||
|
# cd ios && pod install && cd ..
|
||||||
|
|
||||||
|
## アーカイブ
|
||||||
|
xcodebuild -workspace ios/${PKG}.xcworkspace \
|
||||||
|
-scheme ${PKG} \
|
||||||
|
-configuration Release \
|
||||||
|
-archivePath build/${APP_NAME}.xcarchive \
|
||||||
|
-allowProvisioningUpdates \
|
||||||
|
archive
|
||||||
|
|
||||||
|
cd build
|
||||||
|
|
||||||
|
# IPA作成
|
||||||
|
rm -rf Payload ${APP_NAME}.ipa
|
||||||
|
mkdir -p Payload
|
||||||
|
cp -R ${APP_NAME}.xcarchive/Products/Applications/${PKG}.app Payload/
|
||||||
|
cp ../store.mobileprovision Payload/${PKG}.app/embedded.mobileprovision
|
||||||
|
|
||||||
|
# entitlements抽出
|
||||||
|
security cms -D -i Payload/${PKG}.app/embedded.mobileprovision > /tmp/profile.plist
|
||||||
|
/usr/libexec/PlistBuddy -x -c "Print :Entitlements" /tmp/profile.plist > /tmp/entitlements.plist
|
||||||
|
|
||||||
|
codesign -f -s "$CERT" Payload/${PKG}.app/Frameworks/*.framework 2>/dev/null || true
|
||||||
|
codesign -f -s "$CERT" --entitlements /tmp/entitlements.plist Payload/${PKG}.app
|
||||||
|
|
||||||
|
zip -r ${APP_NAME}.ipa Payload
|
||||||
|
|
||||||
|
xcrun altool --upload-app -f ${APP_NAME}.ipa -t ios -u "${MAIL}" -p "@keychain:${KEY_CHAIN}"
|
||||||
|
|
||||||
|
echo "Upload complete"
|
||||||
86
social-app-custom/bin/install.zsh
Normal file
86
social-app-custom/bin/install.zsh
Normal file
@@ -0,0 +1,86 @@
|
|||||||
|
#!/bin/zsh
|
||||||
|
|
||||||
|
if [ "$1" = "social-app-custom" ];then
|
||||||
|
at-social-app-custom-pages
|
||||||
|
at-social-app-custom-screens
|
||||||
|
at-social-app-aiat-config
|
||||||
|
at-social-app-aiat-logo
|
||||||
|
at-origin-social-app
|
||||||
|
exit
|
||||||
|
fi
|
||||||
|
|
||||||
|
function at-social-app-custom-pages() {
|
||||||
|
d_=$d/repos/social-app
|
||||||
|
custom=$d/social-app-custom
|
||||||
|
|
||||||
|
echo "copying custom components to social-app"
|
||||||
|
|
||||||
|
# Create components directory if not exists
|
||||||
|
mkdir -p ${d_}/src/components/custom
|
||||||
|
|
||||||
|
# Copy custom components
|
||||||
|
cp ${custom}/PrivacyContent.tsx ${d_}/src/components/custom/
|
||||||
|
cp ${custom}/AppInfo.tsx ${d_}/src/components/custom/
|
||||||
|
|
||||||
|
echo "custom components copied successfully"
|
||||||
|
}
|
||||||
|
|
||||||
|
function at-social-app-aiat-config() {
|
||||||
|
d_=$d/repos/social-app
|
||||||
|
custom=$d/social-app-custom
|
||||||
|
|
||||||
|
echo "applying Aiat configuration"
|
||||||
|
|
||||||
|
# Update app.config.js
|
||||||
|
cd ${d_}
|
||||||
|
|
||||||
|
# Backup original
|
||||||
|
cp app.config.js app.config.js.orig
|
||||||
|
|
||||||
|
# Apply changes using sed
|
||||||
|
sed -i "s/name: 'Bluesky'/name: 'Aiat'/g" app.config.js
|
||||||
|
sed -i "s/slug: 'bluesky'/slug: 'aiat'/g" app.config.js
|
||||||
|
sed -i "s/scheme: 'bluesky'/scheme: 'aiat'/g" app.config.js
|
||||||
|
sed -i "s/owner: 'blueskysocial'/owner: 'syui'/g" app.config.js
|
||||||
|
sed -i "s/bundleIdentifier: 'xyz.blueskyweb.app'/bundleIdentifier: 'ai.syui.at'/g" app.config.js
|
||||||
|
|
||||||
|
# Update package.json name
|
||||||
|
sed -i 's/"name": "bsky.app"/"name": "aiat"/g' package.json
|
||||||
|
|
||||||
|
echo "Aiat configuration applied"
|
||||||
|
}
|
||||||
|
|
||||||
|
function at-social-app-aiat-logo() {
|
||||||
|
d_=$d/repos/social-app
|
||||||
|
custom=$d/social-app-custom
|
||||||
|
|
||||||
|
echo "applying Aiat logo"
|
||||||
|
|
||||||
|
# Create logo directory if not exists
|
||||||
|
mkdir -p ${custom}/assets
|
||||||
|
|
||||||
|
# Copy logo if exists in custom folder
|
||||||
|
if [ -f ${custom}/assets/icon.png ]; then
|
||||||
|
cp ${custom}/assets/icon.png ${d_}/assets/app-icons/ios_icon_default_next.png
|
||||||
|
echo "Aiat logo applied"
|
||||||
|
else
|
||||||
|
echo "Warning: Logo file not found at ${custom}/assets/icon.png"
|
||||||
|
echo "Please add your logo file there"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
function at-social-app-custom-screens() {
|
||||||
|
d_=$d/repos/social-app
|
||||||
|
custom=$d/social-app-custom
|
||||||
|
|
||||||
|
echo "applying custom screens"
|
||||||
|
|
||||||
|
# Copy custom screen files
|
||||||
|
cp ${custom}/PrivacyPolicy.screen.tsx ${d_}/src/view/screens/PrivacyPolicy.tsx
|
||||||
|
cp ${custom}/Support.screen.tsx ${d_}/src/view/screens/Support.tsx
|
||||||
|
cp ${custom}/LicenseNotice.tsx ${d_}/src/components/custom/
|
||||||
|
|
||||||
|
echo "custom screens applied"
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
Reference in New Issue
Block a user