.. _vhc3: ===== VHC 3 ===== Overview -------- The **VHC - Vico House Cup** is a **LAN event** organized by **Victorien "Vico" OST**. It brings together **16 players**, ranging from the **top 6 to top 30** in France, competing in a **LAN tournament** in Chièvres. The event is streamed live on **Vico's Twitch channel**. For this third edition, I volunteered to assist Vico to **help the event reach a new level**, building on my successful experiences with **Endowar and stream management**. Role ---- Initially, my role was **focused on improving the network architecture** and **managing data streams** during the event. However, due to a last-minute withdrawal, I had to **take full control of the broadcast and backstage operations**. Details ------- - **Network stream** All streams between various **OBS setups** were handled using the **NDI protocol**. - **Python Automation** I started by **automating key actions** with **Python** and the `obs-ws` library to **standardize workflows**: - A scripted **transition** to show/hide banners - Automated **player name updates**, including logo/title/pseudonym associations - Automated **caster name updates** - Management of **animations, cameras, and upcoming match sources** - **Draft handling** and **civilization updates** Then, I developed a **custom software interface** using `custom tkinter`, allowing me to manage all these standardized interactions **from a single central hub**. .. image:: /_static/images/vhc3_interface.png :align: center :width: 400px :class: vhc3-interface Gradually, I was able to **fully automate stream management**, reducing my direct interactions with OBS to just: - **Launching OBS** - **Loading the VHC3 profile** - **Starting the stream** I also leveraged `obs-ws` to **control camera scene switching** on a separate PC, which was responsible for handling specific **camera feeds**. - **Dynamic Ranking System** Instead of manually updating graphics for the rankings, I set up a **local Flask server** running on **port 8000**, allowing **real-time score updates** via **Google Sheets**. A Python script then **processed the data**, generating **HTML/Jinja/CSS** output for **displaying rankings** and the **tournament bracket**. Next Steps ---------- There are several improvements I aim to make to this **stream automation tool**: - **Automatic Scene & Source Creation** Currently, I only **edit** existing scenes. If a scene or source is missing, it’s **not created automatically**. I plan to build a system for **dynamic scene creation**, possibly with **default source placements**. - **Repository Structure & Code Readability** The project evolved quickly, leaving **room for better function modularization**. I need to **refactor several utilities**, improve **code organization**, and add **clearer comments**. - **Expanding Use Cases** Each **tournament or broadcast** has **unique rules**. I'd like to implement **minimal configuration switching** to easily adapt settings between events. Code Example ------------ Here is a bit of python code to hide or show the player's camera sources : .. code-block:: python def show_hide_cams(SCENE_GAME): # Connexion à OBS ws = obsws(OBS_HOST, OBS_PORT, OBS_PASSWORD) ws.connect() try : # Get Cam Status SCENE_CAM = "VHC Adds Cam" SCENE_CAM_OBJ = ws.call(requests.GetSceneItemId(sceneName=SCENE_GAME, sourceName=SCENE_CAM)) SCENE_CAM_ID=SCENE_CAM_OBJ.datain['sceneItemId'] response = ws.call(requests.GetSceneItemEnabled(sceneItemId=SCENE_CAM_ID, sceneName=SCENE_GAME)) IS_ENABLED = response.datain.get("sceneItemEnabled", False) if IS_ENABLED == True: ws.call(requests.SetSceneItemEnabled(sceneItemId=SCENE_CAM_ID, sceneItemEnabled=False, sceneName=SCENE_GAME)) elif IS_ENABLED == False: ws.call(requests.SetSceneItemEnabled(sceneItemId=SCENE_CAM_ID, sceneItemEnabled=True, sceneName=SCENE_GAME)) except Exception as e: print(f"Erreur lors du show cams : {e}") finally: ws.disconnect() Results ------- Here is the link to the **final match stream**: https://www.youtube.com/watch?v=wt0_8SXqTvQ Feel free to watch and enjoy!