@@ -5,6 +5,15 @@ import (
55 "encoding/json"
66 "errors"
77 "fmt"
8+ "log"
9+ "log/slog"
10+ "net/http"
11+ "regexp"
12+ "strconv"
13+ "strings"
14+ "sync"
15+ "time"
16+
817 "github.com/bwmarrin/discordgo"
918 "github.com/warmans/tvgif/pkg/discord/media"
1019 "github.com/warmans/tvgif/pkg/docs"
@@ -16,14 +25,6 @@ import (
1625 "github.com/warmans/tvgif/pkg/searchterms"
1726 "github.com/warmans/tvgif/pkg/store"
1827 "github.com/warmans/tvgif/pkg/util"
19- "log"
20- "log/slog"
21- "net/http"
22- "regexp"
23- "strconv"
24- "strings"
25- "sync"
26- "time"
2728)
2829
2930const SubSeparator = "---"
@@ -47,18 +48,18 @@ const (
4748
4849const (
4950 ActionOpenCustomTextModal = Action ("cstm" )
50- ActionOpenCaptionModal = Action ("ctm" )
5151 ActionOpenExtendTrimModal = Action ("oem" )
5252 ActionOpenMergeModal = Action ("omm" )
5353 ActionOpenAdvancedOverlayModal = Action ("aom" )
54+ ActionOpenTextOverlayModal = Action ("tom" )
5455)
5556
5657const (
5758 ModalSetSubs = Action ("m_ss" )
5859 ModalActionSetExtendValue = Action ("m_sev" )
5960 ModalActionMergeSubs = Action ("m_ms" )
60- ModalSetCaption = Action ("m_sc" )
6161 ModalSetBoomerOverlayLayout = Action ("m_bml" )
62+ ModalSetTextOverlayLayout = Action ("m_tol" )
6263)
6364
6465var postedByUser = regexp .MustCompile (`.+ posted by \x60([^\x60]+)\x60` )
@@ -202,18 +203,18 @@ func NewBot(
202203 ActionNextResult : bot .btnNextResult ,
203204 ActionPrevResult : bot .btnPreviewResult ,
204205 ActionOpenCustomTextModal : bot .btnOpenCustomTextModal ,
205- ActionOpenCaptionModal : bot .btnOpenCaptionModal ,
206206 ActionOpenExtendTrimModal : bot .btnOpenExtendModal ,
207207 ActionOpenMergeModal : bot .btnOpenMergeModal ,
208208 ActionOpenAdvancedOverlayModal : bot .btnOpenAdvancedOverlayModal ,
209+ ActionOpenTextOverlayModal : bot .btnOpenTextOverlayModal ,
209210 ActionUpdateState : bot .btnUpdateState ,
210211 }
211212 bot .modalHandlers = map [Action ]func (s * discordgo.Session , i * discordgo.InteractionCreate ){
212213 ModalSetSubs : bot .handleModalSetSubs ,
213- ModalSetCaption : bot .handleModalSetCaption ,
214214 ModalActionSetExtendValue : bot .handleModalSetExtendTrimValue ,
215215 ModalActionMergeSubs : bot .handleModalMergeSubs ,
216216 ModalSetBoomerOverlayLayout : bot .handleModalBoomerModeLayout ,
217+ ModalSetTextOverlayLayout : bot .handleModalTextOverlayLayout ,
217218 }
218219
219220 return bot , nil
@@ -704,45 +705,6 @@ func (b *Bot) btnOpenCustomTextModal(s *discordgo.Session, i *discordgo.Interact
704705 }
705706}
706707
707- func (b * Bot ) btnOpenCaptionModal (s * discordgo.Session , i * discordgo.InteractionCreate , rawMediaID string ) {
708- mediaID , err := media .ParseID (rawMediaID )
709- if err != nil {
710- b .respondError (s , i , fmt .Errorf ("invalid mediaID" ))
711- return
712- }
713-
714- state , err := extractStateFromBody (i .Message .Content )
715- if err != nil {
716- b .respondError (s , i , fmt .Errorf ("failed to get current state" ))
717- return
718- }
719-
720- fields := []discordgo.MessageComponent {discordgo.ActionsRow {
721- Components : []discordgo.MessageComponent {
722- discordgo.TextInput {
723- CustomID : "caption" ,
724- Label : "Caption" ,
725- Style : discordgo .TextInputParagraph ,
726- Required : true ,
727- MaxLength : 128 ,
728- Value : state .Settings .Caption ,
729- Placeholder : "Caption added to top of image" ,
730- },
731- },
732- }}
733- err = s .InteractionRespond (i .Interaction , & discordgo.InteractionResponse {
734- Type : discordgo .InteractionResponseModal ,
735- Data : & discordgo.InteractionResponseData {
736- CustomID : encodeAction (ModalSetCaption , mediaID ),
737- Title : "Set Caption" ,
738- Components : fields ,
739- },
740- })
741- if err != nil {
742- b .respondError (s , i , err )
743- }
744- }
745-
746708func (b * Bot ) btnOpenExtendModal (s * discordgo.Session , i * discordgo.InteractionCreate , rawMediaID string ) {
747709 state , err := extractStateFromBody (i .Message .Content )
748710 if err != nil {
@@ -801,6 +763,28 @@ func (b *Bot) btnOpenAdvancedOverlayModal(s *discordgo.Session, i *discordgo.Int
801763 )
802764}
803765
766+ func (b * Bot ) btnOpenTextOverlayModal (s * discordgo.Session , i * discordgo.InteractionCreate , rawMediaID string ) {
767+ state , err := extractStateFromBody (i .Message .Content )
768+ if err != nil {
769+ b .respondError (s , i , fmt .Errorf ("failed to get current state" ))
770+ return
771+ }
772+
773+ b .openGenericValueModal (
774+ s ,
775+ i ,
776+ rawMediaID ,
777+ ModalSetTextOverlayLayout ,
778+ "Text Layout" ,
779+ util .IfElse (
780+ state .Settings .TextOverlayLayout != "" ,
781+ state .Settings .TextOverlayLayout ,
782+ b .getTextOverlayInitialLayout (),
783+ ),
784+ discordgo .TextInputParagraph ,
785+ )
786+ }
787+
804788func (b * Bot ) openGenericValueModal (
805789 s * discordgo.Session ,
806790 i * discordgo.InteractionCreate ,
@@ -969,17 +953,6 @@ func (b *Bot) createButtons(dialog []model2.Dialog, state *PreviewState) ([]disc
969953 }
970954 extendButtons := []discordgo.MessageComponent {}
971955
972- if dialogDuration + (time .Second / 2 ) <= limits .MaxGifDuration {
973- extendButtons = append (extendButtons , discordgo.Button {
974- Label : "0.5s" ,
975- Emoji : & discordgo.ComponentEmoji {
976- Name : "➕" ,
977- },
978- Style : discordgo .SecondaryButton ,
979- Disabled : false ,
980- CustomID : StateSetExtendOrTrim (state .Settings .ExtendOrTrim + (time .Second / 2 )).CustomID (),
981- })
982- }
983956 if dialogDuration + time .Second <= limits .MaxGifDuration {
984957 extendButtons = append (extendButtons , discordgo.Button {
985958 Label : "1s" ,
@@ -1060,16 +1033,7 @@ func (b *Bot) createButtons(dialog []model2.Dialog, state *PreviewState) ([]disc
10601033 CustomID : StateSetMode (NormalMode ).CustomID (),
10611034 },
10621035 discordgo.Button {
1063- Label : "Caption" ,
1064- Emoji : & discordgo.ComponentEmoji {
1065- Name : "🎨" ,
1066- },
1067- Style : successBtnIfTrue (state .Settings .Mode == CaptionMode ),
1068- Disabled : false ,
1069- CustomID : StateSetMode (CaptionMode ).CustomID (),
1070- },
1071- discordgo.Button {
1072- Label : "Boomer" ,
1036+ Label : "Overlay" ,
10731037 Emoji : & discordgo.ComponentEmoji {
10741038 Name : "🎨" ,
10751039 },
@@ -1080,20 +1044,6 @@ func (b *Bot) createButtons(dialog []model2.Dialog, state *PreviewState) ([]disc
10801044 }
10811045
10821046 captionButtons := []discordgo.MessageComponent {}
1083- if state .Settings .Mode == CaptionMode {
1084- captionButtons = append (captionButtons , discordgo.Button {
1085- Label : "Set Caption" ,
1086- Style : discordgo .SecondaryButton ,
1087- Disabled : false ,
1088- CustomID : encodeAction (ActionOpenCaptionModal , state .ID ),
1089- })
1090- captionButtons = append (captionButtons , discordgo.Button {
1091- Label : "Toggle Subs" ,
1092- Style : discordgo .SecondaryButton ,
1093- Disabled : false ,
1094- CustomID : StateSetSubsEnabled (! state .Settings .SubsEnabled ).CustomID (),
1095- })
1096- }
10971047
10981048 boomerButtons := []discordgo.MessageComponent {}
10991049 if state .Settings .Mode == BoomerMode {
@@ -1115,6 +1065,15 @@ func (b *Bot) createButtons(dialog []model2.Dialog, state *PreviewState) ([]disc
11151065 Disabled : false ,
11161066 URL : "http://tvgif.scrimpton.com:8080/overlays/index.html" ,
11171067 })
1068+ captionButtons = append (captionButtons , discordgo.Button {
1069+ Label : "Add Text" ,
1070+ Emoji : & discordgo.ComponentEmoji {
1071+ Name : "💬" ,
1072+ },
1073+ Style : successBtnIfTrue (state .Settings .TextOverlayLayout != "" ),
1074+ Disabled : false ,
1075+ CustomID : encodeAction (ActionOpenTextOverlayModal , state .ID ),
1076+ })
11181077 }
11191078
11201079 postActions := []discordgo.MessageComponent {discordgo.Button {
@@ -1159,7 +1118,7 @@ func (b *Bot) createButtons(dialog []model2.Dialog, state *PreviewState) ([]disc
11591118 },
11601119 discordgo.Button {
11611120 Label : "Toggle Preview" ,
1162- Style : successBtnIfTrue (state .Settings .Mode == CaptionMode ),
1121+ Style : successBtnIfTrue (state .Settings .DisablePreviewImage ),
11631122 Disabled : false ,
11641123 CustomID : TogglePreview ().CustomID (),
11651124 },
@@ -1169,10 +1128,10 @@ func (b *Bot) createButtons(dialog []model2.Dialog, state *PreviewState) ([]disc
11691128 if len (navigateButtons ) > 0 && state .Settings .Mode == NormalMode {
11701129 actions = append (actions , discordgo.ActionsRow {Components : navigateButtons })
11711130 }
1172- if len (shiftButtons ) > 0 && state . Settings . Mode != CaptionMode {
1131+ if len (shiftButtons ) > 0 {
11731132 actions = append (actions , discordgo.ActionsRow {Components : shiftButtons })
11741133 }
1175- if len (extendButtons ) > 0 && state . Settings . Mode != CaptionMode {
1134+ if len (extendButtons ) > 0 {
11761135 actions = append (actions , discordgo.ActionsRow {Components : extendButtons })
11771136 }
11781137
@@ -1269,16 +1228,6 @@ func (b *Bot) btnUpdateState(s *discordgo.Session, i *discordgo.InteractionCreat
12691228 b .updatePreview (s , i , update )
12701229}
12711230
1272- func (b * Bot ) handleModalSetCaption (s * discordgo.Session , i * discordgo.InteractionCreate ) {
1273- b .updatePreview (
1274- s ,
1275- i ,
1276- StateSetCaption (
1277- i .Interaction .ModalSubmitData ().Components [0 ].(* discordgo.ActionsRow ).Components [0 ].(* discordgo.TextInput ).Value ,
1278- ),
1279- )
1280- }
1281-
12821231func (b * Bot ) handleModalSetSubs (s * discordgo.Session , i * discordgo.InteractionCreate ) {
12831232 b .updatePreview (
12841233 s ,
@@ -1361,6 +1310,16 @@ func (b *Bot) handleModalBoomerModeLayout(s *discordgo.Session, i *discordgo.Int
13611310 )
13621311}
13631312
1313+ func (b * Bot ) handleModalTextOverlayLayout (s * discordgo.Session , i * discordgo.InteractionCreate ) {
1314+ b .updatePreview (
1315+ s ,
1316+ i ,
1317+ SetTextOverlayLayout (
1318+ i .Interaction .ModalSubmitData ().Components [0 ].(* discordgo.ActionsRow ).Components [0 ].(* discordgo.TextInput ).Value ,
1319+ ),
1320+ )
1321+ }
1322+
13641323func (b * Bot ) btnPostFromPreview (s * discordgo.Session , i * discordgo.InteractionCreate , payload string ) {
13651324
13661325 if err := s .InteractionRespond (i .Interaction , & discordgo.InteractionResponse {
@@ -1555,7 +1514,7 @@ func (b *Bot) respondError(s *discordgo.Session, i *discordgo.InteractionCreate,
15551514
15561515func (b * Bot ) renderFile (state * PreviewState , dialog []model2.Dialog , preview bool ) (* discordgo.File , error ) {
15571516
1558- disableCaching := state .Settings .ExtendOrTrim != 0 || state .Settings .Shift != 0 || state .Settings .OverrideSubs != nil || (state .Settings .Mode != NormalMode )
1517+ disableCaching := state .Settings .ExtendOrTrim != 0 || state .Settings .Shift != 0 || state .Settings .OverrideSubs != nil || (state .Settings .Mode != NormalMode ) || state . Settings . TextOverlayLayout != ""
15591518 startTimestamp := dialog [0 ].StartTimestamp
15601519 endTimestamp := dialog [len (dialog )- 1 ].EndTimestamp
15611520
@@ -1589,20 +1548,14 @@ func (b *Bot) renderFile(state *PreviewState, dialog []model2.Dialog, preview bo
15891548 render .WithCustomText (state .Settings .OverrideSubs ),
15901549 render .WithStartTimestamp (startTimestamp ),
15911550 render .WithEndTimestamp (endTimestamp ),
1551+ render .WithTextOverlayLayout (state .Settings .TextOverlayLayout ),
15921552 }
15931553 if state .Settings .Mode == BoomerMode {
15941554 options = append (options ,
15951555 render .WithOverlayLayout (util .IfElse (state .Settings .BoomerModeOpts .Layout != "" , state .Settings .BoomerModeOpts .Layout , "" )),
15961556 render .WithGrid (preview ),
15971557 )
15981558 }
1599- if state .Settings .Mode == CaptionMode {
1600- options = append (options ,
1601- render .WithCaptionMode (true ),
1602- render .WithCaption (state .Settings .Caption ),
1603- render .WithDisableSubs (state .Settings .SubsEnabled ),
1604- )
1605- }
16061559 if state .Settings .Mode == StickerMode {
16071560 var opts * render.StickerModeOpts
16081561
@@ -1817,6 +1770,24 @@ func (b *Bot) getBoomerModeInitialLayout() string {
18171770 return strings .Join (out , "\n " )
18181771}
18191772
1773+ func (b * Bot ) getTextOverlayInitialLayout () string {
1774+ return `# Remove hash to enable a text overlay.
1775+ # Each line is one text element:
1776+ #
1777+ # [X cell]x[Y cell] [start seconds]-[end seconds] [scale] [text]
1778+ #
1779+ # Use * as the time range to show the text for the whole gif.
1780+ # Cell numbers are decimals and start at 0 (so you can do e.g. 3.5).
1781+ # The scale is optional e.g. 1 = 100%, 2 = 200%, 0.5 = 50%.
1782+ #
1783+ # Examples:
1784+ # 3x0.5 * hello world
1785+ # 0x4 0.5-2 shown from 0.5s to 2s
1786+ # 5x2 1-* shown from 1s to the end
1787+ # 2x2 * 2 double size text
1788+ `
1789+ }
1790+
18201791func encodeAction (action Action , mediaID * media.ID ) string {
18211792 return fmt .Sprintf ("%s:%s" , action , mediaID .String ())
18221793}
0 commit comments