Compare commits
5 Commits
fix/issue-
...
girlcock
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f5cfd73d1c | ||
|
|
052109ec4c | ||
|
|
aedd4a5219 | ||
|
|
276d3b0663 | ||
|
|
b081b71e7d |
12
README.md
12
README.md
@@ -1,21 +1,23 @@
|
|||||||
# VixBluesky 🛠️ (Inspired by [FixTweet](https://github.com/FixTweet/FixTweet))
|
# girlcockbsky Fork of [VixBluesky](https://github.com/Rapougnac/VixBluesky) 🛠️ (Inspired by [FixTweet](https://github.com/FixTweet/FixTweet))
|
||||||
|
|
||||||
> [!IMPORTANT]
|
> [!IMPORTANT]
|
||||||
> This is a fork of [FixBluesky](https://github.com/ThornbushHQ/FixBluesky) by [@ItsRauf](https://www.github.com/ItsRauf).
|
> This is a fork of [VixBluesky](https://github.com/Rapougnac/VixBluesky) by [@Lexedia](https://www.github.com/Rapougnac), which is a fork of [FixBluesky](https://github.com/ThornbushHQ/FixBluesky) by [@ItsRauf](https://www.github.com/ItsRauf).
|
||||||
> All credits go to them for the original idea and implementation.
|
> All credits go to them for the original idea and implementation.
|
||||||
|
|
||||||
|
Converted to nodejs cause serverless design's proprietary-ness annoys me and i wanted to make a funny joke after seeing girlcockx for twitter.
|
||||||
|
|
||||||
Embed Bluesky links in Discord.
|
Embed Bluesky links in Discord.
|
||||||
|
|
||||||
## How To Use?
|
## How To Use?
|
||||||
|
|
||||||
#### Simply append `x` at the end of `bsky.app`.
|
#### Simply append `girlcock` at the front of `bsky.app`.
|
||||||
|
|
||||||
## Direct Links
|
## Direct Links
|
||||||
|
|
||||||
You want to link to a media directly? You can prepend `r.` to the URL to get a direct link.
|
You want to link to a media directly? You can prepend `r.` to the URL to get a direct link.
|
||||||

|
|
||||||
|
|
||||||
## Authors
|
## Authors
|
||||||
|
|
||||||
- [@ItsRauf](https://www.github.com/ItsRauf) - Original author
|
- [@ItsRauf](https://www.github.com/ItsRauf) - Original author
|
||||||
- [@Lexedia](https://www.github.com/Rapougnac)
|
- [@Lexedia](https://www.github.com/Rapougnac) - Also Original author
|
||||||
|
- [@juni.pet](https://github.com/Juniteevee) - depraved critter
|
||||||
|
|||||||
28
docker-compose.yaml
Normal file
28
docker-compose.yaml
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
services:
|
||||||
|
api:
|
||||||
|
build:
|
||||||
|
context: ./pkgs/api/.
|
||||||
|
dockerfile: Dockerfile
|
||||||
|
ports:
|
||||||
|
- "2598:3000"
|
||||||
|
environment:
|
||||||
|
- NODE_ENV=production
|
||||||
|
- PORT=3000
|
||||||
|
- EMPTY_REDIR=https://bsky.app/profile/juni.pet/post/3l3e53fzazy2n
|
||||||
|
restart: unless-stopped
|
||||||
|
app:
|
||||||
|
build:
|
||||||
|
context: ./pkgs/app/.
|
||||||
|
dockerfile: Dockerfile
|
||||||
|
ports:
|
||||||
|
- "2599:3000"
|
||||||
|
environment:
|
||||||
|
- BSKY_SERVICE_URL=https://bsky.social
|
||||||
|
- VIXBLUESKY_APP_DOMAIN=girlcockbsky.app
|
||||||
|
- VIXBLUESKY_API_URL=http://localhost:2598/
|
||||||
|
- BSKY_AUTH_USERNAME=YOUR_OWN_USERNAME
|
||||||
|
- BSKY_AUTH_PASSWORD=YOUR_APP_PASSWORD_SHOULD_COME_FROM_ENV
|
||||||
|
- PORT=3000
|
||||||
|
- EMPTY_REDIR=https://bsky.app/profile/juni.pet/post/3l3e53fzazy2n
|
||||||
|
restart: unless-stopped
|
||||||
|
|
||||||
@@ -22,17 +22,18 @@ declare global {
|
|||||||
interface ProcessEnv {
|
interface ProcessEnv {
|
||||||
readonly NODE_ENV: Env;
|
readonly NODE_ENV: Env;
|
||||||
readonly PORT: string | undefined;
|
readonly PORT: string | undefined;
|
||||||
|
readonly EMPTY_REDIR: string;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const { NODE_ENV: env = "development", PORT } = process.env;
|
const { NODE_ENV: env = "development", PORT, EMPTY_REDIR } = process.env;
|
||||||
|
|
||||||
const app = fastify({ logger: envToLogger[env] });
|
const app = fastify({ logger: envToLogger[env] });
|
||||||
|
|
||||||
app.addContentTypeParser("*", (_, __, done) => done(null));
|
app.addContentTypeParser("*", (_, __, done) => done(null));
|
||||||
|
|
||||||
app.get("/", async (_, res) => res.redirect("https://bskyx.app"));
|
app.get("/", async (_, res) => res.redirect(EMPTY_REDIR));
|
||||||
|
|
||||||
// serve 0 bytes favicon so browsers don't spam the server
|
// serve 0 bytes favicon so browsers don't spam the server
|
||||||
app.get("/favicon.ico", (_, res) => res.send(""));
|
app.get("/favicon.ico", (_, res) => res.send(""));
|
||||||
|
|||||||
14
pkgs/app/Dockerfile
Normal file
14
pkgs/app/Dockerfile
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
#FROM node:22-alpine
|
||||||
|
FROM node:22.2.0-slim
|
||||||
|
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
COPY package*.json ./
|
||||||
|
|
||||||
|
RUN npm i -g pnpm && pnpm install
|
||||||
|
|
||||||
|
COPY . .
|
||||||
|
|
||||||
|
#RUN pnpm run dev
|
||||||
|
|
||||||
|
CMD [ "pnpm", "dev" ]
|
||||||
@@ -1,17 +1,20 @@
|
|||||||
{
|
{
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "wrangler dev src/index.ts",
|
"dev": "tsx watch src/index.ts"
|
||||||
"deploy": "wrangler deploy --minify src/index.ts"
|
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@atcute/bluesky": "^1.0.7",
|
"@atcute/bluesky": "^1.0.7",
|
||||||
"@atcute/client": "^2.0.3",
|
"@atcute/client": "^2.0.3",
|
||||||
"hono": "^4.5.1"
|
"hono": "^4.5.1",
|
||||||
|
"@hono/node-server": "^1.13.2",
|
||||||
|
"node-cache": "^5.1.2"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@cloudflare/workers-types": "^4.20230628.0",
|
"@cloudflare/workers-types": "^4.20230628.0",
|
||||||
"prettier": "^3.3.3",
|
"prettier": "^3.3.3",
|
||||||
"typescript": "^5.1.6",
|
"typescript": "^5.1.6",
|
||||||
"wrangler": "^3.75.0"
|
"wrangler": "^3.75.0",
|
||||||
|
"@types/node": "^20.11.17",
|
||||||
|
"tsx": "^4.7.1"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
18
pkgs/app/src/globals.d.ts
vendored
18
pkgs/app/src/globals.d.ts
vendored
@@ -1,18 +0,0 @@
|
|||||||
import { XRPC } from '@atcute/client';
|
|
||||||
import type { KVNamespace } from '@cloudflare/workers-types';
|
|
||||||
|
|
||||||
declare global {
|
|
||||||
interface Env {
|
|
||||||
Bindings: {
|
|
||||||
BSKY_SERVICE_URL: string;
|
|
||||||
BSKY_AUTH_USERNAME: string;
|
|
||||||
BSKY_AUTH_PASSWORD: string;
|
|
||||||
VIXBLUESKY_APP_DOMAIN: string;
|
|
||||||
VIXBLUESKY_API_URL: string;
|
|
||||||
bskyx: KVNamespace;
|
|
||||||
};
|
|
||||||
Variables: {
|
|
||||||
Agent: XRPC;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import { serve } from '@hono/node-server'
|
||||||
import { Hono } from 'hono';
|
import { Hono } from 'hono';
|
||||||
import { XRPC, CredentialManager, AtpSessionData } from '@atcute/client';
|
import { XRPC, CredentialManager, AtpSessionData } from '@atcute/client';
|
||||||
import '@atcute/bluesky/lexicons';
|
import '@atcute/bluesky/lexicons';
|
||||||
@@ -7,32 +8,34 @@ import { getOEmbed } from './routes/getOEmbed';
|
|||||||
import { getProfileData } from './routes/getProfileData';
|
import { getProfileData } from './routes/getProfileData';
|
||||||
import { getProfile } from './routes/getProfile';
|
import { getProfile } from './routes/getProfile';
|
||||||
import { HTTPException } from 'hono/http-exception';
|
import { HTTPException } from 'hono/http-exception';
|
||||||
|
const NodeCache = require( "node-cache" );
|
||||||
|
|
||||||
const app = new Hono<Env>();
|
const app = new Hono();
|
||||||
|
const myCache = new NodeCache();
|
||||||
|
|
||||||
app.use('*', async (c, next) => {
|
app.use('*', async (c, next) => {
|
||||||
const creds = new CredentialManager({
|
const creds = new CredentialManager({
|
||||||
service: c.env.BSKY_SERVICE_URL,
|
service: process.env.BSKY_SERVICE_URL,
|
||||||
onRefresh(session) {
|
onRefresh(session) {
|
||||||
return c.env.bskyx.put('session', JSON.stringify(session));
|
return myCache.set('session', JSON.stringify(session));
|
||||||
},
|
},
|
||||||
onExpired(session) {
|
onExpired(session) {
|
||||||
return c.env.bskyx.delete('session');
|
return myCache.del('session');
|
||||||
},
|
},
|
||||||
onSessionUpdate(session) {
|
onSessionUpdate(session) {
|
||||||
return c.env.bskyx.put('session', JSON.stringify(session));
|
return myCache.set('session', JSON.stringify(session));
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
const agent = new XRPC({ handler: creds });
|
const agent = new XRPC({ handler: creds });
|
||||||
try {
|
try {
|
||||||
const rawSession = await c.env.bskyx.get('session');
|
const rawSession = myCache.get('session');
|
||||||
if (rawSession) {
|
if(rawSession) {
|
||||||
const session = JSON.parse(rawSession) as AtpSessionData;
|
const session = JSON.parse(rawSession) as AtpSessionData;
|
||||||
await creds.resume(session);
|
await creds.resume(session);
|
||||||
} else {
|
} else {
|
||||||
await creds.login({
|
await creds.login({
|
||||||
identifier: c.env.BSKY_AUTH_USERNAME,
|
identifier: process.env.BSKY_AUTH_USERNAME,
|
||||||
password: c.env.BSKY_AUTH_PASSWORD,
|
password: process.env.BSKY_AUTH_PASSWORD,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
c.set('Agent', agent);
|
c.set('Agent', agent);
|
||||||
@@ -48,7 +51,7 @@ app.use('*', async (c, next) => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
app.get('/', async (c) => {
|
app.get('/', async (c) => {
|
||||||
return c.redirect('https://github.com/Rapougnac/VixBluesky');
|
return c.redirect(process.env.EMPTY_REDIR);
|
||||||
});
|
});
|
||||||
|
|
||||||
app.get('/profile/:user/post/:post', getPost);
|
app.get('/profile/:user/post/:post', getPost);
|
||||||
@@ -65,4 +68,7 @@ app.get('/https://bsky.app/profile/:user/json', getProfileData);
|
|||||||
|
|
||||||
app.get('/oembed', getOEmbed);
|
app.get('/oembed', getOEmbed);
|
||||||
|
|
||||||
export default app;
|
serve({
|
||||||
|
fetch: app.fetch,
|
||||||
|
port: process.env.PORT,
|
||||||
|
})
|
||||||
|
|||||||
@@ -8,7 +8,9 @@ export function parseEmbedDescription(post: AppBskyFeedDefs.PostView): string {
|
|||||||
checkType('app.bsky.embed.recordWithMedia#view', post.embed));
|
checkType('app.bsky.embed.recordWithMedia#view', post.embed));
|
||||||
|
|
||||||
// @ts-expect-error
|
// @ts-expect-error
|
||||||
const embed = post.embed.record?.record ?? post.embed.record;
|
let embed;
|
||||||
|
if(isQuote)
|
||||||
|
embed = post.embed.record?.record ?? post.embed.record;
|
||||||
|
|
||||||
return isQuote
|
return isQuote
|
||||||
? // @ts-expect-error
|
? // @ts-expect-error
|
||||||
|
|||||||
@@ -11,8 +11,8 @@ export const getOEmbed: Handler<Env, '/oembed'> = async (c) => {
|
|||||||
const avatar = c.req.query('avatar');
|
const avatar = c.req.query('avatar');
|
||||||
|
|
||||||
const defaults = {
|
const defaults = {
|
||||||
provider_name: 'VixBluesky',
|
provider_name: 'girlcockbsky',
|
||||||
provider_url: 'https://bskyx.app/',
|
provider_url: 'https://girlcockbsky.app/',
|
||||||
thumbnail_width: 1000,
|
thumbnail_width: 1000,
|
||||||
thumbnail_height: 1000,
|
thumbnail_height: 1000,
|
||||||
};
|
};
|
||||||
@@ -42,7 +42,7 @@ export const getOEmbed: Handler<Env, '/oembed'> = async (c) => {
|
|||||||
const { replies, reposts, likes, description } = c.req.query();
|
const { replies, reposts, likes, description } = c.req.query();
|
||||||
return c.json({
|
return c.json({
|
||||||
...defaults,
|
...defaults,
|
||||||
provider_name: `VixBluesky\n\n🗨️ ${replies} ♻️ ${reposts} 💙 ${likes}`,
|
provider_name: `girlcockbsky\n\n🗨️ ${replies} ♻️ ${reposts} 💙 ${likes}`,
|
||||||
description,
|
description,
|
||||||
title: description,
|
title: description,
|
||||||
author_name: description,
|
author_name: description,
|
||||||
|
|||||||
@@ -29,7 +29,8 @@ export const getPost: Handler<
|
|||||||
Env,
|
Env,
|
||||||
'/profile/:user/post/:post' | '/https://bsky.app/profile/:user/post/:post'
|
'/profile/:user/post/:post' | '/https://bsky.app/profile/:user/post/:post'
|
||||||
> = async (c) => {
|
> = async (c) => {
|
||||||
const { user, post } = c.req.param();
|
let { user, post } = c.req.param();
|
||||||
|
post = post.replaceAll('|', '');
|
||||||
const isDirect = c.req.query('direct');
|
const isDirect = c.req.query('direct');
|
||||||
|
|
||||||
const agent = c.get('Agent');
|
const agent = c.get('Agent');
|
||||||
@@ -67,9 +68,9 @@ export const getPost: Handler<
|
|||||||
<Post
|
<Post
|
||||||
post={fetchedPost}
|
post={fetchedPost}
|
||||||
url={c.req.path}
|
url={c.req.path}
|
||||||
appDomain={c.env.VIXBLUESKY_APP_DOMAIN}
|
appDomain={process.env.VIXBLUESKY_APP_DOMAIN}
|
||||||
videoMetadata={videoMetaData}
|
videoMetadata={videoMetaData}
|
||||||
apiUrl={c.env.VIXBLUESKY_API_URL}
|
apiUrl={process.env.VIXBLUESKY_API_URL}
|
||||||
images={images}
|
images={images}
|
||||||
/>,
|
/>,
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -7,7 +7,8 @@ export const getProfile: Handler<
|
|||||||
Env,
|
Env,
|
||||||
'/profile/:user' | '/https://bsky.app/profile/:user'
|
'/profile/:user' | '/https://bsky.app/profile/:user'
|
||||||
> = async (c) => {
|
> = async (c) => {
|
||||||
const { user } = c.req.param();
|
let { user } = c.req.param();
|
||||||
|
user = user.replaceAll('|', '');
|
||||||
const agent = c.get('Agent');
|
const agent = c.get('Agent');
|
||||||
try {
|
try {
|
||||||
var { data } = await fetchProfile(agent, { user });
|
var { data } = await fetchProfile(agent, { user });
|
||||||
@@ -21,7 +22,7 @@ export const getProfile: Handler<
|
|||||||
<Profile
|
<Profile
|
||||||
profile={data}
|
profile={data}
|
||||||
url={c.req.path}
|
url={c.req.path}
|
||||||
appDomain={c.env.VIXBLUESKY_APP_DOMAIN}
|
appDomain={process.env.VIXBLUESKY_APP_DOMAIN}
|
||||||
/>,
|
/>,
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,13 +1,14 @@
|
|||||||
{
|
{
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"target": "ESNext",
|
"target": "ESNext",
|
||||||
"module": "ESNext",
|
"module": "NodeNext",
|
||||||
"moduleResolution": "Bundler",
|
|
||||||
"esModuleInterop": true,
|
|
||||||
"strict": true,
|
"strict": true,
|
||||||
"lib": ["esnext"],
|
"verbatimModuleSyntax": true,
|
||||||
"types": ["@cloudflare/workers-types"],
|
"skipLibCheck": true,
|
||||||
|
"types": [
|
||||||
|
"node"
|
||||||
|
],
|
||||||
"jsx": "react-jsx",
|
"jsx": "react-jsx",
|
||||||
"jsxImportSource": "hono/jsx"
|
"jsxImportSource": "hono/jsx",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
name = "vixbluesky"
|
|
||||||
main = "src/index.ts"
|
|
||||||
compatibility_date = "2023-01-01"
|
|
||||||
|
|
||||||
workers_dev = false
|
|
||||||
route = { pattern = "bskyx.app/*", zone_name = "bskyx.app" }
|
|
||||||
|
|
||||||
[vars]
|
|
||||||
BSKY_SERVICE_URL="https://bsky.social/"
|
|
||||||
VIXBLUESKY_APP_DOMAIN="bskyx.app"
|
|
||||||
VIXBLUESKY_API_URL="https://api.bskyx.app/"
|
|
||||||
|
|
||||||
[[kv_namespaces]]
|
|
||||||
binding = "bskyx"
|
|
||||||
id = "ee913536e1fb47dcb9fa6275725f5a6f"
|
|
||||||
preview_id = "5e180765d24346c9b238be57d9c7001f"
|
|
||||||
Reference in New Issue
Block a user