@@ -18,6 +18,7 @@ import (
1818 "io"
1919 "net/http"
2020 "os"
21+ "regexp"
2122 "strconv"
2223 "strings"
2324 "sync"
@@ -473,9 +474,57 @@ func (lc *LineClient) Connect(ctx context.Context) {
473474 }
474475
475476 go lc .syncChats (ctx )
477+ go lc .prefetchMessages (ctx )
476478 go lc .pollLoop (ctx )
477479}
478480
481+ func (lc * LineClient ) prefetchMessages (ctx context.Context ) {
482+ client := line .NewClient (lc .AccessToken )
483+ opts := line.MessageBoxesOptions {
484+ ActiveOnly : true ,
485+ MessageBoxCountLimit : 100 ,
486+ WithUnreadCount : true ,
487+ LastMessagesPerMessageBoxCount : 0 ,
488+ }
489+
490+ res , err := client .GetMessageBoxes (opts )
491+ if err != nil && lc .isRefreshRequired (err ) {
492+ if errRefresh := lc .refreshAndSave (ctx ); errRefresh == nil {
493+ client = line .NewClient (lc .AccessToken )
494+ res , err = client .GetMessageBoxes (opts )
495+ }
496+ }
497+ if err != nil {
498+ lc .UserLogin .Bridge .Log .Warn ().Err (err ).Msg ("Failed to prefetch message boxes" )
499+ return
500+ }
501+
502+ for _ , box := range res .MessageBoxes {
503+ // Fetch recent messages for all active chats to ensure history is populated
504+ msgs , err := client .GetRecentMessagesV2 (box .ID , 50 )
505+ if err != nil {
506+ lc .UserLogin .Bridge .Log .Warn ().Err (err ).Str ("chat_mid" , box .ID ).Msg ("Failed to fetch recent messages" )
507+ continue
508+ }
509+
510+ // Reverse messages to process oldest first
511+ for i := len (msgs ) - 1 ; i >= 0 ; i -- {
512+ msg := msgs [i ]
513+
514+ existing , err := lc .UserLogin .Bridge .DB .Message .GetPartByID (ctx , lc .UserLogin .ID , networkid .MessageID (msg .ID ), "" )
515+ if err == nil && existing != nil {
516+ continue
517+ }
518+
519+ opType := 26
520+ if msg .From == lc .Mid {
521+ opType = 25
522+ }
523+ lc .queueIncomingMessage (msg , opType )
524+ }
525+ }
526+ }
527+
479528func (lc * LineClient ) syncChats (ctx context.Context ) {
480529 client := line .NewClient (lc .AccessToken )
481530 midsResp , err := client .GetAllChatMids (true , true )
@@ -948,14 +997,20 @@ func (lc *LineClient) queueIncomingMessage(msg *line.Message, opType int) {
948997 }
949998 decryptedBody := bodyText
950999
1000+ tsInt , _ := msg .CreatedTime .Int64 ()
1001+ ts := time .UnixMilli (tsInt )
1002+ if ts .IsZero () {
1003+ ts = time .Now ()
1004+ }
1005+
9511006 lc .UserLogin .Bridge .QueueRemoteEvent (lc .UserLogin , & simplevent.Message [line.Message ]{
9521007 EventMeta : simplevent.EventMeta {
9531008 Type : bridgev2 .RemoteEventMessage ,
9541009 LogContext : func (c zerolog.Context ) zerolog.Context { return c .Str ("msg_id" , msg .ID ) },
9551010 PortalKey : portalKey ,
9561011 CreatePortal : true ,
9571012 Sender : bridgev2.EventSender {Sender : senderID , IsFromMe : opType == 25 },
958- Timestamp : time . Now () ,
1013+ Timestamp : ts ,
9591014 },
9601015 Data : * msg ,
9611016 ID : networkid .MessageID (msg .ID ),
@@ -1370,15 +1425,43 @@ func (lc *LineClient) queueIncomingMessage(msg *line.Message, opType int) {
13701425 }
13711426
13721427 // Default to Text
1428+ content := & event.MessageEventContent {
1429+ MsgType : event .MsgText ,
1430+ Body : unwrappedText ,
1431+ RelatesTo : replyRelatesTo ,
1432+ }
1433+
1434+ if strings .Contains (unwrappedText , "." ) {
1435+ urlRegex := regexp .MustCompile (`(https?://)?([a-zA-Z0-9.-]+\.[a-zA-Z]{2,})(/[^\s]*)?` )
1436+ if match := urlRegex .FindString (unwrappedText ); match != "" {
1437+ match = strings .TrimRight (match , ".,;:!?" )
1438+ requestURL := match
1439+ if ! strings .HasPrefix (match , "http" ) {
1440+ requestURL = "https://" + match
1441+ }
1442+ client := line .NewClient (lc .AccessToken )
1443+ if info , err := client .GetPageInfo (requestURL ); err == nil {
1444+ preview := & event.BeeperLinkPreview {
1445+ MatchedURL : match ,
1446+ LinkPreview : event.LinkPreview {
1447+ Title : info .Title ,
1448+ Description : info .Summary ,
1449+ CanonicalURL : info .Domain ,
1450+ },
1451+ }
1452+ if info .Image != "" && info .Obs .CDN != "" {
1453+ preview .ImageURL = id .ContentURIString (info .Obs .CDN + info .Image )
1454+ }
1455+ content .BeeperLinkPreviews = []* event.BeeperLinkPreview {preview }
1456+ }
1457+ }
1458+ }
1459+
13731460 return & bridgev2.ConvertedMessage {
13741461 Parts : []* bridgev2.ConvertedMessagePart {
13751462 {
1376- Type : event .EventMessage ,
1377- Content : & event.MessageEventContent {
1378- MsgType : event .MsgText ,
1379- Body : unwrappedText ,
1380- RelatesTo : replyRelatesTo ,
1381- },
1463+ Type : event .EventMessage ,
1464+ Content : content ,
13821465 },
13831466 },
13841467 }, nil
0 commit comments