diff --git a/TSH.exe b/TSH.exe
index 275a60a80..b34342011 100644
Binary files a/TSH.exe and b/TSH.exe differ
diff --git a/assets/icons/bsky.svg b/assets/icons/bsky.svg
new file mode 100644
index 000000000..b60d51c27
--- /dev/null
+++ b/assets/icons/bsky.svg
@@ -0,0 +1,4 @@
+
+
\ No newline at end of file
diff --git a/dependencies/requirements.txt b/dependencies/requirements.txt
index 7059aa78f..09482810e 100755
--- a/dependencies/requirements.txt
+++ b/dependencies/requirements.txt
@@ -16,8 +16,9 @@ cloudscraper==1.2.71
loguru==0.7.3
flask-socketio
simple_websocket
+atproto==0.0.56
termcolor==2.5.0
orjson==3.10.13
msgpack==1.1.0
qasync==0.27.1
-tzdata
\ No newline at end of file
+tzdata
diff --git a/src/Helpers/TSHAltTextHelper.py b/src/Helpers/TSHAltTextHelper.py
index da69aa110..c3b858a32 100644
--- a/src/Helpers/TSHAltTextHelper.py
+++ b/src/Helpers/TSHAltTextHelper.py
@@ -4,6 +4,7 @@
from qtpy.QtGui import *
from qtpy.QtWidgets import *
from qtpy.QtCore import *
+from atproto import client_utils
def add_alt_text_tooltip_to_button(push_button: QPushButton):
altTextTooltip = QApplication.translate(
@@ -19,7 +20,33 @@ def load_program_state():
return (data_json)
-def generate_youtube(scoreboard_id=1, use_phase_name=True):
+def generate_bsky_text(scoreboard_id=1, use_phase_name=True):
+ def transform_yt_into_bsky(description, data):
+ text = "\n".join(description.split("\n")[:-1]).strip("\n")
+ text = "🔴 " + QApplication.translate("altText", "LIVE NOW") + "\n\n" + text
+
+ link_text = QApplication.translate("altText", "Click here to watch")
+ link_url = data.get("score").get(str(scoreboard_id)).get("stream_url")
+ if link_url:
+ text += "\n\n"
+ result = client_utils.TextBuilder().text(text).link(link_text, link_url)
+ raw_text = text + link_text
+ else:
+ result = client_utils.TextBuilder().text(text)
+ raw_text = text
+ return(raw_text, result)
+
+ post_length_limit = 300
+ data = load_program_state()
+ title, description = generate_youtube(scoreboard_id, use_phase_name)
+ raw_text, builder = transform_yt_into_bsky(description, data)
+ if len(raw_text) > post_length_limit:
+ title, description = generate_youtube(scoreboard_id, use_phase_name, use_characters=False)
+ raw_text, builder = transform_yt_into_bsky(description, data)
+ return(raw_text, builder)
+
+
+def generate_youtube(scoreboard_id=1, use_phase_name=True, use_characters=True):
title_length_limit = 100 # Character limit for video titles
data = load_program_state()
tournament_name = data.get("tournamentInfo").get("tournamentName")
@@ -83,8 +110,12 @@ def generate_youtube(scoreboard_id=1, use_phase_name=True):
title_long = f'{title_long}' + \
" / ".join(player_names_with_characters)
title_short = f'{title_short}' + " / ".join(player_names)
- description = description + \
- " / ".join(player_names_with_characters)
+ if use_characters:
+ description = description + \
+ " / ".join(player_names_with_characters)
+ else:
+ description = description + \
+ " / ".join(player_names)
if team_id == "1":
title_long = f'{title_long} ' + \
@@ -110,7 +141,7 @@ def generate_youtube(scoreboard_id=1, use_phase_name=True):
" " + "https://github.com/joaorb64/TournamentStreamHelper/releases"
description = description.strip()
- if len(title_long) <= title_length_limit:
+ if len(title_long) <= title_length_limit and use_characters:
return (title_long, description)
else:
if len(title_short) > title_length_limit:
@@ -226,6 +257,8 @@ def CalculatePlacement(x, bracket_type="DOUBLE_ELIMINATION"):
print(colored("TEST MODE - TSHAltTextHelper.py", "red"))
print("====")
title, description = generate_youtube(1)
+ raw_bsky, builder = generate_bsky_text(1)
print(colored("YouTube title: ", "yellow") + f"{title}")
print(colored(f"\nDescription: \n", "yellow") + f"{description}")
print(colored(f"\nTop 8 alt text: \n", "yellow")+f"{generate_top_n_alt_text()}")
+ print(colored(f"\nBluesky post: \n", "yellow")+f"{raw_bsky}")
diff --git a/src/Helpers/TSHBskyHelper.py b/src/Helpers/TSHBskyHelper.py
new file mode 100644
index 000000000..fbcd55144
--- /dev/null
+++ b/src/Helpers/TSHBskyHelper.py
@@ -0,0 +1,28 @@
+import json
+import math
+import textwrap
+from qtpy.QtGui import *
+from qtpy.QtWidgets import *
+from qtpy.QtCore import *
+from .TSHAltTextHelper import generate_bsky_text, generate_youtube
+from .TSHLocaleHelper import TSHLocaleHelper
+from src.SettingsManager import SettingsManager
+from atproto import Client
+from atproto_client.models.app.bsky.embed.defs import AspectRatio
+
+def post_to_bsky(scoreboardNumber=1, image_path=None):
+ locale = TSHLocaleHelper.programLocale
+ bsky_account = SettingsManager.Get("bsky_account", {})
+ if not bsky_account or not bsky_account.get("username") or not bsky_account.get("host") or not bsky_account.get("app_password"):
+ raise ValueError(QApplication.translate("app", "Bluesky account not correctly set"))
+ client = Client(bsky_account.get("host", "https://bsky.social"))
+ client.login(bsky_account["username"].lstrip("@"), bsky_account["app_password"])
+
+ raw_text, builder = generate_bsky_text(scoreboard_id = scoreboardNumber)
+ yt_title, yt_description = generate_youtube(scoreboard_id = scoreboardNumber) # Use YouTube Description as Alt Text
+
+ pixmap = QPixmap(image_path, "RGBA")
+ aspect_ratio = AspectRatio(width=pixmap.width(), height=pixmap.height())
+
+ with open(image_path, "rb") as image:
+ post = client.send_images(builder, images=[image.read()], image_alts=[yt_description], langs=[locale], image_aspect_ratios=[aspect_ratio])
diff --git a/src/Settings/SettingsWidget.py b/src/Settings/SettingsWidget.py
index 4ecd37785..481b96322 100644
--- a/src/Settings/SettingsWidget.py
+++ b/src/Settings/SettingsWidget.py
@@ -1,6 +1,7 @@
from qtpy.QtWidgets import *
from ..TSHHotkeys import TSHHotkeys
from ..SettingsManager import SettingsManager
+import textwrap
class SettingsWidget(QWidget):
@@ -19,7 +20,7 @@ def __init__(self, settingsBase="", settings=[]):
for setting in settings:
self.AddSetting(*setting)
- def AddSetting(self, name: str, setting: str, type: str, defaultValue, callback=lambda: None):
+ def AddSetting(self, name: str, setting: str, type: str, defaultValue, callback=lambda: None, tooltip=None):
lastRow = self.layout().rowCount()
self.layout().addWidget(QLabel(name), lastRow, 0)
@@ -59,6 +60,23 @@ def AddSetting(self, name: str, setting: str, type: str, defaultValue, callback=
callback()
]
)
+ elif type == "textbox" or type == "password":
+ settingWidget = QLineEdit()
+ if type == "password":
+ settingWidget.setEchoMode(QLineEdit.Password)
+ settingWidget.textChanged.connect(
+ lambda val=None: SettingsManager.Set(self.settingsBase+"."+setting, settingWidget.text()))
+ settingWidget.setText(SettingsManager.Get(
+ self.settingsBase+"."+setting, defaultValue))
+ resetButton.clicked.connect(
+ lambda bt=None, setting=setting, settingWidget=settingWidget: [
+ settingWidget.setText(defaultValue),
+ callback()
+ ]
+ )
+
+ if tooltip:
+ settingWidget.setToolTip('\n'.join(textwrap.wrap(tooltip, 40)))
self.layout().addWidget(settingWidget, lastRow, 1)
self.layout().addWidget(resetButton, lastRow, 2)
diff --git a/src/Settings/TSHSettingsWindow.py b/src/Settings/TSHSettingsWindow.py
index a08897930..5c82a985a 100644
--- a/src/Settings/TSHSettingsWindow.py
+++ b/src/Settings/TSHSettingsWindow.py
@@ -112,6 +112,40 @@ def UiMounted(self):
self.add_setting_widget(QApplication.translate(
"settings", "Hotkeys"), SettingsWidget("hotkeys", hotkeySettings))
+
+ # Add Bluesky settings
+ bskySettings = []
+ bskySettings.append((
+ QApplication.translate(
+ "settings.bsky", "Host server"),
+ "host",
+ "textbox",
+ "https://bsky.social"
+ ))
+ bskySettings.append((
+ QApplication.translate(
+ "settings.bsky", "Bluesky Handle"),
+ "username",
+ "textbox",
+ ""
+ ))
+ bskySettings.append((
+ QApplication.translate(
+ "settings.bsky", "Application Password"),
+ "app_password",
+ "password",
+ "",
+ None,
+ QApplication.translate(
+ "settings.bsky", "You can get an app password by going into your Bluesky settings -> Privacy & Security") + "\n" +
+ QApplication.translate(
+ "settings.bsky", "Please note that said app password will be stored in plain text on your computer") + "\n\n" +
+ QApplication.translate(
+ "settings.bsky", "Do not use your regular account password!").upper()
+ ))
+
+ self.add_setting_widget(QApplication.translate(
+ "settings", "Bluesky"), SettingsWidget("bsky_account", bskySettings))
self.resize(1000, 500)
QApplication.processEvents()
diff --git a/src/TSHScoreboardWidget.py b/src/TSHScoreboardWidget.py
index 09cfc7ae6..c9177d2c0 100644
--- a/src/TSHScoreboardWidget.py
+++ b/src/TSHScoreboardWidget.py
@@ -8,6 +8,7 @@
from typing import List
from src.TSHColorButton import TSHColorButton
from .Helpers.TSHDirHelper import TSHResolve
+from .Helpers.TSHBskyHelper import post_to_bsky
from src.TSHSelectSetWindow import TSHSelectSetWindow
from src.TSHSelectStationWindow import TSHSelectStationWindow
@@ -190,6 +191,13 @@ def __init__(self, scoreboardNumber=1, *args):
col.layout().addWidget(self.thumbnailBtn, Qt.AlignmentFlag.AlignRight)
# self.thumbnailBtn.setPopupMode(QToolButton.InstantPopup)
self.thumbnailBtn.clicked.connect(self.GenerateThumbnail)
+
+ self.bskyBtn = QPushButton(
+ QApplication.translate("app", "Post to Bluesky") + " ")
+ self.bskyBtn.setIcon(QIcon('assets/icons/bsky.svg'))
+ self.bskyBtn.setSizePolicy(QSizePolicy.Maximum, QSizePolicy.Fixed)
+ col.layout().addWidget(self.bskyBtn, Qt.AlignmentFlag.AlignRight)
+ self.bskyBtn.clicked.connect(self.PostToBsky)
# VISIBILITY
col = QWidget()
@@ -246,6 +254,16 @@ def __init__(self, scoreboardNumber=1, *args):
self.innerWidget.layout().addWidget(bottomOptions)
+ self.streamUrl = QHBoxLayout()
+ self.streamUrlLabel = QLabel(QApplication.translate("app", "Stream URL") + " ")
+ self.streamUrl.layout().addWidget(self.streamUrlLabel)
+ self.streamUrlTextBox = QLineEdit()
+ self.streamUrl.layout().addWidget(self.streamUrlTextBox)
+ self.streamUrlTextBox.textChanged.connect(
+ lambda value=None: StateManager.Set(
+ f"score.{self.scoreboardNumber}.stream_url", value))
+ bottomOptions.layout().addLayout(self.streamUrl)
+
self.btSelectSet = QPushButton(
QApplication.translate("app", "Load set"))
self.btSelectSet.setIcon(QIcon("./assets/icons/list.svg"))
@@ -504,7 +522,7 @@ def ExportTeamLogo(self, team, value):
StateManager.Set(
f"score.{self.scoreboardNumber}.team.{team}.logo", None)
- def GenerateThumbnail(self):
+ def GenerateThumbnail(self, quiet_mode=False):
msgBox = QMessageBox()
msgBox.setWindowIcon(QIcon('assets/icons/icon.png'))
msgBox.setWindowTitle(QApplication.translate(
@@ -519,25 +537,48 @@ def GenerateThumbnail(self):
# msgBox.setInformativeText(thumbnailPath)
thumbnail_settings = SettingsManager.Get("thumbnail_config")
- if thumbnail_settings.get("open_explorer"):
- outThumbDir = f"{os.getcwd()}/out/thumbnails/"
- if platform.system() == "Windows":
- thumbnailPath = thumbnailPath[2:].replace("/", "\\")
- outThumbDir = f"{os.getcwd()}\\{thumbnailPath}"
- # os.startfile(outThumbDir)
- subprocess.Popen(r'explorer /select,"'+outThumbDir+'"')
- elif platform.system() == "Darwin":
- subprocess.Popen(["open", outThumbDir])
+ if not quiet_mode:
+ if thumbnail_settings.get("open_explorer"):
+ outThumbDir = f"{os.getcwd()}/out/thumbnails/"
+ if platform.system() == "Windows":
+ thumbnailPath = thumbnailPath[2:].replace("/", "\\")
+ outThumbDir = f"{os.getcwd()}\\{thumbnailPath}"
+ # os.startfile(outThumbDir)
+ subprocess.Popen(r'explorer /select,"'+outThumbDir+'"')
+ elif platform.system() == "Darwin":
+ subprocess.Popen(["open", outThumbDir])
+ else:
+ subprocess.Popen(["xdg-open", outThumbDir])
else:
- subprocess.Popen(["xdg-open", outThumbDir])
+ msgBox.exec()
else:
- msgBox.exec()
+ return(thumbnailPath)
except Exception as e:
msgBox.setText(QApplication.translate("app", "Warning"))
msgBox.setInformativeText(str(e))
msgBox.setIcon(QMessageBox.Warning)
msgBox.exec()
+
+ def PostToBsky(self):
+ thumbnailPath = self.GenerateThumbnail(quiet_mode=True)
+ if thumbnailPath:
+ msgBox = QMessageBox()
+ msgBox.setWindowIcon(QIcon('assets/icons/icon.png'))
+ msgBox.setWindowTitle(QApplication.translate(
+ "app", "TSH - Bluesky"))
+ try:
+ post_to_bsky(scoreboardNumber=self.scoreboardNumber, image_path=thumbnailPath.replace(".png", ".jpg"))
+ username = SettingsManager.Get("bsky_account", {}).get("username")
+ msgBox.setText(QApplication.translate("app", "The post has successfully been sent to account {0}").format(username))
+ msgBox.setIcon(QMessageBox.NoIcon)
+ msgBox.exec()
+ except Exception as e:
+ msgBox.setText(QApplication.translate("app", "Warning"))
+ msgBox.setInformativeText(str(e))
+ msgBox.setIcon(QMessageBox.Warning)
+ msgBox.exec()
+
def ToggleElements(self, action: QAction, elements):
for pw in self.playerWidgets:
for element in elements:
diff --git a/src/i18n/TSH_de.ts b/src/i18n/TSH_de.ts
index c7edf7d22..ba88a070b 100644
--- a/src/i18n/TSH_de.ts
+++ b/src/i18n/TSH_de.ts
@@ -702,36 +702,46 @@ p, li { white-space: pre-wrap; }
altText
-
-
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
+
+
+
-
-
+
+
-
+
-
+
-
+
@@ -760,7 +770,7 @@ p, li { white-space: pre-wrap; }
-
+
Charaktere pro Slot
@@ -1337,48 +1347,48 @@ p, li { white-space: pre-wrap; }
-
+
Spieler pro Team
-
+
Thumbnail erstellen
-
+
Klarname
-
+
Twitter
-
+
Staat/Region
-
+
Charaktere
-
+
Pronomen
-
-
+
+
Set laden
@@ -1387,8 +1397,8 @@ p, li { white-space: pre-wrap; }
aktuelles Stream-Set laden
-
-
+
+
TEAM {0}
@@ -1397,28 +1407,49 @@ p, li { white-space: pre-wrap; }
-
+
+
ACHTUNG
-
+
+
+
+
+
+
+
+
+
+
+
-
+
+
+
+
+
+
+
+
+
+
+
Set von {0} laden
-
+
User-Set {0} laden
-
+
User-Set laden
@@ -1523,6 +1554,11 @@ p, li { white-space: pre-wrap; }
+
+
+
+
+
punctuation
@@ -1562,11 +1598,49 @@ p, li { white-space: pre-wrap; }
-
+
+
+
+
+
+
+
+ settings.bsky
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
settings.control_score_from_stage_strike
@@ -1653,18 +1727,18 @@ p, li { white-space: pre-wrap; }
thumb_app
-
+
-
+
Thumbnail wurde erstellt:
-
+
@@ -1682,7 +1756,7 @@ p, li { white-space: pre-wrap; }
tips
-
+
diff --git a/src/i18n/TSH_en.ts b/src/i18n/TSH_en.ts
index 72c8327b6..6e6d9d263 100644
--- a/src/i18n/TSH_en.ts
+++ b/src/i18n/TSH_en.ts
@@ -697,36 +697,46 @@ p, li { white-space: pre-wrap; }
altText
-
-
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
+
+
+
-
-
+
+
-
+
-
+
-
+
@@ -755,7 +765,7 @@ p, li { white-space: pre-wrap; }
-
+
@@ -820,7 +830,8 @@ p, li { white-space: pre-wrap; }
-
+
+
@@ -1149,74 +1160,94 @@ p, li { white-space: pre-wrap; }
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
-
+
+
+
+
+
+
+
+
+
+
+
+
-
+
-
-
+
+
-
+
+
+
+
+
+
+
+
+
+
+
-
+
-
+
@@ -1474,6 +1505,11 @@ p, li { white-space: pre-wrap; }
+
+
+
+
+
punctuation
@@ -1513,11 +1549,49 @@ p, li { white-space: pre-wrap; }
-
+
+
+
+
+
+
+
+ settings.bsky
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
settings.control_score_from_stage_strike
@@ -1636,18 +1710,18 @@ p, li { white-space: pre-wrap; }
thumb_app
-
+
-
+
-
+
@@ -1665,7 +1739,7 @@ p, li { white-space: pre-wrap; }
tips
-
+
diff --git a/src/i18n/TSH_es.ts b/src/i18n/TSH_es.ts
index 61d694fd8..73a8c8674 100644
--- a/src/i18n/TSH_es.ts
+++ b/src/i18n/TSH_es.ts
@@ -707,36 +707,46 @@ p, li { white-space: pre-wrap; }
altText
-
-
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
+
+
+
-
-
+
+
-
+
-
+
-
+
@@ -765,7 +775,7 @@ p, li { white-space: pre-wrap; }
-
+
Personajes por jugador
@@ -1346,48 +1356,48 @@ p, li { white-space: pre-wrap; }
-
+
Jugadores por equipo
-
+
Generar Miniatura
-
+
Nombre Real
-
+
-
+
Localidad
-
+
Personajes
-
+
Pronombres
-
-
+
+
Cargar set
@@ -1396,8 +1406,8 @@ p, li { white-space: pre-wrap; }
Cargar set actual desde el stream
-
-
+
+
EQUIPO {0}
@@ -1406,28 +1416,49 @@ p, li { white-space: pre-wrap; }
-
+
+
Aviso
-
+
+
+
+
+
+
+
+
+
+
+
-
+
+
+
+
+
+
+
+
+
+
+
Cargar set de {0}
-
+
Cargar set de usuario ({0})
-
+
Cargar set de usuario
@@ -1536,6 +1567,11 @@ p, li { white-space: pre-wrap; }
+
+
+
+
+
punctuation
@@ -1575,11 +1611,49 @@ p, li { white-space: pre-wrap; }
-
+
+
+
+
+
+
+
+ settings.bsky
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
settings.control_score_from_stage_strike
@@ -1676,18 +1750,18 @@ p, li { white-space: pre-wrap; }
Falta la tag del jugador {0}
-
+
-
+
La miniatura se generó aquí:
-
+
@@ -1695,7 +1769,7 @@ p, li { white-space: pre-wrap; }
tips
-
+
diff --git a/src/i18n/TSH_fr.qm b/src/i18n/TSH_fr.qm
index 20c1e5547..7b0feebf9 100644
Binary files a/src/i18n/TSH_fr.qm and b/src/i18n/TSH_fr.qm differ
diff --git a/src/i18n/TSH_fr.ts b/src/i18n/TSH_fr.ts
index 46d95a933..fa5548107 100644
--- a/src/i18n/TSH_fr.ts
+++ b/src/i18n/TSH_fr.ts
@@ -702,36 +702,46 @@ p, li { white-space: pre-wrap; }
altText
-
-
+
+
+ ACTUELLEMENT EN DIRECT
+
+
+
+
+ Cliquez ici pour regarder
+
+
+
+
Jeu :
-
-
-
+
+
+
contre
-
-
+
+
Commentateurs :
-
+
Stream produit avec Tournament Stream Helper :
-
+
Résultats :
-
+
Stream produit avec Tournament Stream Helper
@@ -1199,7 +1209,7 @@ p, li { white-space: pre-wrap; }
-
+
Nombre de personnages par joueur
@@ -1292,7 +1302,7 @@ p, li { white-space: pre-wrap; }
Stage
-
+
Nombre de joueurs par équipe
@@ -1301,13 +1311,23 @@ p, li { white-space: pre-wrap; }
Générer la miniature
-
+
Générer la miniature
-
-
+
+
+ Envoyer un post sur Bluesky
+
+
+
+
+ URL du stream
+
+
+
+
Charger un set
@@ -1320,8 +1340,8 @@ p, li { white-space: pre-wrap; }
Suivre les matchs d’un poste de jeu
-
-
+
+
ÉQUIPE {0}
@@ -1330,28 +1350,39 @@ p, li { white-space: pre-wrap; }
-
+
+
Attention
-
+
Suivre les matchs en cours sur un stream ou un poste de jeu
-
+
+
+ TSH - Bluesky
+
+
+
+
+ Le post a été envoyé sur le compte {0}
+
+
+
Charger un set depuis {0}
-
+
Charger le set de l'utilisateur {0}
-
+
Charger un set utilisateur
@@ -1466,31 +1497,31 @@ p, li { white-space: pre-wrap; }
-
+
Nom Réel
-
+
Twitter
-
+
Lieu
-
+
Personnages
-
+
Pronoms
@@ -1583,6 +1614,11 @@ p, li { white-space: pre-wrap; }
Identifiant
+
+
+
+ Le compte Bluesky n’a pas été correctement configuré
+
punctuation
@@ -1622,11 +1658,49 @@ p, li { white-space: pre-wrap; }
Raccourcis clavier
-
+
+
+ Bluesky
+
+
+
Paramètres par défaut
+
+ settings.bsky
+
+
+
+ Serveur hôte
+
+
+
+
+ Nom d’utilisateur Bluesky
+
+
+
+
+ Mot de passe d’application
+
+
+
+
+ Vous pouvez obtenir un mot de passe d’application sur Bluesky via les Paramètres -> Confidentialité et sécurité
+
+
+
+
+ Veuillez noter que ce mot de passe sera stocké en clair sur votre ordinateur
+
+
+
+
+ N’utilisez pas le mot de passe principal de votre compte !
+
+
settings.control_score_from_stage_strike
@@ -1727,18 +1801,18 @@ p, li { white-space: pre-wrap; }
Miniature sauvegardée sous {0}/{1}.png et {0}/{1}.jpg
-
+
TSH - Miniature
-
+
La miniature a été enregistrée à l'emplacement suivant :
-
+
Le titre et la description de la vidéo ont également été générés.
@@ -1746,7 +1820,7 @@ p, li { white-space: pre-wrap; }
tips
-
+
L’Alternative textuelle décrit les images pour les personnes aveugles et malvoyantes, et donne du contexte supplémentaire autout des dites images. En conséquence, nous recommandons vivement l’ajout de l’Alternative textuelle aux images mises en ligne sur votre site web ou vos réseaux sociaux.
diff --git a/src/i18n/TSH_it.ts b/src/i18n/TSH_it.ts
index 344a8d707..f4126ee6f 100644
--- a/src/i18n/TSH_it.ts
+++ b/src/i18n/TSH_it.ts
@@ -697,36 +697,46 @@ p, li { white-space: pre-wrap; }
altText
-
-
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
+
+
+
-
-
+
+
-
+
-
+
-
+
@@ -738,7 +748,8 @@ p, li { white-space: pre-wrap; }
-
+
+
Avvertimento
@@ -1146,7 +1157,7 @@ p, li { white-space: pre-wrap; }
-
+
Personaggi per giocatore
@@ -1235,74 +1246,94 @@ p, li { white-space: pre-wrap; }
-
+
-
+
Generare la miniatura
-
+
Nome legale
-
+
-
+
-
+
Personaggi
-
+
-
-
+
+
+
+
+
+
+
+
+
+
+
+
-
+
-
-
+
+
-
+
+
+
+
+
+
+
+
+
+
+
-
+
-
+
@@ -1474,6 +1505,11 @@ p, li { white-space: pre-wrap; }
+
+
+
+
+
punctuation
@@ -1513,11 +1549,49 @@ p, li { white-space: pre-wrap; }
-
+
+
+
+
+
+
+
+ settings.bsky
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
settings.control_score_from_stage_strike
@@ -1604,18 +1678,18 @@ p, li { white-space: pre-wrap; }
thumb_app
-
+
TSH - Miniatura
-
+
-
+
@@ -1633,7 +1707,7 @@ p, li { white-space: pre-wrap; }
tips
-
+
diff --git a/src/i18n/TSH_ja.ts b/src/i18n/TSH_ja.ts
index d350e9d17..d7c4692f9 100644
--- a/src/i18n/TSH_ja.ts
+++ b/src/i18n/TSH_ja.ts
@@ -710,36 +710,46 @@ p, li { white-space: pre-wrap; }
altText
-
-
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
+
+
+
-
-
+
+
-
+
-
+
-
+
@@ -1171,7 +1181,7 @@ p, li { white-space: pre-wrap; }
-
+
各プレイヤーの使用キャラクター数
@@ -1369,54 +1379,54 @@ p, li { white-space: pre-wrap; }
ステージ
-
+
各チームのプレイヤー数
-
+
本名
-
+
ツイッター
-
+
本拠地
-
+
使用キャラクター
-
+
代名詞
-
-
+
+
対戦データをロードする
-
+
-
-
+
+
チーム{0}
@@ -1425,13 +1435,14 @@ p, li { white-space: pre-wrap; }
-
+
+
注意
-
+
{0}から対戦データをロードする
@@ -1440,17 +1451,37 @@ p, li { white-space: pre-wrap; }
配信中の対戦データをロードする
-
+
サムネイルを作成する
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
ユーザーの対戦データ({0})をロードする
-
+
ユーザーの対戦データをロードする
@@ -1539,6 +1570,11 @@ p, li { white-space: pre-wrap; }
+
+
+
+
+
punctuation
@@ -1578,11 +1614,49 @@ p, li { white-space: pre-wrap; }
-
+
+
+
+
+
+
+
+ settings.bsky
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
settings.control_score_from_stage_strike
@@ -1679,18 +1753,18 @@ p, li { white-space: pre-wrap; }
プレイヤー{0}のタグがありません
-
+
TSH - サムネイル
-
+
サムネイルはここに作成されました:
-
+
@@ -1698,7 +1772,7 @@ p, li { white-space: pre-wrap; }
tips
-
+
diff --git a/src/i18n/TSH_pt-BR.ts b/src/i18n/TSH_pt-BR.ts
index 620b7fc0f..ce9cace87 100644
--- a/src/i18n/TSH_pt-BR.ts
+++ b/src/i18n/TSH_pt-BR.ts
@@ -709,36 +709,46 @@ p, li { white-space: pre-wrap; }
altText
-
-
+
+
+
+
+
+
+
+
+
+
+
+
Jogo:
-
-
-
+
+
+
VS
-
-
+
+
Comentaristas:
-
+
Transmissão utilizando TournamentStreamHelper
-
+
-
+
Transmissão utilizando TournamentStreamHelper
@@ -1218,7 +1228,7 @@ p, li { white-space: pre-wrap; }
-
+
Personagens por jogador
@@ -1424,7 +1434,7 @@ p, li { white-space: pre-wrap; }
-
+
Jogadores por time
@@ -1434,48 +1444,48 @@ p, li { white-space: pre-wrap; }
-
+
Nome Real
-
+
-
+
Local
-
+
Personagens
-
+
Pronomes
-
-
+
+
Carregar set
-
+
Seguir os sets de um stream ou uma estação
-
-
+
+
TIME {0}
@@ -1484,13 +1494,14 @@ p, li { white-space: pre-wrap; }
-
+
+
Aviso
-
+
Carregar set do {0}
@@ -1499,17 +1510,37 @@ p, li { white-space: pre-wrap; }
Carregar set atual do stream
-
+
Gerar Thumbnail
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Carregar set do usuário ({0})
-
+
Carregar set do usuário
@@ -1602,6 +1633,11 @@ p, li { white-space: pre-wrap; }
Identificador
+
+
+
+
+
punctuation
@@ -1645,11 +1681,49 @@ p, li { white-space: pre-wrap; }
Teclas de atalho
-
+
+
+
+
+
+
Padrão
+
+ settings.bsky
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
settings.control_score_from_stage_strike
@@ -1778,18 +1852,18 @@ p, li { white-space: pre-wrap; }
Tag do jogador {0} não está presente
-
+
-
+
A miniatura foi gerada aqui:
-
+
@@ -1797,7 +1871,7 @@ p, li { white-space: pre-wrap; }
tips
-
+
diff --git a/src/i18n/TSH_zh-CN.ts b/src/i18n/TSH_zh-CN.ts
index 707a9b18a..028caeaf4 100644
--- a/src/i18n/TSH_zh-CN.ts
+++ b/src/i18n/TSH_zh-CN.ts
@@ -697,36 +697,46 @@ p, li { white-space: pre-wrap; }
altText
-
-
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
+
+
+
-
-
+
+
-
+
-
+
-
+
@@ -738,7 +748,8 @@ p, li { white-space: pre-wrap; }
-
+
+
@@ -1146,7 +1157,7 @@ p, li { white-space: pre-wrap; }
-
+
@@ -1235,74 +1246,94 @@ p, li { white-space: pre-wrap; }
-
+
-
+
-
+
-
+
-
+
-
+
角色
-
+
-
-
+
+
+
+
+
+
+
+
+
+
+
+
-
+
-
-
+
+
-
+
+
+
+
+
+
+
+
+
+
+
-
+
-
+
@@ -1474,6 +1505,11 @@ p, li { white-space: pre-wrap; }
+
+
+
+
+
punctuation
@@ -1513,11 +1549,49 @@ p, li { white-space: pre-wrap; }
-
+
+
+
+
+
+
+
+ settings.bsky
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
settings.control_score_from_stage_strike
@@ -1604,18 +1678,18 @@ p, li { white-space: pre-wrap; }
thumb_app
-
+
TSH - 缩略图
-
+
-
+
@@ -1633,7 +1707,7 @@ p, li { white-space: pre-wrap; }
tips
-
+
diff --git a/src/i18n/TSH_zh-TW.ts b/src/i18n/TSH_zh-TW.ts
index 003bb86fe..4d0ec232d 100644
--- a/src/i18n/TSH_zh-TW.ts
+++ b/src/i18n/TSH_zh-TW.ts
@@ -697,36 +697,46 @@ p, li { white-space: pre-wrap; }
altText
-
-
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
+
+
+
-
-
+
+
-
+
-
+
-
+
@@ -738,7 +748,8 @@ p, li { white-space: pre-wrap; }
-
+
+
@@ -1146,7 +1157,7 @@ p, li { white-space: pre-wrap; }
-
+
@@ -1235,74 +1246,94 @@ p, li { white-space: pre-wrap; }
-
+
-
+
-
+
-
+
-
+
-
+
角色
-
+
-
-
+
+
+
+
+
+
+
+
+
+
+
+
-
+
-
-
+
+
-
+
+
+
+
+
+
+
+
+
+
+
-
+
-
+
@@ -1474,6 +1505,11 @@ p, li { white-space: pre-wrap; }
+
+
+
+
+
punctuation
@@ -1513,11 +1549,49 @@ p, li { white-space: pre-wrap; }
-
+
+
+
+
+
+
+
+ settings.bsky
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
settings.control_score_from_stage_strike
@@ -1604,18 +1678,18 @@ p, li { white-space: pre-wrap; }
thumb_app
-
+
-
+
-
+
@@ -1633,7 +1707,7 @@ p, li { white-space: pre-wrap; }
tips
-
+