Live video on the AT Protocol
79
fork

Configure Feed

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

at next 89 lines 2.9 kB view raw
1package statedb 2 3import ( 4 "fmt" 5 6 "gorm.io/gorm" 7) 8 9// BrandingBlob stores branding assets for broadcasters 10type BrandingBlob struct { 11 gorm.Model 12 BroadcasterID string `gorm:"index:idx_broadcaster_key,priority:1,unique"` 13 Key string `gorm:"index:idx_broadcaster_key,priority:2,unique"` // "mainLogo", "favicon", "siteTitle", etc. 14 MimeType string // "image/svg+xml", "image/png", "text/plain" 15 Data []byte `gorm:"type:bytea"` // actual blob data 16 Width *int // image width in pixels (nullable) 17 Height *int // image height in pixels (nullable) 18} 19 20// GetBrandingBlob fetches a single branding asset 21func (state *StatefulDB) GetBrandingBlob(broadcasterID, key string) (*BrandingBlob, error) { 22 var blob BrandingBlob 23 err := state.DB.Where("broadcaster_id = ? AND key = ?", broadcasterID, key).First(&blob).Error 24 if err != nil { 25 return nil, err 26 } 27 return &blob, nil 28} 29 30// PutBrandingBlob stores or updates a branding asset 31func (state *StatefulDB) PutBrandingBlob(broadcasterID, key, mimeType string, data []byte, width, height *int) error { 32 // try to find existing blob (including soft-deleted ones) 33 var existing BrandingBlob 34 err := state.DB.Unscoped().Where("broadcaster_id = ? AND key = ?", broadcasterID, key).First(&existing).Error 35 36 if err == gorm.ErrRecordNotFound { 37 // create new blob 38 blob := BrandingBlob{ 39 BroadcasterID: broadcasterID, 40 Key: key, 41 MimeType: mimeType, 42 Data: data, 43 Width: width, 44 Height: height, 45 } 46 if err := state.DB.Create(&blob).Error; err != nil { 47 return fmt.Errorf("error creating branding blob: %w", err) 48 } 49 return nil 50 } else if err != nil { 51 return fmt.Errorf("error checking for existing branding blob: %w", err) 52 } 53 54 // update existing blob (restore if soft-deleted) 55 existing.MimeType = mimeType 56 existing.Data = data 57 existing.Width = width 58 existing.Height = height 59 existing.DeletedAt = gorm.DeletedAt{} // clear soft delete 60 if err := state.DB.Unscoped().Save(&existing).Error; err != nil { 61 return fmt.Errorf("error updating branding blob: %w", err) 62 } 63 64 return nil 65} 66 67// ListBrandingKeys returns all keys for a broadcaster 68func (state *StatefulDB) ListBrandingKeys(broadcasterID string) ([]string, error) { 69 var blobs []BrandingBlob 70 err := state.DB.Where("broadcaster_id = ?", broadcasterID).Select("key").Find(&blobs).Error 71 if err != nil { 72 return nil, err 73 } 74 75 keys := make([]string, len(blobs)) 76 for i, blob := range blobs { 77 keys[i] = blob.Key 78 } 79 return keys, nil 80} 81 82// DeleteBrandingBlob removes a specific asset 83func (state *StatefulDB) DeleteBrandingBlob(broadcasterID, key string) error { 84 err := state.DB.Where("broadcaster_id = ? AND key = ?", broadcasterID, key).Delete(&BrandingBlob{}).Error 85 if err != nil { 86 return fmt.Errorf("error deleting branding blob: %w", err) 87 } 88 return nil 89}