diff --git a/website/.env b/website/.env index 19a975be..957cea56 100644 --- a/website/.env +++ b/website/.env @@ -1,5 +1,6 @@ VITE_DEPLOY_MODE=live -VITE_DATA_SERVER="https://data.slmn.gg" +# VITE_DATA_SERVER="https://data.slmn.gg" +VITE_DATA_SERVER="http://localhost:8901" # VITE_MAIN_DOMAIN="https://dev.slmn.gg" # for auth returns # VITE_MAIN_COOKIE_DOMAIN="dev.slmn.gg" # no protocol or ports (for cookies) diff --git a/website/src/apps/BroadcastApp.vue b/website/src/apps/BroadcastApp.vue index 6513d815..f72fe807 100644 --- a/website/src/apps/BroadcastApp.vue +++ b/website/src/apps/BroadcastApp.vue @@ -115,9 +115,9 @@ export default { window.addEventListener("obsSourceActiveChanged", (e) => { this.active = e.detail.active; }); - document.body.addEventListener("click", () => { - this.active = !this.active; - }); + // document.body.addEventListener("click", () => { + // this.active = !this.active; + // }); } if (this.broadcastKey) { console.log("loading with broadcastKey"); diff --git a/website/src/components/broadcast/MapDisplay.vue b/website/src/components/broadcast/MapDisplay.vue index ca6a3d0f..a50406b7 100644 --- a/website/src/components/broadcast/MapDisplay.vue +++ b/website/src/components/broadcast/MapDisplay.vue @@ -20,7 +20,7 @@ import { getNewURL } from "@/utils/images"; export default { name: "MapDisplay", components: { MapSegment }, - props: ["broadcast", "animationActive", "useTransitions", "noMapVideos"], + props: ["broadcast", "animationActive", "useTransitions", "virtualMatch", "noMapVideos"], data: () => ({ activeAudio: null, showNextMap: false, @@ -29,6 +29,7 @@ export default { }), computed: { match() { + if (this.virtualMatch) return this.virtualMatch; if (!this.broadcast?.live_match) return null; return ReactiveRoot(this.broadcast.live_match[0], { teams: ReactiveArray("teams", { diff --git a/website/src/components/broadcast/SoloControlButton.vue b/website/src/components/broadcast/SoloControlButton.vue new file mode 100644 index 00000000..048be489 --- /dev/null +++ b/website/src/components/broadcast/SoloControlButton.vue @@ -0,0 +1,102 @@ + + + + + diff --git a/website/src/components/broadcast/SoloMapButton.vue b/website/src/components/broadcast/SoloMapButton.vue new file mode 100644 index 00000000..c681bddf --- /dev/null +++ b/website/src/components/broadcast/SoloMapButton.vue @@ -0,0 +1,75 @@ + + + + + diff --git a/website/src/components/broadcast/SoloMapToggleButton.vue b/website/src/components/broadcast/SoloMapToggleButton.vue new file mode 100644 index 00000000..0e089c7e --- /dev/null +++ b/website/src/components/broadcast/SoloMapToggleButton.vue @@ -0,0 +1,99 @@ + + + + + diff --git a/website/src/components/broadcast/SoloOverlay.vue b/website/src/components/broadcast/SoloOverlay.vue new file mode 100644 index 00000000..3ea95c61 --- /dev/null +++ b/website/src/components/broadcast/SoloOverlay.vue @@ -0,0 +1,550 @@ + + + + + diff --git a/website/src/components/broadcast/SoloTeamControlButton.vue b/website/src/components/broadcast/SoloTeamControlButton.vue new file mode 100644 index 00000000..abff9511 --- /dev/null +++ b/website/src/components/broadcast/SoloTeamControlButton.vue @@ -0,0 +1,36 @@ + + + + + diff --git a/website/src/components/broadcast/break/BreakMatch.vue b/website/src/components/broadcast/break/BreakMatch.vue index febb44bf..ef6e4b11 100644 --- a/website/src/components/broadcast/break/BreakMatch.vue +++ b/website/src/components/broadcast/break/BreakMatch.vue @@ -13,7 +13,7 @@ -
+
{{ match.custom_name }} diff --git a/website/src/components/broadcast/break/BreakOverlay.vue b/website/src/components/broadcast/break/BreakOverlay.vue index d6c231b7..7d0890ba 100644 --- a/website/src/components/broadcast/break/BreakOverlay.vue +++ b/website/src/components/broadcast/break/BreakOverlay.vue @@ -23,9 +23,9 @@ -
Current time
+
Current time
-
@@ -36,8 +36,8 @@ :expanded="true" :key="match.id" :theme-color="themeColor"/>
- + :key="`Standings-${currentStage || ''}`"> +
@@ -74,7 +74,7 @@
- +
@@ -107,7 +107,7 @@ const tickTime = 25; export default { name: "BreakOverlay", - props: ["broadcast", "title", "animationActive", "secondary", "headlineInterval"], + props: ["broadcast", "title", "animationActive", "secondary", "headlineInterval", "virtualMatch", "customBreakAutomation"], components: { Squeezable, OtherBroadcasts, ThemeLogo, BreakMatchup, BreakStaffList, BreakHeadlines, BroadcastPreview, Bracket, Standings, BreakMatch, Sponsors, Countdown, ThemeTransition }, data: () => ({ tick: 0, @@ -134,6 +134,7 @@ export default { return resizedImageNoWrap(this.broadcast, ["break_image"], "h-1080"); }, nextMatch() { + if (this.virtualMatch) return this.virtualMatch; if (!this.broadcast || !this.broadcast.live_match || !this.broadcast.show_live_match) return null; return ReactiveRoot(this.broadcast.live_match[0], { teams: ReactiveArray("teams", { @@ -142,6 +143,7 @@ export default { }); }, fullSchedule() { + if (this.virtualMatch) return [this.virtualMatch]; if (!this.broadcast || !this.broadcast.schedule) return null; return ReactiveArray("schedule", { teams: ReactiveArray("teams", { @@ -192,9 +194,15 @@ export default { }, bracket() { if (!this.event?.brackets) return null; - if (!this.bracketKey) return this.event.brackets[0]; - const bracket = this.event.brackets.find(b => b && b.key === this.bracketKey); - return bracket || this.event.brackets[0]; + if (this.virtualMatch?._virtual_match_category) { + const bracket = this.event.brackets.find(b => b && b.associated_match_group === this.virtualMatch._virtual_match_category); + if (bracket) return bracket; + } + if (this.bracketKey) { + const bracket = this.event.brackets.find(b => b && b.key === this.bracketKey); + if (bracket) return bracket; + } + return this.event.brackets[0]; }, headlines() { return (this.broadcast?.headlines || []).filter(b => b.ready); @@ -202,29 +210,36 @@ export default { themeColor() { return themeBackground1(this.event); }, + breakAutomation() { + return this.customBreakAutomation || this.broadcast?.break_automation || []; + }, suggestedShow() { - if (!this.broadcast?.break_automation?.length) return null; + if (!this.breakAutomation?.length) return null; - let slides = this.broadcast.break_automation.filter(s => s.startsWith("use:")).map(s => s.replace("use: ", "")); + let slides = this.breakAutomation.filter(s => s.startsWith("use:")).map(s => s.replace("use: ", "")); console.log(slides); if (!this.nextMatch) slides = slides.filter(s => s !== "Matchup"); - - console.log(slides, this.nextMatch); + if (!this.currentStage) slides = slides.filter(s => s !== "Standings"); + if (!this.bracket) slides = slides.filter(s => s !== "Bracket"); + if (!this.virtualMatch) slides = slides.filter(s => s !== "Schedule"); // Only going to be 1 match atm so matchup will be fine + console.log(slides); // TODO: add stuff here that changes based on the countdown remaining - if (slides?.includes("Schedule") && this.broadcast.countdown_end && this.lastCountdownTick <= 30) { + if (slides?.includes("Schedule") && this.countdownEnd && this.lastCountdownTick <= 30) { return "Schedule"; } return slides[(this.tick % slides.length)]; }, automatedShow() { - if (this.broadcast?.break_automation?.length && this.lastCountdownTick <= 30 && this.broadcast.countdown_end) { - if (this.broadcast.break_automation.includes("setting: Always do 30s Schedule")) return "Schedule"; - if (this.broadcast.break_automation.includes("setting: Always do 30s Matchup") && this.nextMatch) return "Matchup"; + if (this.breakAutomation?.length && this.lastCountdownTick <= 30 && this.countdownEnd) { + if (this.breakAutomation.includes("setting: Always do 30s Schedule")) return "Schedule"; + if (this.breakAutomation.includes("setting: Always do 30s Matchup") && this.nextMatch) return "Matchup"; } + if (this.customBreakAutomation) return this.suggestedShow; + if (this.broadcast.break_display && this.broadcast.break_display !== "Automated") { // do what it says return this.broadcast.break_display; @@ -233,9 +248,18 @@ export default { return this.suggestedShow; } }, + currentStage() { + return this.virtualMatch?._virtual_match_category || this.broadcast?.current_stage; + }, + countdownEnd() { + return this.virtualMatch?._virtual_break_end || this.broadcast?.countdown_end; + }, matchIsLast() { if (!this.schedule?.length) return true; // no schedule - assume last if (!this.nextMatch?.first_to) return false; // no match - assume others?? + + // TODO: this logic doesn't make much sense. it should check if any match has completed, rather than the order in the schedule + const index = this.schedule.findIndex(match => match.id === this.nextMatch.id); if (index === -1) return true; // not in schedule - assume it's a schedule for tomorrow if (index === (this.schedule.length - 1)) return true; // last of the day! @@ -251,6 +275,7 @@ export default { }, overlayTitle() { const title = this.title || this.broadcast?.title || this.broadcast?.name || ""; + if (this.virtualMatch) return this.autoTitle || this.broadcast?.event?.name; const titleWithAuto = title.replace("{auto}", this.autoTitle); if (!titleWithAuto || titleWithAuto.trim().length === 0) return title; // make sure we have something here return titleWithAuto; diff --git a/website/src/components/broadcast/roots/OverviewOverlay.vue b/website/src/components/broadcast/roots/OverviewOverlay.vue index e380437b..65f36d8c 100644 --- a/website/src/components/broadcast/roots/OverviewOverlay.vue +++ b/website/src/components/broadcast/roots/OverviewOverlay.vue @@ -1,10 +1,10 @@ @@ -15,9 +15,10 @@ import DeskMatch from "@/components/broadcast/desk/DeskMatch"; export default { name: "OverviewOverlay", components: { DeskMatch, MapDisplay }, - props: ["broadcast"], + props: ["broadcast", "virtualMatch", "noMapVideos"], computed: { matchID() { + if (this.virtualMatch) return null; if (!this.broadcast?.live_match) return null; return this.broadcast.live_match[0]; } diff --git a/website/src/components/broadcast/roots/RosterOverlay.vue b/website/src/components/broadcast/roots/RosterOverlay.vue index 7926e2f1..4fa1ba11 100644 --- a/website/src/components/broadcast/roots/RosterOverlay.vue +++ b/website/src/components/broadcast/roots/RosterOverlay.vue @@ -62,12 +62,13 @@ import ThemeLogo from "@/components/website/ThemeLogo"; export default { name: "RosterOverlay", components: { ThemeTransition, GenericOverlay, ThemeLogo }, - props: ["broadcast", "title", "showRoles", "sort", "animationActive", "showStaff", "splitPlayers", "showBadges"], + props: ["broadcast", "title", "showRoles", "sort", "animationActive", "showStaff", "splitPlayers", "showBadges", "virtualMatch"], computed: { accentColor() { return this.$root?.broadcast?.event?.theme?.color_theme; }, match() { + if (this.virtualMatch) return this.virtualMatch; if (!this.broadcast || !this.broadcast.live_match) return null; return ReactiveRoot(this.broadcast.live_match[0], { teams: ReactiveArray("teams", { diff --git a/website/src/router/broadcast.js b/website/src/router/broadcast.js index 224fa73e..58d4ae67 100644 --- a/website/src/router/broadcast.js +++ b/website/src/router/broadcast.js @@ -188,5 +188,14 @@ export default [ wsUrl: route.query.url || route.query.wsUrl || route.query.wsurl || route.query.wsURL || "ws://127.0.0.1:4455", wsPassword: route.query.wsPassword || route.query.password || route.query.pw }) + }, + { + path: "solo", + component: () => import("@/components/broadcast/SoloOverlay.vue"), + props: route => ({ + modules: route.query.modules?.split(","), + rosterOptions: (route.query.rosterOptions || route.query.roster)?.split(","), + showMapVideos: !!(route.query.mapVideos || route.query.videos) + }) } ];