donat-widget/internal/model/widget-templates.go

255 lines
7.2 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package model
import "fmt"
func GetTemplate1(streamerID int, donatHost, ttsHost string) string {
style := `body {
margin: 0;
padding: 0;
height: 100vh;
display: flex;
justify-content: center;
align-items: flex-start;
background-color: #000;
font-family: Arial, sans-serif;
}
#content {
display: flex;
flex-direction: column;
align-items: center;
width: 100%;
max-width: 1920px;
margin: 20px auto;
gap: 20px;
}
#content img {
width: 100%;
height: auto;
max-height: 90vh;
object-fit: contain;
border-radius: 15px;
}
.text-container {
display: flex;
align-items: center;
gap: 20px;
font-size: 40px;
color: #fff;
text-shadow: 2px 2px 4px rgba(0,0,0,0.5);
opacity: 0;
animation: fadeIn 2s forwards;
}
.donation-text {
margin: 0;
}
.donation-amount {
color: #4CAF50;
font-weight: bold;
padding: 5px 15px;
background: rgba(0,0,0,0.7);
border-radius: 8px;
}
@keyframes fadeIn {
to {
opacity: 1;
}
}`
script := fmt.Sprintf(`
let widgetUrl = 'https://%s/api';
let ttsUrl = 'https://%s/api/tts';
function createTextWithAmount(text, amount) {
const container = document.createElement('div');
container.className = 'text-container';
const textElem = document.createElement('p');
textElem.className = 'donation-text';
textElem.textContent = text;
const amountElem = document.createElement('div');
amountElem.className = 'donation-amount';
amountElem.textContent = amount + '₽';
container.appendChild(textElem);
container.appendChild(amountElem);
return container;
}
async function getDonatInfo(streamerID) {
try {
let response = await fetch(widgetUrl + '/widget/get-donat-for-playing/' + streamerID);
return await response.json();
} catch (error) {
console.error('Fetch error:', error);
return null;
}
}
function addImage(container, imageUrl) {
const img = document.createElement('img');
img.src = imageUrl + '?t=' + new Date().getTime();
img.onload = () => {
const aspectRatio = img.naturalWidth / img.naturalHeight;
if (aspectRatio > 1) {
img.style.width = '100%%';
img.style.height = 'auto';
} else {
img.style.width = 'auto';
img.style.height = '100%%';
}
};
container.appendChild(img);
}
function addText(container, text) {
const p = document.createElement('p');
p.className = 'donation-text';
p.textContent = text;
container.appendChild(p);
}
function clearContainer(container) {
while (container.firstChild) {
container.removeChild(container.firstChild);
}
}
function playAudio(audioUrl, callback) {
fetch(audioUrl)
.then(response => {
if (!response.ok) throw new Error('Audio network error');
return response.blob();
})
.then(blob => {
const url = URL.createObjectURL(blob);
const audio = new Audio(url);
audio.play().catch(console.error);
setTimeout(() => {
audio.pause();
URL.revokeObjectURL(url);
if (callback) callback();
}, 7000);
})
.catch(console.error);
}
function playSpeech(text) {
fetch(ttsUrl + '/generate', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({ text: text }),
})
.then(response => {
if (!response.ok) throw new Error('TTS error');
return response.blob();
})
.then(blob => {
const url = URL.createObjectURL(blob);
const audio = new Audio(url);
audio.play().catch(console.error);
audio.addEventListener('ended', () => {
URL.revokeObjectURL(url);
});
})
.catch(console.error);
}
function playSpeechAfterAudio(audioUrl, text) {
playAudio(audioUrl, () => playSpeech(text));
}
async function widgetView() {
const streamerID = '%v';
const contentDiv = document.getElementById('content');
const REQUEST_INTERVAL = 5000; // Фиксированный интервал 5 секунд
if (!contentDiv) {
console.error('Content container not found!');
return;
}
while (true) {
const iterationStart = Date.now(); // Замер времени начала итерации
try {
const donat = await getDonatInfo(streamerID);
console.log('Donat received:', donat);
if (!donat || Object.keys(donat).length === 0) {
await new Promise(r => setTimeout(r, 5000));
continue;
}
clearContainer(contentDiv);
// Добавление элементов в DOM
if (donat.image_link) {
addImage(contentDiv, donat.image_link);
}
// Создание текста с суммой
if (donat.text && donat.amount) {
const textWithAmount = createTextWithAmount(donat.text, donat.amount);
contentDiv.appendChild(textWithAmount);
} else if (donat.text) {
addText(contentDiv, donat.text);
}
// Воспроизведение аудио
if (donat.audio_link) {
playSpeechAfterAudio(donat.audio_link, donat.text);
} else if (donat.text) {
playSpeech(donat.text);
}
// Ожидаем указанную длительность
await new Promise(r => setTimeout(r, donat.duration * 1000));
// Отправка подтверждения просмотра
if (donat.order_id) {
try {
const response = await fetch(widgetUrl + '/widget/donat/viewed', {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({order_id: donat.order_id}),
});
if (!response.ok) console.error('Ошибка подтверждения просмотра');
} catch (error) {
console.error('Ошибка:', error);
}
}
} catch (error) {
console.error('Ошибка в цикле:', error);
} finally {
// Гарантируем задержку между итерациями
const elapsed = Date.now() - iterationStart;
const remaining = REQUEST_INTERVAL - elapsed;
if (remaining > 0) {
await new Promise(r => setTimeout(r, remaining));
}
}
}
}
document.addEventListener('DOMContentLoaded', widgetView);`, donatHost, ttsHost, streamerID)
template := fmt.Sprintf(`<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<style>%s</style>
</head>
<body>
<div id='content'></div>
<script>%s</script>
</body>
</html>`, style, script)
return template
}