diff --git a/.forgejo/workflows/build.yml b/.forgejo/workflows/build.yml index 8b5eaef..35e0797 100644 --- a/.forgejo/workflows/build.yml +++ b/.forgejo/workflows/build.yml @@ -17,8 +17,6 @@ jobs: - name: Set up Docker Build Push Action uses: https://github.com/docker/build-push-action@v2 with: - tags: | - git.zio.sh/astra/bsky2tg:latest - git.zio.sh/astra/bsky2tg:${{ github.sha }} + tags: git.zio.sh/astra/bsky2tg:latest push: true load: false \ No newline at end of file diff --git a/README.md b/README.md index 8ee216b..b61cf15 100644 --- a/README.md +++ b/README.md @@ -16,12 +16,6 @@ BSKY_HANDLE= BSKY_PASSWORD= ``` -If you use a different Telegram bot endpoint, you can set it with - -```properties -TG_API_ENDPOINT=https://api.domain.com/bot%s/%s -``` - To run: ```bash diff --git a/bsky/bluesky.go b/bsky/bluesky.go index 1ca7bd5..38422f7 100644 --- a/bsky/bluesky.go +++ b/bsky/bluesky.go @@ -127,7 +127,7 @@ func (bluesky *Bluesky) CheckSessionValid() { type TelegramRecord struct { ChannelID int64 `json:"channel_id"` - MessageID []int `json:"message_id"` + MessageID int `json:"message_id"` Link *Link `json:"link"` Error string `json:"error"` Message string `json:"message"` diff --git a/bsky/parse.go b/bsky/parse.go index a06f131..c600af9 100644 --- a/bsky/parse.go +++ b/bsky/parse.go @@ -18,50 +18,42 @@ type Post struct { Facets *[]Facets `json:"facets,omitempty"` CreatedAt time.Time `json:"createdAt"` } - type Ref struct { Link string `json:"$link,omitempty"` } - type Thumb struct { Type string `json:"$type,omitempty"` Ref *Ref `json:"ref,omitempty"` MimeType string `json:"mimeType,omitempty"` Size int `json:"size,omitempty"` } - type External struct { URI string `json:"uri,omitempty"` Thumb *Thumb `json:"thumb,omitempty"` Title string `json:"title,omitempty"` Description string `json:"description,omitempty"` } - type Video struct { Type string `json:"$type,omitempty"` Ref *Ref `json:"ref,omitempty"` MimeType string `json:"mimeType,omitempty"` Size int `json:"size,omitempty"` } - type Image struct { Type string `json:"$type,omitempty"` Ref *Ref `json:"ref,omitempty"` MimeType string `json:"mimeType,omitempty"` Size int `json:"size,omitempty"` } - type AspectRatio struct { Width int `json:"width,omitempty"` Height int `json:"height,omitempty"` } - type Images struct { Alt string `json:"alt,omitempty"` Image *Image `json:"image,omitempty"` AspectRatio *AspectRatio `json:"aspectRatio,omitempty"` } - type Media struct { Type string `json:"$type,omitempty"` External *External `json:"external,omitempty"` @@ -69,19 +61,16 @@ type Media struct { Images *[]Images `json:"images,omitempty"` AspectRatio *AspectRatio `json:"aspectRatio,omitempty"` } - type Record struct { Cid string `json:"cid,omitempty"` URI string `json:"uri,omitempty"` } - type PostRecord struct { Type string `json:"$type,omitempty"` Cid string `json:"cid,omitempty"` URI string `json:"uri,omitempty"` Record *Record `json:"record,omitempty"` } - type Embed struct { Type string `json:"$type,omitempty"` Media *Media `json:"media,omitempty"` @@ -90,59 +79,35 @@ type Embed struct { Record *PostRecord `json:"record,omitempty"` External *External `json:"external,omitempty"` } - type Values struct { Val string `json:"val,omitempty"` } - type Labels struct { Type string `json:"$type,omitempty"` Values *[]Values `json:"values,omitempty"` } - type Root struct { Cid string `json:"cid,omitempty"` URI string `json:"uri,omitempty"` } - -func (r *Root) GetDID() string { - return strings.Split(r.URI, "/")[2] -} - -func (r *Root) GetRKey() string { - return strings.Split(r.URI, "/")[4] -} - type Parent struct { Cid string `json:"cid,omitempty"` URI string `json:"uri,omitempty"` } - -func (p *Parent) GetDID() string { - return strings.Split(p.URI, "/")[2] -} - -func (p *Parent) GetRKey() string { - return strings.Split(p.URI, "/")[4] -} - type Reply struct { Root *Root `json:"root,omitempty"` Parent *Parent `json:"parent,omitempty"` } - type Index struct { ByteEnd int `json:"byteEnd,omitempty"` ByteStart int `json:"byteStart,omitempty"` } - type Features struct { Did string `json:"did,omitempty"` URI string `json:"uri,omitempty"` Tag string `json:"tag,omitempty"` Type string `json:"$type,omitempty"` } - type Facets struct { Type string `json:"$type"` Index *Index `json:"index,omitempty"` @@ -153,7 +118,6 @@ type ParsedEmbeds struct { Type string MimeType string Ref string - Cid string URI string Width int64 Height int64 diff --git a/main.go b/main.go index 2f4ac7e..f59e825 100644 --- a/main.go +++ b/main.go @@ -21,6 +21,8 @@ import ( "git.zio.sh/astra/bsky2tg/bsky" tgbotapi "github.com/OvyFlash/telegram-bot-api" + // apibsky "github.com/bluesky-social/indigo/api/bsky" + "github.com/bluesky-social/jetstream/pkg/client" "github.com/bluesky-social/jetstream/pkg/client/schedulers/sequential" "github.com/bluesky-social/jetstream/pkg/models" @@ -84,15 +86,11 @@ func main() { handle, _ = bskyClient.ResolveHandle(s[1]) } - if handle != bskyClient.Bluesky.Cfg.DID { - log.Fatal("Unable to send posts from other accounts") - } - - tgpost, tgposterr := h.bsky.Bluesky.GetTelegramData(s[2]) if *delete { - if tgposterr == "" { - log.Printf("Found post %s in channel %d, deleting", s[2], tgpost.ChannelID) - m := tgbotapi.NewDeleteMessages(tgpost.ChannelID, tgpost.MessageID) + r, e := h.bsky.Bluesky.GetTelegramData(s[2]) + if e == "" { + log.Printf("Found post %s in channel %d, deleting", s[2], r.ChannelID) + m := tgbotapi.NewDeleteMessage(r.ChannelID, r.MessageID) h.tg.Send(m) h.bsky.Bluesky.DeleteRecord([]string{s[2], s[1], "blue.zio.bsky2tg.post"}) } else { @@ -101,11 +99,6 @@ func main() { return } - if tgpost.ChannelID != 0 { - log.Printf("Post %s already sent to channel %d, exiting", s[2], tgpost.ChannelID) - return - } - postJSON := bskyClient.Bluesky.FetchPost(handle, s[2]) p, _ := json.Marshal(postJSON.Record) h.ProcessPost(&models.Event{ @@ -142,6 +135,47 @@ func main() { log.Fatalf("failed to create client: %v", err) } + // ------------------------------------------------------------------------------ + // file, err := os.Open("posts.json") + // if err != nil { + // fmt.Printf("Error opening file: %v\n", err) + // return + // } + // defer file.Close() + // byteValue, err := io.ReadAll(file) + // if err != nil { + // fmt.Printf("Error reading file: %v\n", err) + // return + // } + + // var posts = struct { + // Records []struct { + // URI string `json:"uri"` + // CID string `json:"cid"` + // Value *bsky.Post `json:"value"` + // } `json:"records"` + // }{} + + // // 4. Unmarshal (decode) the JSON data into the struct + // err = json.Unmarshal(byteValue, &posts) + // if err != nil { + // fmt.Printf("Error unmarshaling JSON: %v\n", err) + // return + // } + // for _, post := range posts.Records { + // log.Printf("post: %s\n", post.Value.ProcessFacets(h.bsky.Bluesky.FetchAliases())) + // s, _ := json.Marshal(post.Value) + // h.ProcessPost(&models.Event{Did: bskyClient.Bluesky.Cfg.DID, Commit: &models.Commit{ + // Record: s, + // RKey: strings.Split(post.URI, "/")[4], + // CID: post.CID, + // Collection: "app.bsky.feed.post", + // }}) + // time.Sleep(time.Second * 2) + // } + // return + // ------------------------------------------------------------------------------ + cursor := time.Now().UnixMicro() restartCount := 0 loop: @@ -174,7 +208,7 @@ func (h *handler) HandleEvent(ctx context.Context, event *models.Event) error { bsky.PersistAuthSession(h.bsky.Bluesky.Cfg) r, e := h.bsky.Bluesky.GetTelegramData(event.Commit.RKey) if e == "" { - m := tgbotapi.NewDeleteMessages(r.ChannelID, r.MessageID) + m := tgbotapi.NewDeleteMessage(r.ChannelID, r.MessageID) h.tg.Send(m) h.bsky.Bluesky.DeleteRecord([]string{event.Commit.RKey, event.Did, "blue.zio.bsky2tg.post"}) } @@ -283,13 +317,9 @@ func (h *handler) ProcessPost(event *models.Event) error { } else { resp, _ := h.tg.SendMediaGroup(tgbotapi.NewMediaGroup(cid, mediaGroup)) uri, cid := getLink(event) - var messageIDs []int - for _, msgID := range resp { - messageIDs = append(messageIDs, msgID.MessageID) - } h.bsky.Bluesky.CommitTelegramResponse(&bsky.TelegramRecord{ ChannelID: resp[0].Chat.ID, - MessageID: messageIDs, + MessageID: resp[0].MessageID, Link: &bsky.Link{ Cid: cid, URI: uri, @@ -307,11 +337,10 @@ func (h *handler) ProcessPost(event *models.Event) error { if ps.IsQuotePost() { m.LinkPreviewOptions = tgbotapi.LinkPreviewOptions{ IsDisabled: false, - URL: fmt.Sprintf("https://fxbsky.app/profile/%s/post/%s", + URL: fmt.Sprintf("https://bsky.app/profile/%s/post/%s", strings.Split(ps.Embed.Record.URI, "/")[2], strings.Split(ps.Embed.Record.URI, "/")[4]), - PreferSmallMedia: false, - PreferLargeMedia: true, + PreferSmallMedia: true, ShowAboveText: true, } } else { @@ -321,7 +350,7 @@ func (h *handler) ProcessPost(event *models.Event) error { uri, cid := getLink(event) h.bsky.Bluesky.CommitTelegramResponse(&bsky.TelegramRecord{ ChannelID: resp.Chat.ID, - MessageID: []int{resp.MessageID}, + MessageID: resp.MessageID, Link: &bsky.Link{ Cid: cid, URI: uri, @@ -332,7 +361,7 @@ func (h *handler) ProcessPost(event *models.Event) error { } func buildBlobURL(server string, did string, cid string) string { - return server + "/xrpc/com.atproto.sync.getBlob?did=" + url.QueryEscape(did) + "&cid=" + cid + return server + "/xrpc/com.atproto.sync.getBlob?did=" + url.QueryEscape(did) + "&cid=" + url.QueryEscape(cid) } func getLink(event *models.Event) (string, string) {