Updated script to sync and archive playlist files from a remote system
This commit is contained in:
parent
faf42af274
commit
362603d160
35
scripts/NOTES.md
Normal file
35
scripts/NOTES.md
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
# Beat Saber Playlist Scripts
|
||||||
|
|
||||||
|
Tools for managing Beat Saber playlists and custom maps across Windows and other systems.
|
||||||
|
|
||||||
|
## Map Installation
|
||||||
|
|
||||||
|
To copy a custom map to Beat Saber:
|
||||||
|
```powershell
|
||||||
|
Copy-Item -Path "map_folder" -Destination "C:\Program Files (x86)\Steam\steamapps\common\Beat Saber\Beat Saber_Data\CustomLevels\" -Recurse
|
||||||
|
```
|
||||||
|
|
||||||
|
## Playlist Sync Script
|
||||||
|
`sabersync.py` is a utility script that:
|
||||||
|
- Syncs `.bplist` files between systems
|
||||||
|
- Archives old/deleted playlists
|
||||||
|
- Optionally syncs Beat Saber video recordings
|
||||||
|
|
||||||
|
Usage:
|
||||||
|
```bash
|
||||||
|
./sabersync.py [--video] [--help]
|
||||||
|
```
|
||||||
|
|
||||||
|
Options:
|
||||||
|
- `--video`: Sync video recordings from the remote system
|
||||||
|
- `--help`: Show help message
|
||||||
|
|
||||||
|
The script expects:
|
||||||
|
- SSH access to a Windows machine with alias `winroar`
|
||||||
|
- Beat Saber installed at standard Steam paths
|
||||||
|
- Playlists in `BSManager/BSInstances/1.39.1/Playlists/`
|
||||||
|
|
||||||
|
When run with `--video`, it will:
|
||||||
|
1. Copy videos from the remote system
|
||||||
|
2. Wait for confirmation
|
||||||
|
3. Clean up remote video files after transfer
|
118
scripts/sabersync.py
Executable file
118
scripts/sabersync.py
Executable file
@ -0,0 +1,118 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
# Helper script to backup playlists and copy new ones over
|
||||||
|
|
||||||
|
import argparse
|
||||||
|
import subprocess
|
||||||
|
import os
|
||||||
|
import shutil
|
||||||
|
from pathlib import Path
|
||||||
|
import sys
|
||||||
|
import shlex
|
||||||
|
|
||||||
|
def usage():
|
||||||
|
print("Usage: {} [--video]".format(sys.argv[0]))
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
def run_command(command, capture_output=False, text=True):
|
||||||
|
try:
|
||||||
|
result = subprocess.run(command, shell=True, check=True, capture_output=capture_output, text=text)
|
||||||
|
return result.stdout if capture_output else None
|
||||||
|
except subprocess.CalledProcessError as e:
|
||||||
|
print(f"Command '{command}' failed with exit code {e.returncode}")
|
||||||
|
sys.exit(e.returncode)
|
||||||
|
|
||||||
|
def main():
|
||||||
|
parser = argparse.ArgumentParser(description="Synchronize Beat Saber playlists and optionally videos.", add_help=False)
|
||||||
|
parser.add_argument('-v', '--video', action='store_true', help='Enable video synchronization')
|
||||||
|
parser.add_argument('-h', '--help', action='store_true', help='Show help message and exit')
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
if args.help:
|
||||||
|
usage()
|
||||||
|
|
||||||
|
COPY_VIDEOS = args.video
|
||||||
|
|
||||||
|
# Define paths
|
||||||
|
REMOTE_PLAYLISTS = "BSManager/BSInstances/1.39.1/Playlists/"
|
||||||
|
REMOTE_PLAYLISTS_WIN = "BSManager\\BSInstances\\1.39.1\\Playlists" # For Windows SSH commands
|
||||||
|
LOCAL_ARCHIVE_DIR = Path.home() / "archive" / "beatsaber-playlists"
|
||||||
|
LOCAL_ARCHIVE_SUBDIR = LOCAL_ARCHIVE_DIR / "archive"
|
||||||
|
LOCAL_BPLIST_DIR = Path.cwd()
|
||||||
|
|
||||||
|
# Ensure archive subdirectory exists
|
||||||
|
LOCAL_ARCHIVE_SUBDIR.mkdir(parents=True, exist_ok=True)
|
||||||
|
|
||||||
|
# Check for local *.bplist files and sync to remote using scp
|
||||||
|
bplist_files = list(LOCAL_BPLIST_DIR.glob("*.bplist"))
|
||||||
|
if bplist_files:
|
||||||
|
print("Starting synchronization of .bplist files to remote using scp...")
|
||||||
|
# Build file string with proper quoting using shlex.quote, so wildcard expansion isn't needed
|
||||||
|
files_str = " ".join(shlex.quote(str(file)) for file in bplist_files)
|
||||||
|
scp_sync_upload = f"scp {files_str} winroar:\"{REMOTE_PLAYLISTS}\""
|
||||||
|
run_command(scp_sync_upload)
|
||||||
|
# Remove local *.bplist files after successful transfer
|
||||||
|
for f in bplist_files:
|
||||||
|
f.unlink()
|
||||||
|
print(f"Removed local file: {f.name}")
|
||||||
|
|
||||||
|
# Fetch list of remote *.bplist files
|
||||||
|
print("Fetching list of remote .bplist files...")
|
||||||
|
ssh_command = f'ssh winroar "cd {REMOTE_PLAYLISTS_WIN} && dir /b *.bplist"'
|
||||||
|
remote_bplist = run_command(ssh_command, capture_output=True)
|
||||||
|
remote_bplist_files = set(remote_bplist.strip().split('\n')) if remote_bplist else set()
|
||||||
|
|
||||||
|
# Fetch list of local archive *.bplist files
|
||||||
|
print("Fetching list of local archived .bplist files...")
|
||||||
|
local_archive_files = set(f.name for f in LOCAL_ARCHIVE_DIR.glob("*.bplist"))
|
||||||
|
|
||||||
|
# Determine deleted files (present locally but not remotely)
|
||||||
|
deleted_files = local_archive_files - remote_bplist_files
|
||||||
|
if deleted_files:
|
||||||
|
print("Identifying deleted playlists...")
|
||||||
|
for file in deleted_files:
|
||||||
|
local_file = LOCAL_ARCHIVE_DIR / file
|
||||||
|
destination_file = LOCAL_ARCHIVE_SUBDIR / file
|
||||||
|
if local_file.exists():
|
||||||
|
if destination_file.exists():
|
||||||
|
destination_file.unlink() # Remove existing file to allow overwrite
|
||||||
|
print(f"Overwriting existing archived file: {file}")
|
||||||
|
shutil.move(str(local_file), str(destination_file))
|
||||||
|
print(f"Archived deleted playlist: {file}")
|
||||||
|
else:
|
||||||
|
print("No deleted playlists found.")
|
||||||
|
|
||||||
|
# Sync remote *.bplist to local archive directory
|
||||||
|
print("Downloading current remote .bplist files to local archive...")
|
||||||
|
scp_sync_download = (
|
||||||
|
f"scp winroar:\"{REMOTE_PLAYLISTS}*.bplist\" \"{LOCAL_ARCHIVE_DIR}/\""
|
||||||
|
)
|
||||||
|
run_command(scp_sync_download)
|
||||||
|
print("Download complete.")
|
||||||
|
|
||||||
|
# Optional video synchronization
|
||||||
|
if COPY_VIDEOS:
|
||||||
|
print("Starting video synchronization with scp...")
|
||||||
|
|
||||||
|
# Define remote and local video paths
|
||||||
|
REMOTE_VIDEOS = "/Users/pleb/Videos/Beat Saber/"
|
||||||
|
LOCAL_DOWNLOADS = Path.home() / "Downloads" / "Beat Saber"
|
||||||
|
|
||||||
|
# Ensure local downloads directory exists
|
||||||
|
LOCAL_DOWNLOADS.mkdir(parents=True, exist_ok=True)
|
||||||
|
|
||||||
|
# Construct scp command to copy videos from remote to local Downloads folder
|
||||||
|
scp_sync_videos = (
|
||||||
|
f"scp -r winroar:\"{REMOTE_VIDEOS}\" \"{LOCAL_DOWNLOADS}\""
|
||||||
|
)
|
||||||
|
run_command(scp_sync_videos)
|
||||||
|
print("Video files synchronized successfully.")
|
||||||
|
|
||||||
|
input("Press [Enter] to delete videos on winroar.")
|
||||||
|
|
||||||
|
# Delete videos on remote after confirmation
|
||||||
|
ssh_delete_command = f'ssh winroar \'rm -rf "{REMOTE_VIDEOS}"\''
|
||||||
|
run_command(ssh_delete_command)
|
||||||
|
print("Remote video directory deleted.")
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
84
scripts/sabersync.sh
Executable file
84
scripts/sabersync.sh
Executable file
@ -0,0 +1,84 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -e
|
||||||
|
|
||||||
|
# Function to display usage
|
||||||
|
usage() {
|
||||||
|
echo "Usage: $0 [--video]"
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
# Parse command-line arguments
|
||||||
|
COPY_VIDEOS=false
|
||||||
|
|
||||||
|
while [[ "$#" -gt 0 ]]; do
|
||||||
|
case $1 in
|
||||||
|
-v|--video)
|
||||||
|
COPY_VIDEOS=true
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
-h|--help)
|
||||||
|
usage
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
echo "Unknown parameter passed: $1"
|
||||||
|
usage
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
if [ -n "$(find . -maxdepth 1 -type f -name "*.bplist" -print -quit)" ]; then
|
||||||
|
scp ./*.bplist winroar:BSManager/BSInstances/1.39.1/Playlists/
|
||||||
|
rm -v ./*.bplist
|
||||||
|
fi
|
||||||
|
|
||||||
|
##
|
||||||
|
## Playlist Archive
|
||||||
|
##
|
||||||
|
|
||||||
|
# Define remote and local directories for playlist synchronization
|
||||||
|
REMOTE_PLAYLISTS="BSManager/BSInstances/1.39.1/Playlists/"
|
||||||
|
LOCAL_ARCHIVE_DIR=~/archive/beatsaber-playlists/
|
||||||
|
LOCAL_ARCHIVE_SUBDIR=~/archive/beatsaber-playlists/archive/
|
||||||
|
PREVIOUS_LIST=~/archive/beatsaber-playlists/previous_bplist_files.txt
|
||||||
|
|
||||||
|
# Ensure archive subdirectory exists
|
||||||
|
mkdir -p "$LOCAL_ARCHIVE_SUBDIR"
|
||||||
|
|
||||||
|
# Fetch current remote *.bplist files
|
||||||
|
ssh winroar "cd \"${REMOTE_PLAYLISTS}\" && dir /B *.bplist" > current_bplist_files.txt
|
||||||
|
|
||||||
|
# Compare with previous list to find deleted files
|
||||||
|
if [[ -f "$PREVIOUS_LIST" ]]; then
|
||||||
|
deleted_files=$(comm -23 <(sort "$PREVIOUS_LIST") <(sort current_bplist_files.txt))
|
||||||
|
for file in $deleted_files; do
|
||||||
|
filename=$(basename "$file")
|
||||||
|
if [[ -f "${LOCAL_ARCHIVE_DIR}${filename}" ]]; then
|
||||||
|
mv "${LOCAL_ARCHIVE_DIR}${filename}" "$LOCAL_ARCHIVE_SUBDIR"
|
||||||
|
echo "Archived deleted playlist: $filename"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Update the previous list
|
||||||
|
mv current_bplist_files.txt "$PREVIOUS_LIST"
|
||||||
|
|
||||||
|
# Sync playlist files from remote to local
|
||||||
|
scp -q winroar:"${REMOTE_PLAYLISTS}*.bplist" "$LOCAL_ARCHIVE_DIR"
|
||||||
|
|
||||||
|
# Optional video synchronization
|
||||||
|
if $COPY_VIDEOS; then
|
||||||
|
echo "Starting video synchronization..."
|
||||||
|
|
||||||
|
# Copy videos from remote to local Downloads folder
|
||||||
|
scp -r winroar:"Videos/Beat Saber/" "$HOME/Downloads/"
|
||||||
|
|
||||||
|
echo "Video files copied successfully."
|
||||||
|
|
||||||
|
echo "Press [Enter] to delete videos on winroar."
|
||||||
|
read -r
|
||||||
|
|
||||||
|
# Delete videos on remote after confirmation
|
||||||
|
ssh winroar 'rmdir Videos/Beat\ Saber /q /s'
|
||||||
|
|
||||||
|
echo "Remote video directory deleted."
|
||||||
|
fi
|
Loading…
x
Reference in New Issue
Block a user