-
-
Save galister/1a971254af72bb2a5bc27740e984bce2 to your computer and use it in GitHub Desktop.
VRC AVPro Playback Script for Linux
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/usr/bin/env python3 | |
| # This script was made to be used with WlxOverlay. When in an AVPro | |
| # world, this will spawn a media player window on your desktop, allowing | |
| # you to enjoy content via an overlay without the usual AVPro concerns. | |
| # | |
| # Usage: Start VRChat with AVPro DISABLED and run this script. | |
| # Optional: In case of a non-default install location, change below. | |
| # Requirements: ffplay (for rtsp streams), mpv (for everything else) | |
| import glob | |
| import os | |
| import re | |
| import subprocess | |
| import time | |
| from datetime import datetime,timedelta,tzinfo | |
| from dateutil.tz import tzlocal | |
| from zoneinfo import ZoneInfo | |
| home = os.getenv("HOME") | |
| # Change me | |
| vrc_appdata : str = f"{home}/.steam/steam/steamapps/compatdata/438100/pfx/drive_c/users/steamuser/AppData/LocalLow/VRChat/VRChat" | |
| # Change me | |
| tz : tzinfo = tzlocal() | |
| # Change me | |
| default_volume_percent : str = "50" | |
| ts_fmt : str = "%Y.%m.%d %H:%M:%S" | |
| log_path : str = f"{vrc_appdata}/output_log_*" | |
| playback_re = re.compile(r"^([0-9.]+ [0-9:]+)[^-]+- \s+\[Video Playback\] (?:Resolving URL|Attempting to resolve URL|URL '[^']+' resolved to) \'([^\']+)") | |
| interrupt_re = re.compile(r"^([0-9.]+ [0-9:]+)[^-]+- \s+\[(KineL|USharpVideo|iwaSync\d|ATA .+Now Playing|VideoTXL[^]]+|Behaviour\] OnLeftRoom)") | |
| cur_file : str = "" | |
| cur_pos : int = 0 | |
| video_start_time : datetime = datetime.min.replace(tzinfo=tz) | |
| player_process : subprocess.Popen | None = None | |
| def cleanup_player() -> None: | |
| global player_process, video_start_time | |
| if player_process: | |
| try: | |
| print("Stopping player...") | |
| player_process.terminate() | |
| except: | |
| pass | |
| video_start_time = datetime.min.replace(tzinfo=tz) | |
| player_process = None | |
| def launch_player(url: str, elapsed: timedelta) -> None: | |
| global player_process | |
| cleanup_player() | |
| url = url.replace("rtspt:", "rtsp:") | |
| if url.startswith("rtsp:"): | |
| args = ["ffplay", "-volume="+default_volume_percent]; | |
| else: | |
| args = ["mpv", "--cache-secs=5", "--volume="+default_volume_percent] | |
| if elapsed.total_seconds() > 5: | |
| args.append(f"--start={str(elapsed)}") | |
| args.append(url) | |
| print("Running: " + " ".join(args)) | |
| player_process = subprocess.Popen(args); | |
| def scan_file() -> None: | |
| global cur_file, cur_pos, video_start_time | |
| files = glob.glob(log_path) | |
| latest_file = max(files, key=os.path.getmtime) | |
| if latest_file != cur_file: | |
| cur_pos = 0 | |
| cur_file = latest_file | |
| with open(cur_file) as f: | |
| f.seek(cur_pos) | |
| old_pos = cur_pos | |
| lines = [] | |
| while True: | |
| line = f.readline() | |
| if not line: | |
| break | |
| lines.append(line) | |
| # debug | |
| # print('\r' + line.strip(), end='') | |
| cur_pos = f.tell() | |
| for line in reversed(lines): | |
| m = interrupt_re.match(line) | |
| if m: | |
| cleanup_player() | |
| print("Stop Triggered: " + line.rstrip()) | |
| break | |
| m = playback_re.match(line) | |
| if m: | |
| start_time = datetime.strptime(m.group(1), ts_fmt).replace(tzinfo=tz) | |
| elapsed = datetime.now(tz) - start_time | |
| if elapsed.total_seconds() < 1: | |
| cur_pos = old_pos | |
| break | |
| if start_time > video_start_time: | |
| print("Play Triggered: " + line.rstrip()) | |
| video_start_time = start_time | |
| launch_player(m.group(2), elapsed) | |
| break | |
| if __name__ == "__main__": | |
| while True: | |
| scan_file() | |
| time.sleep(1) | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment