Live video on the AT Protocol
79
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v0.8.13 121 lines 4.0 kB view raw
1package spxrpc 2 3import ( 4 "context" 5 "fmt" 6 "net/http" 7 "time" 8 9 comatprototypes "github.com/bluesky-social/indigo/api/atproto" 10 "github.com/bluesky-social/indigo/atproto/syntax" 11 "github.com/bluesky-social/indigo/xrpc" 12 "github.com/google/uuid" 13 "github.com/labstack/echo/v4" 14 "github.com/streamplace/oatproxy/pkg/oatproxy" 15 "stream.place/streamplace/pkg/config" 16 "stream.place/streamplace/pkg/log" 17 "stream.place/streamplace/pkg/media" 18 "stream.place/streamplace/pkg/model" 19) 20 21func (s *Server) handleComAtprotoModerationCreateReport(ctx context.Context, body *comatprototypes.ModerationCreateReport_Input) (*comatprototypes.ModerationCreateReport_Output, error) { 22 c, ok := ctx.Value(echoContextKey).(echo.Context) 23 if !ok { 24 return nil, echo.NewHTTPError(http.StatusInternalServerError, "echo context not found") 25 } 26 27 atprotoProxy := c.Request().Header.Get("Atproto-Proxy") 28 if atprotoProxy == "" { 29 if len(s.cli.Labelers) > 0 { 30 atprotoProxy = fmt.Sprintf("%s#atproto_labeler", s.cli.Labelers[0]) 31 } else { 32 return nil, echo.NewHTTPError(http.StatusBadRequest, "Atproto-Proxy header is required (where are you sending this report?)") 33 } 34 } 35 36 log.Log(ctx, "handleComAtprotoModerationCreateReport", "body", body) 37 38 session, client := oatproxy.GetOAuthSession(ctx) 39 if session == nil { 40 return nil, echo.NewHTTPError(http.StatusUnauthorized, "oauth session not found") 41 } 42 43 if body.Reason == nil { 44 empty := "" 45 body.Reason = &empty 46 } 47 48 if body.Subject == nil { 49 return nil, echo.NewHTTPError(http.StatusBadRequest, "subject is required") 50 } 51 52 var did string 53 54 if body.Subject.AdminDefs_RepoRef != nil { 55 d, err := syntax.ParseDID(body.Subject.AdminDefs_RepoRef.Did) 56 if err != nil { 57 return nil, echo.NewHTTPError(http.StatusBadRequest, "invalid subject did") 58 } 59 did = d.String() 60 } else if body.Subject.RepoStrongRef != nil { 61 aturi, err := syntax.ParseATURI(body.Subject.RepoStrongRef.Uri) 62 if err != nil { 63 return nil, echo.NewHTTPError(http.StatusBadRequest, "invalid subject uri") 64 } 65 did = aturi.Authority().String() 66 // if it's chat, we want the clip from the streamer, not from the chatter 67 if aturi.Collection() == "place.stream.chat.message" { 68 msg, err := s.model.GetChatMessage(body.Subject.RepoStrongRef.Uri) 69 if err != nil { 70 log.Error(ctx, "failed to get chat message for chat report", "error", err) 71 } else { 72 did = msg.StreamerRepoDID 73 } 74 } 75 } else { 76 return nil, echo.NewHTTPError(http.StatusBadRequest, "invalid subject") 77 } 78 79 clipID, err := makeClip(ctx, s.cli, s.model, did) 80 if err != nil { 81 // we still want the report to go through! 82 log.Error(ctx, "failed to make clip for report", "error", err) 83 } else { 84 clipURL := fmt.Sprintf("https://%s/api/clip/%s/%s.mp4", s.cli.BroadcasterHost, did, clipID) 85 newReason := fmt.Sprintf("%s\n\nClip: %s", *body.Reason, clipURL) 86 body.Reason = &newReason 87 } 88 89 client.SetHeaders(map[string]string{ 90 "Atproto-Proxy": atprotoProxy, 91 }) 92 93 var output comatprototypes.ModerationCreateReport_Output 94 err = client.Do(ctx, xrpc.Procedure, "application/json", "com.atproto.moderation.createReport", nil, body, &output) 95 if err != nil { 96 return nil, echo.NewHTTPError(http.StatusInternalServerError, err.Error()) 97 } 98 99 return &output, nil 100} 101 102func makeClip(ctx context.Context, cli *config.CLI, mod model.Model, did string) (string, error) { 103 after := time.Now().Add(-time.Duration(60) * time.Second) 104 105 uu, err := uuid.NewV7() 106 if err != nil { 107 return "", echo.NewHTTPError(http.StatusInternalServerError, "failed to generate uuid") 108 } 109 110 fd, err := cli.DataFileCreate([]string{did, "clips", fmt.Sprintf("%s.mp4", uu.String())}, false) 111 if err != nil { 112 return "", echo.NewHTTPError(http.StatusInternalServerError, "failed to create data file") 113 } 114 defer fd.Close() 115 116 err = media.ClipUser(ctx, mod, cli, did, fd, nil, &after) 117 if err != nil { 118 return "", echo.NewHTTPError(http.StatusInternalServerError, "failed to clip user") 119 } 120 return uu.String(), nil 121}