2022-12-10 21:43:11 +00:00
/ *
GoToSocial
2023-01-05 11:43:00 +00:00
Copyright ( C ) 2021 - 2023 GoToSocial Authors admin @ gotosocial . org
2022-12-10 21:43:11 +00:00
This program is free software : you can redistribute it and / or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation , either version 3 of the License , or
( at your option ) any later version .
This program is distributed in the hope that it will be useful ,
but WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
GNU Affero General Public License for more details .
You should have received a copy of the GNU Affero General Public License
along with this program . If not , see < http : //www.gnu.org/licenses/>.
* /
package media
import (
"context"
"errors"
"fmt"
"io"
"net/url"
"github.com/superseriousbusiness/gotosocial/internal/db"
"github.com/superseriousbusiness/gotosocial/internal/gtsmodel"
"github.com/superseriousbusiness/gotosocial/internal/log"
"github.com/superseriousbusiness/gotosocial/internal/util"
)
type DereferenceMedia func ( ctx context . Context , iri * url . URL ) ( io . ReadCloser , int64 , error )
func ( m * manager ) RefetchEmojis ( ctx context . Context , domain string , dereferenceMedia DereferenceMedia ) ( int , error ) {
// normalize domain
if domain == "" {
domain = db . EmojiAllDomains
}
var (
maxShortcodeDomain string
refetchIDs [ ] string
)
// page through emojis 20 at a time, looking for those with missing images
for {
// Fetch next block of emojis from database
2023-02-13 18:40:48 +00:00
emojis , err := m . state . DB . GetEmojis ( ctx , domain , false , true , "" , maxShortcodeDomain , "" , 20 )
2022-12-10 21:43:11 +00:00
if err != nil {
if ! errors . Is ( err , db . ErrNoEntries ) {
// an actual error has occurred
2023-02-17 11:02:29 +00:00
log . Errorf ( ctx , "error fetching emojis from database: %s" , err )
2022-12-10 21:43:11 +00:00
}
break
}
for _ , emoji := range emojis {
if emoji . Domain == "" {
// never try to refetch local emojis
continue
}
if refetch , err := m . emojiRequiresRefetch ( ctx , emoji ) ; err != nil {
// an error here indicates something is wrong with storage, so we should stop
return 0 , fmt . Errorf ( "error checking refetch requirement for emoji %s: %w" , util . ShortcodeDomain ( emoji ) , err )
} else if ! refetch {
continue
}
refetchIDs = append ( refetchIDs , emoji . ID )
}
// Update next maxShortcodeDomain from last emoji
maxShortcodeDomain = util . ShortcodeDomain ( emojis [ len ( emojis ) - 1 ] )
}
// bail early if we've got nothing to do
toRefetchCount := len ( refetchIDs )
if toRefetchCount == 0 {
2023-02-17 11:02:29 +00:00
log . Debug ( ctx , "no remote emojis require a refetch" )
2022-12-10 21:43:11 +00:00
return 0 , nil
}
2023-02-17 11:02:29 +00:00
log . Debugf ( ctx , "%d remote emoji(s) require a refetch, doing that now..." , toRefetchCount )
2022-12-10 21:43:11 +00:00
var totalRefetched int
for _ , emojiID := range refetchIDs {
2023-02-13 18:40:48 +00:00
emoji , err := m . state . DB . GetEmojiByID ( ctx , emojiID )
2022-12-10 21:43:11 +00:00
if err != nil {
// this shouldn't happen--since we know we have the emoji--so return if it does
return 0 , fmt . Errorf ( "error getting emoji %s: %w" , emojiID , err )
}
shortcodeDomain := util . ShortcodeDomain ( emoji )
if emoji . ImageRemoteURL == "" {
2023-02-17 11:02:29 +00:00
log . Errorf ( ctx , "remote emoji %s could not be refreshed because it has no ImageRemoteURL set" , shortcodeDomain )
2022-12-10 21:43:11 +00:00
continue
}
emojiImageIRI , err := url . Parse ( emoji . ImageRemoteURL )
if err != nil {
2023-02-17 11:02:29 +00:00
log . Errorf ( ctx , "remote emoji %s could not be refreshed because its ImageRemoteURL (%s) is not a valid uri: %s" , shortcodeDomain , emoji . ImageRemoteURL , err )
2022-12-10 21:43:11 +00:00
continue
}
dataFunc := func ( ctx context . Context ) ( reader io . ReadCloser , fileSize int64 , err error ) {
return dereferenceMedia ( ctx , emojiImageIRI )
}
2023-02-13 18:40:48 +00:00
processingEmoji , err := m . PreProcessEmoji ( ctx , dataFunc , nil , emoji . Shortcode , emoji . ID , emoji . URI , & AdditionalEmojiInfo {
2022-12-10 21:43:11 +00:00
Domain : & emoji . Domain ,
ImageRemoteURL : & emoji . ImageRemoteURL ,
ImageStaticRemoteURL : & emoji . ImageStaticRemoteURL ,
Disabled : emoji . Disabled ,
VisibleInPicker : emoji . VisibleInPicker ,
} , true )
if err != nil {
2023-02-17 11:02:29 +00:00
log . Errorf ( ctx , "emoji %s could not be refreshed because of an error during processing: %s" , shortcodeDomain , err )
2022-12-10 21:43:11 +00:00
continue
}
if _ , err := processingEmoji . LoadEmoji ( ctx ) ; err != nil {
2023-02-17 11:02:29 +00:00
log . Errorf ( ctx , "emoji %s could not be refreshed because of an error during loading: %s" , shortcodeDomain , err )
2022-12-10 21:43:11 +00:00
continue
}
2023-02-17 11:02:29 +00:00
log . Tracef ( ctx , "refetched emoji %s successfully from remote" , shortcodeDomain )
2022-12-10 21:43:11 +00:00
totalRefetched ++
}
return totalRefetched , nil
}
func ( m * manager ) emojiRequiresRefetch ( ctx context . Context , emoji * gtsmodel . Emoji ) ( bool , error ) {
2023-02-13 18:40:48 +00:00
if has , err := m . state . Storage . Has ( ctx , emoji . ImagePath ) ; err != nil {
2022-12-10 21:43:11 +00:00
return false , err
} else if ! has {
return true , nil
}
2023-02-13 18:40:48 +00:00
if has , err := m . state . Storage . Has ( ctx , emoji . ImageStaticPath ) ; err != nil {
2022-12-10 21:43:11 +00:00
return false , err
} else if ! has {
return true , nil
}
return false , nil
}