An ATproto social media client -- with an independent Appview.

feat: rename bsky.app -> social.shatteredsky.net

+48 -37
+2 -2
README.md
··· 4 5 Get the app itself: 6 7 - - **Web: bsky.app** 8 9 <a href="https://apps.obtainium.imranr.dev/redirect?r=obtainium://add/https://github.com/NekoDrone/catsky-social"> 10 <img src="https://github.com/ImranR98/Obtainium/blob/main/assets/graphics/badge_obtainium.png?raw=true" ··· 48 - Stay away from PRs like... 49 - Changing "Post" to "Skeet." 50 - Refactoring the codebase, e.g., to replace React Query with Redux Toolkit or something. 51 - - Adding entirely new features without prior discussion. 52 53 Remember, we serve a wide community of users. Our day-to-day involves us constantly asking "which top priority is our top priority." If you submit well-written PRs that solve problems concisely, that's an awesome contribution. Otherwise, as much as we'd love to accept your ideas and contributions, we really don't have the bandwidth. That's what forking is for! 54
··· 4 5 Get the app itself: 6 7 + - **Web: social.shatteredsky.net** 8 9 <a href="https://apps.obtainium.imranr.dev/redirect?r=obtainium://add/https://github.com/NekoDrone/catsky-social"> 10 <img src="https://github.com/ImranR98/Obtainium/blob/main/assets/graphics/badge_obtainium.png?raw=true" ··· 48 - Stay away from PRs like... 49 - Changing "Post" to "Skeet." 50 - Refactoring the codebase, e.g., to replace React Query with Redux Toolkit or something. 51 + - Adding entirely new features without prior discussion. 52 53 Remember, we serve a wide community of users. Our day-to-day involves us constantly asking "which top priority is our top priority." If you submit well-written PRs that solve problems concisely, that's an awesome contribution. Otherwise, as much as we'd love to accept your ideas and contributions, we really don't have the bandwidth. That's what forking is for! 54
+2 -1
app.config.js
··· 18 const IS_DEV = !IS_TESTFLIGHT || !IS_PRODUCTION 19 20 const ASSOCIATED_DOMAINS = [ 21 'applinks:bsky.app', 22 'applinks:staging.bsky.app', 23 'appclips:bsky.app', ··· 159 data: [ 160 { 161 scheme: 'https', 162 - host: 'bsky.app', 163 }, 164 IS_DEV && { 165 scheme: 'http',
··· 18 const IS_DEV = !IS_TESTFLIGHT || !IS_PRODUCTION 19 20 const ASSOCIATED_DOMAINS = [ 21 + 'applinks:shatteredsky.net', 22 'applinks:bsky.app', 23 'applinks:staging.bsky.app', 24 'appclips:bsky.app', ··· 160 data: [ 161 { 162 scheme: 'https', 163 + host: 'social.shatteredsky.net', 164 }, 165 IS_DEV && { 166 scheme: 'http',
+1
bskyembed/src/components/post.tsx
··· 158 className="text-blue-500 hover:underline" 159 disableTracking={ 160 !segment.link.uri.startsWith('https://bsky.app') && 161 !segment.link.uri.startsWith('https://go.bsky.app') 162 }> 163 {segment.text}
··· 158 className="text-blue-500 hover:underline" 159 disableTracking={ 160 !segment.link.uri.startsWith('https://bsky.app') && 161 + !segment.link.uri.startsWith('https://social.shatteredsky.net') && 162 !segment.link.uri.startsWith('https://go.bsky.app') 163 }> 164 {segment.text}
+2 -2
bskyembed/src/screens/landing.tsx
··· 18 import {niceDate} from '../util/nice-date' 19 20 const DEFAULT_POST = 21 - 'https://bsky.app/profile/did:plc:vjug55kidv6sye7ykr5faxxn/post/3jzn6g7ixgq2y' 22 const DEFAULT_URI = 23 'at://did:plc:vjug55kidv6sye7ykr5faxxn/app.bsky.feed.post/3jzn6g7ixgq2y' 24 ··· 59 } else { 60 try { 61 const urlp = new URL(uri) 62 - if (!urlp.hostname.endsWith('bsky.app')) { 63 throw new Error('Invalid hostname') 64 } 65 const split = urlp.pathname.slice(1).split('/')
··· 18 import {niceDate} from '../util/nice-date' 19 20 const DEFAULT_POST = 21 + 'https://social.shatteredsky.net/profile/did:plc:vjug55kidv6sye7ykr5faxxn/post/3jzn6g7ixgq2y' 22 const DEFAULT_URI = 23 'at://did:plc:vjug55kidv6sye7ykr5faxxn/app.bsky.feed.post/3jzn6g7ixgq2y' 24 ··· 59 } else { 60 try { 61 const urlp = new URL(uri) 62 + if (!urlp.hostname.endsWith('shatteredsky.net')) { 63 throw new Error('Invalid hostname') 64 } 65 const split = urlp.pathname.slice(1).split('/')
+2 -2
bskyembed/src/screens/post.tsx
··· 90 91 function ErrorMessage() { 92 return ( 93 - <Container href="https://bsky.app/"> 94 <Link 95 - href="https://bsky.app/" 96 className="transition-transform hover:scale-110 absolute top-4 right-4"> 97 <img src={logo} className="h-6" /> 98 </Link>
··· 90 91 function ErrorMessage() { 92 return ( 93 + <Container href="https://social.shatteredsky.net/"> 94 <Link 95 + href="https://social.shatteredsky.net/" 96 className="transition-transform hover:scale-110 absolute top-4 right-4"> 97 <img src={logo} className="h-6" /> 98 </Link>
+1 -1
bskylink/src/config.ts
··· 74 version: env.version, 75 hostnames: env.hostnames, 76 hostnamesSet: new Set(env.hostnames), 77 - appHostname: env.appHostname ?? 'bsky.app', 78 safelinkEnabled: env.safelinkEnabled ?? false, 79 safelinkPdsUrl: env.safelinkPdsUrl, 80 safelinkAgentIdentifier: env.safelinkAgentIdentifier,
··· 74 version: env.version, 75 hostnames: env.hostnames, 76 hostnamesSet: new Set(env.hostnames), 77 + appHostname: env.appHostname ?? 'social.shatteredsky.net', 78 safelinkEnabled: env.safelinkEnabled ?? false, 79 safelinkPdsUrl: env.safelinkPdsUrl, 80 safelinkAgentIdentifier: env.safelinkAgentIdentifier,
+1 -1
bskylink/src/html/linkWarningContents.ts
··· 38 </div> 39 <div class="button-group"> 40 ${continueButton} 41 - <a class="button primary" href="https://bsky.app">${req.__('Return to Bluesky')}</a> 42 </div> 43 ` 44 }
··· 38 </div> 39 <div class="button-group"> 40 ${continueButton} 41 + <a class="button primary" href="https://social.shatteredsky.net">${req.__('Return to Shattered Sky')}</a> 42 </div> 43 ` 44 }
+1 -1
bskyweb/cmd/bskyweb/main.go
··· 84 Name: "cors-allowed-origins", 85 Usage: "list of allowed origins for CORS requests", 86 Required: false, 87 - Value: cli.NewStringSlice("https://bsky.app", "https://main.bsky.dev", "https://app.staging.bsky.dev"), 88 EnvVars: []string{"CORS_ALLOWED_ORIGINS"}, 89 }, 90 &cli.StringFlag{
··· 84 Name: "cors-allowed-origins", 85 Usage: "list of allowed origins for CORS requests", 86 Required: false, 87 + Value: cli.NewStringSlice("https://bsky.app", "https://main.bsky.dev", "https://app.staging.bsky.dev", "https://social.shatteredsky.net"), 88 EnvVars: []string{"CORS_ALLOWED_ORIGINS"}, 89 }, 90 &cli.StringFlag{
+7 -7
bskyweb/cmd/embedr/handlers.go
··· 78 if err != nil { 79 return nil, err 80 } 81 - if u.Hostname() != "bsky.app" { 82 - return nil, fmt.Errorf("only bsky.app URLs currently supported") 83 } 84 pathParts := strings.Split(u.Path, "/") // NOTE: pathParts[0] will be empty string 85 if len(pathParts) != 5 || pathParts[1] != "profile" || pathParts[3] != "post" { 86 - return nil, fmt.Errorf("only bsky.app post URLs currently supported") 87 } 88 atid, err := syntax.ParseAtIdentifier(pathParts[2]) 89 if err != nil { ··· 142 143 aturi, err := srv.parseBlueskyURL(c.Request().Context(), c.QueryParam("url")) 144 if err != nil { 145 - return c.String(http.StatusBadRequest, fmt.Sprintf("Expected 'url' to be bsky.app URL or AT-URI: %v", err)) 146 } 147 if aturi.Collection() != syntax.NSID("app.bsky.feed.post") { 148 return c.String(http.StatusNotImplemented, "Only posts (app.bsky.feed.post records) can be embedded currently") ··· 169 Type: "rich", 170 Version: "1.0", 171 AuthorName: "@" + post.Author.Handle, 172 - AuthorURL: fmt.Sprintf("https://bsky.app/profile/%s", post.Author.Handle), 173 - ProviderName: "Bluesky Social", 174 - ProviderURL: "https://bsky.app", 175 CacheAge: 86400, 176 Width: &width, 177 Height: nil,
··· 78 if err != nil { 79 return nil, err 80 } 81 + if u.Hostname() != "social.shatteredsky.net" { 82 + return nil, fmt.Errorf("only social.shatteredsky.net URLs currently supported") 83 } 84 pathParts := strings.Split(u.Path, "/") // NOTE: pathParts[0] will be empty string 85 if len(pathParts) != 5 || pathParts[1] != "profile" || pathParts[3] != "post" { 86 + return nil, fmt.Errorf("only social.shatteredsky.net post URLs currently supported") 87 } 88 atid, err := syntax.ParseAtIdentifier(pathParts[2]) 89 if err != nil { ··· 142 143 aturi, err := srv.parseBlueskyURL(c.Request().Context(), c.QueryParam("url")) 144 if err != nil { 145 + return c.String(http.StatusBadRequest, fmt.Sprintf("Expected 'url' to be social.shatteredsky.net URL or AT-URI: %v", err)) 146 } 147 if aturi.Collection() != syntax.NSID("app.bsky.feed.post") { 148 return c.String(http.StatusNotImplemented, "Only posts (app.bsky.feed.post records) can be embedded currently") ··· 169 Type: "rich", 170 Version: "1.0", 171 AuthorName: "@" + post.Author.Handle, 172 + AuthorURL: fmt.Sprintf("https://social.shatteredsky.net/profile/%s", post.Author.Handle), 173 + ProviderName: "Shattered Sky", 174 + ProviderURL: "https://social.shatteredsky.net", 175 CacheAge: 86400, 176 Width: &width, 177 Height: nil,
+2 -2
bskyweb/cmd/embedr/snippet.go
··· 64 PostText: post.Text, 65 PostAuthor: authorName, 66 PostIndexedAt: sortAt, 67 - ProfileURL: template.URL(fmt.Sprintf("https://bsky.app/profile/%s?ref_src=embed", aturi.Authority())), 68 - PostURL: template.URL(fmt.Sprintf("https://bsky.app/profile/%s/post/%s?ref_src=embed", aturi.Authority(), aturi.RecordKey())), 69 WidgetURL: template.URL("https://embed.bsky.app/static/embed.js"), 70 } 71
··· 64 PostText: post.Text, 65 PostAuthor: authorName, 66 PostIndexedAt: sortAt, 67 + ProfileURL: template.URL(fmt.Sprintf("https://social.shatteredsky.net/profile/%s?ref_src=embed", aturi.Authority())), 68 + PostURL: template.URL(fmt.Sprintf("https://social.shatteredsky.net/profile/%s/post/%s?ref_src=embed", aturi.Authority(), aturi.RecordKey())), 69 WidgetURL: template.URL("https://embed.bsky.app/static/embed.js"), 70 } 71
+1 -1
bskyweb/templates/post.html
··· 63 "author": { 64 "@type": "Person", 65 "name": "{{ postView.Author.DisplayName }}", 66 - "url": "https://bsky.app/profile/{{ postView.Author.Handle }}" 67 }, 68 {%- if postText %} 69 "text": "{{ postText }}",
··· 63 "author": { 64 "@type": "Person", 65 "name": "{{ postView.Author.DisplayName }}", 66 + "url": "https://social.shatteredsky.net/profile/{{ postView.Author.Handle }}" 67 }, 68 {%- if postText %} 69 "text": "{{ postText }}",
+3 -3
modules/BlueskyClip/ViewController.swift
··· 34 webView.navigationDelegate = self 35 self.view.addSubview(webView) 36 self.webView = webView 37 - self.webView?.load(URLRequest(url: URL(string: "https://bsky.app/?splash=true&clip=true")!)) 38 } 39 40 func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) { ··· 86 } 87 88 switch host { 89 - case "bsky.app": 90 if url.pathComponents.count == 4, 91 url.pathComponents[1] == "start" || url.pathComponents[1] == "starter-pack" { 92 return true ··· 109 self.webView?.load(URLRequest(url: url)) 110 } 111 } else { 112 - self.webView?.load(URLRequest(url: URL(string: "https://bsky.app/?splash=true&clip=true")!)) 113 } 114 } 115
··· 34 webView.navigationDelegate = self 35 self.view.addSubview(webView) 36 self.webView = webView 37 + self.webView?.load(URLRequest(url: URL(string: "https://social.shatteredsky.net/?splash=true&clip=true")!)) 38 } 39 40 func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) { ··· 86 } 87 88 switch host { 89 + case "social.shatteredsky.net": 90 if url.pathComponents.count == 4, 91 url.pathComponents[1] == "start" || url.pathComponents[1] == "starter-pack" { 92 return true ··· 109 self.webView?.load(URLRequest(url: url)) 110 } 111 } else { 112 + self.webView?.load(URLRequest(url: URL(string: "https://social.shatteredsky.net/?splash=true&clip=true")!)) 113 } 114 } 115
+1 -1
modules/expo-bluesky-swiss-army/src/Referrer/index.web.ts
··· 17 ) { 18 try { 19 const url = new URL(document.referrer) 20 - if (url.hostname !== 'bsky.app') { 21 return { 22 referrer: url.href, 23 hostname: url.hostname,
··· 17 ) { 18 try { 19 const url = new URL(document.referrer) 20 + if (url.hostname !== 'social.shatteredsky.net') { 21 return { 22 referrer: url.href, 23 hostname: url.hostname,
+2 -2
src/Navigation.tsx
··· 795 const LINKING = { 796 // TODO figure out what we are going to use 797 // note: `bluesky://` is what is used in app.config.js 798 - prefixes: ['bsky://', 'bluesky://', 'https://bsky.app'], 799 800 getPathFromState(state: State) { 801 // find the current node in the navigation tree ··· 1085 1086 if (isWeb) { 1087 const referrerInfo = Referrer.getReferrerInfo() 1088 - if (referrerInfo && referrerInfo.hostname !== 'bsky.app') { 1089 logEvent('deepLink:referrerReceived', { 1090 to: window.location.href, 1091 referrer: referrerInfo?.referrer,
··· 795 const LINKING = { 796 // TODO figure out what we are going to use 797 // note: `bluesky://` is what is used in app.config.js 798 + prefixes: ['bsky://', 'bluesky://', 'https://social.shatteredsky.net'], 799 800 getPathFromState(state: State) { 801 // find the current node in the navigation tree ··· 1085 1086 if (isWeb) { 1087 const referrerInfo = Referrer.getReferrerInfo() 1088 + if (referrerInfo && referrerInfo.hostname !== 'social.shatteredsky.net') { 1089 logEvent('deepLink:referrerReceived', { 1090 to: window.location.href, 1091 referrer: referrerInfo?.referrer,
+1 -1
src/lib/constants.ts
··· 14 export const HELP_DESK_URL = `https://github.com/NekoDrone/catsky-social/issues/new/choose` 15 export const EMBED_SERVICE = 'https://embed.bsky.app' 16 export const EMBED_SCRIPT = `${EMBED_SERVICE}/static/embed.js` 17 - export const BSKY_DOWNLOAD_URL = 'https://bsky.app/download' 18 export const STARTER_PACK_MAX_SIZE = 150 19 20 // HACK
··· 14 export const HELP_DESK_URL = `https://github.com/NekoDrone/catsky-social/issues/new/choose` 15 export const EMBED_SERVICE = 'https://embed.bsky.app' 16 export const EMBED_SCRIPT = `${EMBED_SERVICE}/static/embed.js` 17 + export const BSKY_DOWNLOAD_URL = 'https://social.shatteredsky.net/download' 18 export const STARTER_PACK_MAX_SIZE = 150 19 20 // HACK
+1 -1
src/lib/hooks/useIntentHandler.ts
··· 34 React.useEffect(() => { 35 const handleIncomingURL = (url: string) => { 36 const referrerInfo = Referrer.getReferrerInfo() 37 - if (referrerInfo && referrerInfo.hostname !== 'bsky.app') { 38 logger.metric('deepLink:referrerReceived', { 39 to: url, 40 referrer: referrerInfo?.referrer,
··· 34 React.useEffect(() => { 35 const handleIncomingURL = (url: string) => { 36 const referrerInfo = Referrer.getReferrerInfo() 37 + if (referrerInfo && referrerInfo.hostname !== 'social.shatteredsky.net') { 38 logger.metric('deepLink:referrerReceived', { 39 to: url, 40 referrer: referrerInfo?.referrer,
+2 -2
src/lib/routes/links.ts
··· 50 rkey?: string, 51 ) { 52 if (typeof starterPackOrName === 'string') { 53 - return `https://bsky.app/start/${starterPackOrName}/${rkey}` 54 } else { 55 const uriRkey = new AtUri(starterPackOrName.uri).rkey 56 - return `https://bsky.app/start/${starterPackOrName.creator.handle}/${uriRkey}` 57 } 58 }
··· 50 rkey?: string, 51 ) { 52 if (typeof starterPackOrName === 'string') { 53 + return `https://social.shatteredsky.net/start/${starterPackOrName}/${rkey}` 54 } else { 55 const uriRkey = new AtUri(starterPackOrName.uri).rkey 56 + return `https://social.shatteredsky.net/start/${starterPackOrName.creator.handle}/${uriRkey}` 57 } 58 }
+2 -2
src/lib/strings/embed-player.ts
··· 9 ? // @ts-ignore only for web 10 window.location.host === 'localhost:8100' 11 ? 'http://localhost:8100' 12 - : 'https://bsky.app' 13 : __DEV__ && !process.env.JEST_WORKER_ID 14 ? 'http://localhost:8100' 15 - : 'https://bsky.app' 16 17 export const embedPlayerSources = [ 18 'youtube',
··· 9 ? // @ts-ignore only for web 10 window.location.host === 'localhost:8100' 11 ? 'http://localhost:8100' 12 + : 'https://social.shatteredsky.net' 13 : __DEV__ && !process.env.JEST_WORKER_ID 14 ? 'http://localhost:8100' 15 + : 'https://social.shatteredsky.net' 16 17 export const embedPlayerSources = [ 18 'youtube',
+10 -3
src/lib/strings/url-helpers.ts
··· 7 import {startUriToStarterPackUri} from '#/lib/strings/starter-pack' 8 import {logger} from '#/logger' 9 10 - export const BSKY_APP_HOST = 'https://bsky.app' 11 const BSKY_TRUSTED_HOSTS = [ 12 'bsky\\.app', 13 'bsky\\.social', 14 'blueskyweb\\.xyz', ··· 91 } 92 93 export function isBskyAppUrl(url: string): boolean { 94 - return url.startsWith('https://bsky.app/') 95 } 96 97 export function isRelativeUrl(url: string): boolean { ··· 100 101 export function isBskyRSSUrl(url: string): boolean { 102 return ( 103 - (url.startsWith('https://bsky.app/') || isRelativeUrl(url)) && 104 /\/rss\/?$/.test(url) 105 ) 106 }
··· 7 import {startUriToStarterPackUri} from '#/lib/strings/starter-pack' 8 import {logger} from '#/logger' 9 10 + export const BSKY_APP_HOST = 'https://social.shatteredsky.net' 11 const BSKY_TRUSTED_HOSTS = [ 12 + 'social\\.shatteredsky\\.net', 13 + 'shatteredsky\\.net', 14 'bsky\\.app', 15 'bsky\\.social', 16 'blueskyweb\\.xyz', ··· 93 } 94 95 export function isBskyAppUrl(url: string): boolean { 96 + return ( 97 + url.startsWith('https://bsky.app/') || 98 + url.startsWith('https://social.shatteredsky.net/') 99 + ) 100 } 101 102 export function isRelativeUrl(url: string): boolean { ··· 105 106 export function isBskyRSSUrl(url: string): boolean { 107 return ( 108 + (url.startsWith('https://bsky.app/') || 109 + url.startsWith('https://social.shatteredsky.net/') || 110 + isRelativeUrl(url)) && 111 /\/rss\/?$/.test(url) 112 ) 113 }
+4 -2
src/screens/Moderation/index.tsx
··· 423 <Trans> 424 Adult content can only be enabled via the Web at{' '} 425 <InlineLinkText 426 - label={_(msg`The Bluesky web application`)} 427 to="" 428 onPress={evt => { 429 evt.preventDefault() 430 - Linking.openURL('https://bsky.app/') 431 return false 432 }}> 433 bsky.app
··· 423 <Trans> 424 Adult content can only be enabled via the Web at{' '} 425 <InlineLinkText 426 + label={_(msg`The Shattered Sky web application`)} 427 to="" 428 onPress={evt => { 429 evt.preventDefault() 430 + Linking.openURL( 431 + 'https://social.shatteredsky.net/', 432 + ) 433 return false 434 }}> 435 bsky.app