Compare commits
10 Commits
6846cca5b0
...
875b8e21da
Author | SHA1 | Date | |
---|---|---|---|
875b8e21da | |||
9e4553c6f3 | |||
238421c69f | |||
c33fa8a4f4 | |||
db55335add | |||
0dfeb43124 | |||
d302522256 | |||
bd86426553 | |||
2f01c1e500 | |||
81fcc84741 |
@ -80,5 +80,11 @@ func main() {
|
||||
targetService,
|
||||
fileService,
|
||||
authClient,
|
||||
cfg.Cors.AllowedOrigins,
|
||||
cfg.Cors.AllowedMethods,
|
||||
cfg.Cors.AllowedHeaders,
|
||||
cfg.Cors.AllowCredentials,
|
||||
cfg.Cors.ExposeHeaders,
|
||||
cfg.Cors.MaxAge,
|
||||
)
|
||||
}
|
||||
|
@ -10,8 +10,8 @@ services:
|
||||
environment:
|
||||
- GO_ENV=production
|
||||
restart: always
|
||||
networks:
|
||||
- donat-network
|
||||
# networks:
|
||||
# - donat-network
|
||||
volumes:
|
||||
- ./storage:/storage
|
||||
|
||||
@ -20,12 +20,13 @@ services:
|
||||
image: postgres:16.3-alpine3.20
|
||||
env_file:
|
||||
- .env
|
||||
networks:
|
||||
- donat-network
|
||||
# networks:
|
||||
# - donat-network
|
||||
ports:
|
||||
- "31002:5432"
|
||||
volumes:
|
||||
- ./docker/postgres/data:/var/lib/postgresql/data
|
||||
networks:
|
||||
donat-network:
|
||||
external: true
|
||||
- ./sql:/docker-entrypoint-initdb.d
|
||||
#networks:
|
||||
# donat-network:
|
||||
# external: true
|
@ -46,6 +46,7 @@ func CreateDonat(donatService model.DonatService) echo.HandlerFunc {
|
||||
body.DonatUser,
|
||||
body.TargetID,
|
||||
body.Amount,
|
||||
body.MediaUrl,
|
||||
)
|
||||
if err != nil {
|
||||
return request.JSON(http.StatusInternalServerError, err.Error())
|
||||
@ -91,6 +92,7 @@ func CreateTestDonat(donatService model.DonatService) echo.HandlerFunc {
|
||||
body.Text,
|
||||
body.DonatUser,
|
||||
body.TargetID,
|
||||
body.MediaUrl,
|
||||
body.Amount,
|
||||
)
|
||||
|
||||
|
@ -48,6 +48,7 @@ func CreateWidget(widgetService model.WidgetService) echo.HandlerFunc {
|
||||
body.Audio,
|
||||
body.Name,
|
||||
body.IsActive,
|
||||
body.VolumePercent,
|
||||
)
|
||||
if err != nil {
|
||||
slog.Error(err.Error())
|
||||
|
@ -28,23 +28,24 @@ func NewApp(
|
||||
targetService model.TargetService,
|
||||
fileService model.FileService,
|
||||
authClient model.AuthClient,
|
||||
allowOrigins []string,
|
||||
allowMethods []string,
|
||||
allowHeaders []string,
|
||||
allowCredentials bool,
|
||||
exposeHeaders []string,
|
||||
maxAge int,
|
||||
) {
|
||||
server := echo.New()
|
||||
|
||||
server.Use(
|
||||
middleware.CORSWithConfig(
|
||||
middleware.CORSConfig{
|
||||
AllowOrigins: []string{
|
||||
"https://donatehelper.com",
|
||||
"https://donatehelper.com",
|
||||
"https://widget.donatehelper.com",
|
||||
"http://widget.donatehelper.com",
|
||||
"http://127.0.0.1:8002",
|
||||
},
|
||||
AllowHeaders: []string{"Content-Type", "Authorization", "X-Requested-With"},
|
||||
AllowCredentials: true,
|
||||
ExposeHeaders: []string{"Content-Length"},
|
||||
MaxAge: 86400,
|
||||
AllowOrigins: allowOrigins,
|
||||
AllowMethods: allowMethods,
|
||||
AllowHeaders: allowHeaders,
|
||||
AllowCredentials: allowCredentials,
|
||||
ExposeHeaders: exposeHeaders,
|
||||
MaxAge: maxAge,
|
||||
},
|
||||
),
|
||||
)
|
||||
|
@ -13,6 +13,7 @@ type Config struct {
|
||||
StreamerService StreamerService `yaml:"streamerService"`
|
||||
TtsHost string `yaml:"ttsHost"`
|
||||
HOST string `yaml:"host"`
|
||||
Cors CorsConfig `yaml:"cors"`
|
||||
}
|
||||
|
||||
type Database struct {
|
||||
@ -46,6 +47,15 @@ type StreamerService struct {
|
||||
Port string `yaml:"port"`
|
||||
}
|
||||
|
||||
type CorsConfig struct {
|
||||
AllowedOrigins []string `yaml:"allow_origins"`
|
||||
AllowedMethods []string `yaml:"allow_methods"`
|
||||
AllowedHeaders []string `yaml:"allow_headers"`
|
||||
AllowCredentials bool `yaml:"allow_credentials"`
|
||||
ExposeHeaders []string `yaml:"expose_headers"`
|
||||
MaxAge int `yaml:"max_age"`
|
||||
}
|
||||
|
||||
func Init() *Config {
|
||||
data, err := os.ReadFile("internal/config/config.yaml")
|
||||
if err != nil {
|
||||
|
@ -1665,6 +1665,9 @@ const docTemplate = `{
|
||||
"donatUser": {
|
||||
"type": "string"
|
||||
},
|
||||
"mediaUrl": {
|
||||
"type": "string"
|
||||
},
|
||||
"targetID": {
|
||||
"type": "integer"
|
||||
},
|
||||
@ -1729,6 +1732,10 @@ const docTemplate = `{
|
||||
"template_id": {
|
||||
"type": "integer",
|
||||
"example": 1
|
||||
},
|
||||
"volume_percent": {
|
||||
"type": "integer",
|
||||
"example": 50
|
||||
}
|
||||
}
|
||||
},
|
||||
@ -2041,6 +2048,11 @@ const docTemplate = `{
|
||||
"type": "string",
|
||||
"format": "date-time",
|
||||
"example": "2025-03-07T10:15:30Z"
|
||||
},
|
||||
"volume_percent": {
|
||||
"type": "integer",
|
||||
"format": "int64",
|
||||
"example": 50
|
||||
}
|
||||
}
|
||||
},
|
||||
@ -2257,6 +2269,10 @@ const docTemplate = `{
|
||||
"voice_speed": {
|
||||
"description": "Добавляем новые поля для настроек голоса",
|
||||
"type": "string"
|
||||
},
|
||||
"volume_percent": {
|
||||
"type": "integer",
|
||||
"example": 100
|
||||
}
|
||||
}
|
||||
},
|
||||
@ -2371,6 +2387,10 @@ const docTemplate = `{
|
||||
"name": {
|
||||
"type": "string",
|
||||
"example": "Awesome Widget"
|
||||
},
|
||||
"volume_percent": {
|
||||
"type": "integer",
|
||||
"example": 50
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -1658,6 +1658,9 @@
|
||||
"donatUser": {
|
||||
"type": "string"
|
||||
},
|
||||
"mediaUrl": {
|
||||
"type": "string"
|
||||
},
|
||||
"targetID": {
|
||||
"type": "integer"
|
||||
},
|
||||
@ -1722,6 +1725,10 @@
|
||||
"template_id": {
|
||||
"type": "integer",
|
||||
"example": 1
|
||||
},
|
||||
"volume_percent": {
|
||||
"type": "integer",
|
||||
"example": 50
|
||||
}
|
||||
}
|
||||
},
|
||||
@ -2034,6 +2041,11 @@
|
||||
"type": "string",
|
||||
"format": "date-time",
|
||||
"example": "2025-03-07T10:15:30Z"
|
||||
},
|
||||
"volume_percent": {
|
||||
"type": "integer",
|
||||
"format": "int64",
|
||||
"example": 50
|
||||
}
|
||||
}
|
||||
},
|
||||
@ -2250,6 +2262,10 @@
|
||||
"voice_speed": {
|
||||
"description": "Добавляем новые поля для настроек голоса",
|
||||
"type": "string"
|
||||
},
|
||||
"volume_percent": {
|
||||
"type": "integer",
|
||||
"example": 100
|
||||
}
|
||||
}
|
||||
},
|
||||
@ -2364,6 +2380,10 @@
|
||||
"name": {
|
||||
"type": "string",
|
||||
"example": "Awesome Widget"
|
||||
},
|
||||
"volume_percent": {
|
||||
"type": "integer",
|
||||
"example": 50
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -15,6 +15,8 @@ definitions:
|
||||
type: integer
|
||||
donatUser:
|
||||
type: string
|
||||
mediaUrl:
|
||||
type: string
|
||||
targetID:
|
||||
type: integer
|
||||
text:
|
||||
@ -55,6 +57,9 @@ definitions:
|
||||
template_id:
|
||||
example: 1
|
||||
type: integer
|
||||
volume_percent:
|
||||
example: 50
|
||||
type: integer
|
||||
required:
|
||||
- audio
|
||||
- duration
|
||||
@ -294,6 +299,10 @@ definitions:
|
||||
example: "2025-03-07T10:15:30Z"
|
||||
format: date-time
|
||||
type: string
|
||||
volume_percent:
|
||||
example: 50
|
||||
format: int64
|
||||
type: integer
|
||||
type: object
|
||||
donat-widget_internal_model.InitNewStreamerBody:
|
||||
properties:
|
||||
@ -440,6 +449,9 @@ definitions:
|
||||
voice_speed:
|
||||
description: Добавляем новые поля для настроек голоса
|
||||
type: string
|
||||
volume_percent:
|
||||
example: 100
|
||||
type: integer
|
||||
type: object
|
||||
donat-widget_internal_model.TextAfterPaidDonat:
|
||||
properties:
|
||||
@ -517,6 +529,9 @@ definitions:
|
||||
name:
|
||||
example: Awesome Widget
|
||||
type: string
|
||||
volume_percent:
|
||||
example: 50
|
||||
type: integer
|
||||
type: object
|
||||
donat-widget_internal_model.VoiceSettingsResponse:
|
||||
properties:
|
||||
|
@ -26,6 +26,7 @@ type WidgetService interface {
|
||||
audio string,
|
||||
name string,
|
||||
isActive bool,
|
||||
volumePercent int,
|
||||
) (GetWidgetDb, error)
|
||||
GetWidgetsByStreamer(ctx context.Context, streamerID int) (AllWidgets, error)
|
||||
UpdateWidget(ctx context.Context, updateWidget UpdateWidget, widgetID, accountID int) error
|
||||
@ -45,6 +46,7 @@ type WidgetRepo interface {
|
||||
audio string,
|
||||
name string,
|
||||
isActive bool,
|
||||
volumePercent int,
|
||||
) (WidgetID, error)
|
||||
CheckWidgetName(ctx context.Context, streamerID int, name string) (bool, error)
|
||||
GetWidgetsByStreamerID(ctx context.Context, streamerID int) ([]*GetWidgetDb, error)
|
||||
@ -58,6 +60,7 @@ type WidgetRepo interface {
|
||||
image *uuid.UUID,
|
||||
audio *uuid.UUID,
|
||||
name *string,
|
||||
volumePercent *int,
|
||||
) error
|
||||
CheckExistsWidget(ctx context.Context, widgetID, accountID int) error
|
||||
GetWidgetByID(ctx context.Context, widgetID int) (GetWidgetDb, error)
|
||||
@ -73,13 +76,21 @@ type DonatService interface {
|
||||
|
||||
CheckToken(request echo.Context) (api.CheckTokenResponse, error)
|
||||
|
||||
CreateDonat(ctx context.Context, streamerLogin, text, donatUser string, targetID *int, amount int) (CreateDonatResponse, error)
|
||||
CreateDonat(
|
||||
ctx context.Context,
|
||||
streamerLogin, text,
|
||||
donatUser string,
|
||||
targetID *int,
|
||||
amount int,
|
||||
mediaUrl *string,
|
||||
) (CreateDonatResponse, error)
|
||||
CreateTestDonat(
|
||||
ctx context.Context,
|
||||
streamerID int,
|
||||
text string,
|
||||
donatUser string,
|
||||
targetID *int,
|
||||
mediaURL *string,
|
||||
amount int,
|
||||
) error
|
||||
|
||||
@ -139,6 +150,7 @@ type DonatRepo interface {
|
||||
amount int,
|
||||
text string,
|
||||
donatUser string,
|
||||
mediaUrl *string,
|
||||
status string,
|
||||
) error
|
||||
|
||||
|
@ -25,6 +25,7 @@ type GetWidgetDb struct {
|
||||
Duration int `db:"duration" json:"duration" example:"30" format:"int64" description:"Duration of the widget"`
|
||||
MinAmount int `db:"min_amount" json:"min_amount" example:"100" format:"int64" description:"Minimum donation amount"`
|
||||
MaxAmount int `db:"max_amount" json:"max_amount" example:"1000" format:"int64" description:"Maximum donation amount"`
|
||||
VolumePercent int `db:"volume_percent" json:"volume_percent" example:"50" format:"int64" description:"Volume percentage of the widget"`
|
||||
CreatedAt time.Time `db:"created_at" json:"created_at" format:"date-time" example:"2025-03-06T13:37:36Z" description:"Timestamp when the widget was created"`
|
||||
UpdatedAt time.Time `db:"updated_at" json:"updated_at" format:"date-time" example:"2025-03-07T10:15:30Z" description:"Timestamp when the widget was last updated"`
|
||||
GroupID int `db:"group_id" json:"group_id" example:"2" format:"int64" description:"Group ID associated with the widget"`
|
||||
@ -58,6 +59,7 @@ type UpdateWidget struct {
|
||||
Name *string `json:"name" example:"Awesome Widget" description:"Name of the widget"`
|
||||
Image *uuid.UUID `json:"image" example:"d2c2f03f-3fe5-4bfc-b963-5478a057149e" description:"UUID of the widget image"`
|
||||
Audio *uuid.UUID `json:"audio" example:"a0f9e244-f61f-4bfe-a7a0-3b5e91fe7364" description:"UUID of the widget audio file"`
|
||||
VolumePercent *int `json:"volume_percent" example:"50" description:"Volume percentage of the widget"`
|
||||
Duration *int `json:"duration" example:"120" description:"Duration of the widget in seconds"`
|
||||
MinAmount *int `json:"min_amount" example:"10" description:"Minimum amount for the widget"`
|
||||
MaxAmount *int `json:"max_amount" example:"100" description:"Maximum amount for the widget"`
|
||||
@ -255,6 +257,7 @@ type CreateWidgetBody struct {
|
||||
Audio string `json:"audio" validate:"required" format:"uuid" example:"550e8400-e29b-41d4-a716-446655440001"`
|
||||
MinAmount int `json:"min_amount" validate:"required" example:"10"`
|
||||
MaxAmount int `json:"max_amount" validate:"required" example:"100"`
|
||||
VolumePercent int `json:"volume_percent" example:"50" description:"Volume percentage of the widget"`
|
||||
}
|
||||
|
||||
type DonatAndWidget struct {
|
||||
@ -267,6 +270,7 @@ type CreateDonatBody struct {
|
||||
Amount int `json:"amount"`
|
||||
Text string `json:"text"`
|
||||
DonatUser string `json:"donatUser"`
|
||||
MediaUrl *string `json:"mediaUrl"`
|
||||
}
|
||||
|
||||
type DonationStat struct {
|
||||
@ -328,6 +332,7 @@ type MarkDonatViewed struct {
|
||||
|
||||
type PlayingDonat struct {
|
||||
Duration int `json:"duration" example:"30"`
|
||||
VolumePercent int `json:"volume_percent" example:"100"`
|
||||
Image *string `json:"image_link"`
|
||||
Audio *string `json:"audio_link"`
|
||||
Text string `json:"text"`
|
||||
@ -341,6 +346,7 @@ type PlayingDonat struct {
|
||||
|
||||
type PlayingDonatResponse struct {
|
||||
Duration int `json:"duration" example:"30"`
|
||||
VolumePercent int `json:"volume_percent" example:"100"`
|
||||
Image *string `json:"image_link"`
|
||||
Audio *string `json:"audio_link"`
|
||||
Text string `json:"text"`
|
||||
|
@ -15,7 +15,7 @@ CREATE TABLE IF NOT EXISTS widgets (
|
||||
duration INTEGER NOT NULL,
|
||||
min_amount INTEGER NOT NUll,
|
||||
max_amount INTEGER NOT NULL,
|
||||
|
||||
volume_percent INTEGER NOT NULL DEFAULT 75,
|
||||
created_at TIMESTAMP NOT NULL DEFAULT now(),
|
||||
updated_at TIMESTAMP NOT NULL DEFAULT now()
|
||||
);
|
||||
@ -39,6 +39,7 @@ CREATE TABLE IF NOT EXISTS donats (
|
||||
target_id INTEGER,
|
||||
paid_time TIMESTAMP,
|
||||
is_test BOOLEAN DEFAULT 'false',
|
||||
media_url VARCHAR(255),
|
||||
|
||||
status VARCHAR(50) NOT NULL DEFAULT 'pending',
|
||||
|
||||
|
@ -6,8 +6,8 @@ import (
|
||||
)
|
||||
|
||||
var CreateWidget = `
|
||||
INSERT INTO widgets (streamer_id, template_id, image, audio, duration, min_amount, max_amount, name)
|
||||
VALUES (@streamer_id, @template_id, @image, @audio, @duration, @min_amount, @max_amount, @name)
|
||||
INSERT INTO widgets (streamer_id, template_id, image, audio, duration, min_amount, max_amount, name, volume_percent)
|
||||
VALUES (@streamer_id, @template_id, @image, @audio, @duration, @min_amount, @max_amount, @name, @volume_percent)
|
||||
RETURNING id;
|
||||
`
|
||||
|
||||
@ -40,8 +40,8 @@ func GetMediaUrl(mediaType model.MediaType) string {
|
||||
}
|
||||
|
||||
var CreateDonat = `
|
||||
INSERT INTO donats (streamer_id, widget_id, text, amount, donat_user, order_id, target_id, status, paid_time, is_test)
|
||||
VALUES (@streamer_id, @widget_id, @text, @amount, @donat_user, @order_id, @target_id, @status, @paid_time, @is_test)
|
||||
INSERT INTO donats (streamer_id, widget_id, text, amount, donat_user, order_id, target_id, status, paid_time, is_test, media_url)
|
||||
VALUES (@streamer_id, @widget_id, @text, @amount, @donat_user, @order_id, @target_id, @status, @paid_time, @is_test, @media_url)
|
||||
RETURNING id;
|
||||
`
|
||||
var MarkDonatView = `
|
||||
@ -199,6 +199,7 @@ SELECT
|
||||
w.group_id,
|
||||
w.name,
|
||||
w.is_active,
|
||||
w.volume_percent,
|
||||
img.id AS image_id,
|
||||
img.file_name AS image_file_name,
|
||||
img.file_type AS image_type,
|
||||
@ -280,7 +281,8 @@ SET
|
||||
is_active = COALESCE(@is_active, is_active),
|
||||
image = COALESCE(@image, image),
|
||||
audio = COALESCE(@audio, audio),
|
||||
name = COALESCE(@name, name)
|
||||
name = COALESCE(@name, name),
|
||||
volume_percent = COALESCE(@volume_percent, volume_percent)
|
||||
WHERE id = @id;
|
||||
`
|
||||
|
||||
@ -402,7 +404,7 @@ WHERE
|
||||
streamer_id = @streamer_id
|
||||
AND created_at >= NOW() - INTERVAL '24 hours'
|
||||
AND paid_time IS NOT NULL
|
||||
AND is_test IS 'false'
|
||||
AND is_test IS false
|
||||
|
||||
GROUP BY
|
||||
DATE_TRUNC('hour', created_at) -- Группировка по часам
|
||||
@ -421,7 +423,7 @@ WHERE
|
||||
streamer_id = @streamer_id
|
||||
AND created_at >= NOW() - INTERVAL '7 days'
|
||||
AND paid_time IS NOT NULL
|
||||
AND is_test IS 'false'
|
||||
AND is_test IS false
|
||||
|
||||
|
||||
GROUP BY
|
||||
@ -441,7 +443,7 @@ WHERE
|
||||
streamer_id = @streamer_id
|
||||
AND created_at >= NOW() - INTERVAL '1 month'
|
||||
AND paid_time IS NOT NULL
|
||||
AND is_test IS 'false'
|
||||
AND is_test IS false
|
||||
|
||||
GROUP BY
|
||||
DATE(created_at) -- Группировка по дням
|
||||
@ -460,7 +462,7 @@ WHERE
|
||||
streamer_id = @streamer_id
|
||||
AND created_at >= NOW() - INTERVAL '1 year'
|
||||
AND paid_time IS NOT NULL
|
||||
AND is_test IS 'false'
|
||||
AND is_test IS false
|
||||
|
||||
GROUP BY
|
||||
DATE_TRUNC('month', created_at) -- Группировка по месяцам
|
||||
@ -478,7 +480,7 @@ WHERE
|
||||
streamer_id = @streamer_id
|
||||
AND created_at >= NOW() - INTERVAL '24 hours'
|
||||
AND paid_time IS NOT NULL
|
||||
AND is_test IS 'false';
|
||||
AND is_test IS false;
|
||||
`
|
||||
|
||||
const GetDonationsSummaryLast7Days = `
|
||||
@ -491,7 +493,7 @@ WHERE
|
||||
streamer_id = @streamer_id
|
||||
AND created_at >= NOW() - INTERVAL '7 days'
|
||||
AND paid_time IS NOT NULL
|
||||
AND is_test IS 'false';
|
||||
AND is_test IS false;
|
||||
`
|
||||
|
||||
const GetDonationsSummaryLastMonth = `
|
||||
@ -504,7 +506,7 @@ WHERE
|
||||
streamer_id = @streamer_id
|
||||
AND created_at >= NOW() - INTERVAL '1 month'
|
||||
AND paid_time IS NOT NULL
|
||||
AND is_test IS 'false';
|
||||
AND is_test IS false;
|
||||
`
|
||||
|
||||
const GetDonationsSummaryLastYear = `
|
||||
@ -517,7 +519,7 @@ WHERE
|
||||
streamer_id = @streamer_id
|
||||
AND created_at >= NOW() - INTERVAL '1 year'
|
||||
AND paid_time IS NOT NULL
|
||||
AND is_test IS 'false';
|
||||
AND is_test IS false;
|
||||
`
|
||||
|
||||
const GetLastModeration = `
|
||||
@ -588,7 +590,8 @@ SELECT
|
||||
d.donat_user,
|
||||
d.play_content,
|
||||
d.show_name,
|
||||
d.show_text
|
||||
d.show_text,
|
||||
w.volume_percent
|
||||
FROM widgets AS w
|
||||
INNER JOIN
|
||||
donats AS d ON d.widget_id = w.id
|
||||
|
@ -166,8 +166,10 @@ async function playMedia(donat, voiceSettings) {
|
||||
const mediaPromise = (async () => {
|
||||
if (donat.play_content && donat.audio_link) {
|
||||
await playAudio(donat.audio_link, (voiceSettings.voice_sound_percent || 100) / 100, controller.signal);
|
||||
if (donat.text) await playSpeech(donat.text, voiceSettings, controller.signal);
|
||||
} else if (donat.text && donat.voice_enabled) {
|
||||
if (donat.text && donat.show_text) {
|
||||
await playSpeech(donat.text, voiceSettings, controller.signal);
|
||||
}
|
||||
} else if (donat.text && donat.voice_enabled && donat.show_text) {
|
||||
await playSpeech(donat.text, voiceSettings, controller.signal);
|
||||
}
|
||||
})();
|
||||
@ -179,8 +181,6 @@ async function playMedia(donat, voiceSettings) {
|
||||
}, timeoutDuration);
|
||||
});
|
||||
|
||||
// Promise.race будет ждать либо завершения медиа, либо таймаута
|
||||
// Если медиа завершится с ошибкой (например, автоплей заблокирован), она пробросится дальше.
|
||||
return Promise.race([mediaPromise, timeoutPromise]);
|
||||
}
|
||||
|
||||
@ -226,16 +226,12 @@ async function widgetView() {
|
||||
contentDiv.appendChild(textElem);
|
||||
}
|
||||
|
||||
// --- Воспроизведение ---
|
||||
const voiceSettings = { voice_speed: currentDonat.voice_speed, scenery: currentDonat.scenery, voice_sound_percent: currentDonat.voice_sound_percent, min_price: currentDonat.min_price, languages: currentDonat.languages, voice_enabled: currentDonat.voice_enabled };
|
||||
await playMedia(currentDonat, voiceSettings);
|
||||
|
||||
} catch (error) {
|
||||
// Логируем ошибку, но не прерываем логику ожидания и очистки
|
||||
console.error('Ошибка обработки доната:', error.name === 'AbortError' ? 'Таймаут или блокировка звука' : error);
|
||||
} finally {
|
||||
// --- Очистка и завершение ---
|
||||
// Этот блок выполнится ВСЕГДА: и после успеха, и после ошибки.
|
||||
if (currentDonat) {
|
||||
// Отмечаем донат как просмотренный
|
||||
if (currentDonat.order_id) {
|
||||
@ -250,7 +246,6 @@ async function widgetView() {
|
||||
}
|
||||
}
|
||||
|
||||
// Ждем оставшееся время до конца показа доната
|
||||
const elapsedMs = Date.now() - iterationStart;
|
||||
const durationMs = (currentDonat.duration || 5) * 1000;
|
||||
const remainingTimeMs = Math.max(0, durationMs - elapsedMs);
|
||||
@ -259,7 +254,6 @@ async function widgetView() {
|
||||
await new Promise(r => setTimeout(r, remainingTimeMs));
|
||||
}
|
||||
|
||||
// Гарантированно очищаем контейнер
|
||||
clearContainer(contentDiv);
|
||||
}
|
||||
}
|
||||
|
@ -33,6 +33,7 @@ func (repoDonat *RepoDonat) CreateDonat(
|
||||
amount int,
|
||||
text string,
|
||||
donatUser string,
|
||||
mediaUrl *string,
|
||||
status string,
|
||||
) error {
|
||||
args := pgx.NamedArgs{
|
||||
@ -44,6 +45,7 @@ func (repoDonat *RepoDonat) CreateDonat(
|
||||
"amount": amount,
|
||||
"status": status,
|
||||
"donat_user": donatUser,
|
||||
"media_url": mediaUrl,
|
||||
"is_test": false,
|
||||
"paid_time": nil,
|
||||
}
|
||||
@ -858,6 +860,7 @@ func (repoDonat *RepoDonat) GetPlayingDonat(
|
||||
&donatForPlaying.PlayContent,
|
||||
&donatForPlaying.ShowName,
|
||||
&donatForPlaying.ShowText,
|
||||
&donatForPlaying.VolumePercent,
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
|
@ -37,6 +37,7 @@ func (widgetRepo *RepoWidget) CreateWidget(
|
||||
audio string,
|
||||
name string,
|
||||
isActive bool,
|
||||
volumePercent int,
|
||||
) (model.WidgetID, error) {
|
||||
args := pgx.NamedArgs{
|
||||
"streamer_id": streamerID,
|
||||
@ -48,6 +49,7 @@ func (widgetRepo *RepoWidget) CreateWidget(
|
||||
"audio": audio,
|
||||
"name": name,
|
||||
"is_active": isActive,
|
||||
"volume_percent": volumePercent,
|
||||
}
|
||||
widgetID, err := widgetRepo.db.Insert(ctx, sql.CreateWidget, args)
|
||||
if err != nil {
|
||||
@ -141,6 +143,7 @@ func (widgetRepo *RepoWidget) UpdateWidget(
|
||||
image *uuid.UUID,
|
||||
audio *uuid.UUID,
|
||||
name *string,
|
||||
volumePercent *int,
|
||||
) error {
|
||||
args := pgx.NamedArgs{
|
||||
"id": widgetID,
|
||||
@ -167,6 +170,9 @@ func (widgetRepo *RepoWidget) UpdateWidget(
|
||||
if isActive != nil {
|
||||
args["is_active"] = *isActive
|
||||
}
|
||||
if volumePercent != nil {
|
||||
args["volume_percent"] = *volumePercent
|
||||
}
|
||||
|
||||
err := widgetRepo.db.Update(ctx, sql.UpdateWidget, args)
|
||||
if err != nil {
|
||||
|
@ -95,6 +95,7 @@ func (donatService *ServiceDonat) CreateDonat(
|
||||
donatUser string,
|
||||
targetID *int,
|
||||
amount int,
|
||||
mediaUrl *string,
|
||||
) (model.CreateDonatResponse, error) {
|
||||
|
||||
donatePage, err := donatService.donatRepo.GetDonatPageByLogin(ctx, streamerLogin)
|
||||
@ -128,6 +129,7 @@ func (donatService *ServiceDonat) CreateDonat(
|
||||
amount,
|
||||
text,
|
||||
donatUser,
|
||||
mediaUrl,
|
||||
"pending",
|
||||
)
|
||||
if err != nil {
|
||||
@ -153,13 +155,26 @@ func (donatService *ServiceDonat) CreateTestDonat(
|
||||
text string,
|
||||
donatUser string,
|
||||
targetID *int,
|
||||
mediaUrl *string,
|
||||
amount int,
|
||||
) error {
|
||||
orderID := uuid.New()
|
||||
|
||||
widgetID := donatService.defaultWidgetID
|
||||
widgets, err := donatService.widgetRepo.GetWidgetsByStreamerID(ctx, streamerID)
|
||||
if err != nil {
|
||||
slog.Error(err.Error())
|
||||
return err
|
||||
}
|
||||
|
||||
err := donatService.donatRepo.CreateDonat(
|
||||
widgetID := donatService.defaultWidgetID
|
||||
for _, widget := range widgets {
|
||||
if amount >= widget.MinAmount && amount <= widget.MaxAmount && widget.IsActive == true {
|
||||
widgetID = widget.ID
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
err = donatService.donatRepo.CreateDonat(
|
||||
ctx,
|
||||
streamerID,
|
||||
targetID,
|
||||
@ -168,6 +183,7 @@ func (donatService *ServiceDonat) CreateTestDonat(
|
||||
amount,
|
||||
text,
|
||||
donatUser,
|
||||
mediaUrl,
|
||||
"test_donat",
|
||||
)
|
||||
if err != nil {
|
||||
@ -818,6 +834,7 @@ func (donatService *ServiceDonat) GetPlayingDonat(
|
||||
PlayContent: playingDonat.PlayContent,
|
||||
ShowName: playingDonat.ShowName,
|
||||
ShowText: playingDonat.ShowText,
|
||||
VolumePercent: playingDonat.VolumePercent,
|
||||
}
|
||||
|
||||
filteredSettings, err := donatService.GetFiltersSettings(ctx, streamerID)
|
||||
@ -839,7 +856,7 @@ func (donatService *ServiceDonat) GetPlayingDonat(
|
||||
if !filteredSettings.EnableLinks {
|
||||
response.Text = donatService.replaceLinks(response.Text)
|
||||
}
|
||||
fmt.Println(response.Text)
|
||||
|
||||
response.VoiceSpeed = voiceSettings.VoiceSpeed
|
||||
response.Scenery = voiceSettings.Scenery
|
||||
response.VoiceSoundPercent = voiceSettings.VoiceSoundPercent
|
||||
|
@ -49,12 +49,12 @@ func (widgetService *ServiceWidget) CreateWidget(
|
||||
audio string,
|
||||
name string,
|
||||
isActive bool,
|
||||
volumePercent int,
|
||||
) (model.GetWidgetDb, error) {
|
||||
exists, err := widgetService.widgetRepo.CheckWidgetName(ctx, streamerID, name)
|
||||
if err != nil {
|
||||
return model.GetWidgetDb{}, err
|
||||
}
|
||||
fmt.Println(exists)
|
||||
if exists == true {
|
||||
slog.Error("GetWidgetDb with name %s already exists", name)
|
||||
return model.GetWidgetDb{}, fmt.Errorf("widget with name %s already exists", name)
|
||||
@ -71,6 +71,7 @@ func (widgetService *ServiceWidget) CreateWidget(
|
||||
audio,
|
||||
name,
|
||||
isActive,
|
||||
volumePercent,
|
||||
)
|
||||
if err != nil {
|
||||
slog.Error(err.Error())
|
||||
@ -149,6 +150,7 @@ func (widgetService *ServiceWidget) UpdateWidget(
|
||||
updateWidget.Image,
|
||||
updateWidget.Audio,
|
||||
updateWidget.Name,
|
||||
updateWidget.VolumePercent,
|
||||
)
|
||||
if err != nil {
|
||||
slog.Error(err.Error())
|
||||
|
@ -20,6 +20,7 @@ CREATE TABLE IF NOT EXISTS widgets (
|
||||
name VARCHAR(50) NOT NULL,
|
||||
image UUID REFERENCES files(id) ON DELETE CASCADE,
|
||||
audio UUID REFERENCES files(id) ON DELETE CASCADE,
|
||||
volume_percent INTEGER NOT NULL DEFAULT 70,
|
||||
duration INTEGER NOT NULL,
|
||||
min_amount INTEGER NOT NULL,
|
||||
max_amount INTEGER NOT NULL,
|
||||
|
Loading…
x
Reference in New Issue
Block a user