|
@@ -1,5 +1,6 @@
|
|
#!/usr/bin/env python3
|
|
#!/usr/bin/env python3
|
|
|
|
|
|
|
|
+import re
|
|
import os
|
|
import os
|
|
import sys
|
|
import sys
|
|
import shutil
|
|
import shutil
|
|
@@ -8,6 +9,14 @@ from configparser import ConfigParser
|
|
from termcolor import colored
|
|
from termcolor import colored
|
|
import colorama
|
|
import colorama
|
|
|
|
|
|
|
|
+CHECKFILE = "slidegen-checkfile.txt"
|
|
|
|
+CACHEFILE = "slidegen-cachefile.txt"
|
|
|
|
+
|
|
|
|
+NULNAME = ""
|
|
|
|
+if os.name == "nt":
|
|
|
|
+ NULNAME = "NUL"
|
|
|
|
+else:
|
|
|
|
+ NULNAME = "/dev/null"
|
|
|
|
|
|
def error_msg(msg: str):
|
|
def error_msg(msg: str):
|
|
print(colored("[*] Error: {}".format(msg), "red"))
|
|
print(colored("[*] Error: {}".format(msg), "red"))
|
|
@@ -28,6 +37,10 @@ class Ssync:
|
|
try:
|
|
try:
|
|
self.rclone_remote_dir = config_parser["RCLONE"]["remote_dir"]
|
|
self.rclone_remote_dir = config_parser["RCLONE"]["remote_dir"]
|
|
self.rclone_local_dir = config_parser["RCLONE"]["local_dir"]
|
|
self.rclone_local_dir = config_parser["RCLONE"]["local_dir"]
|
|
|
|
+
|
|
|
|
+ self.slidegen_exe_path = config_parser["SLIDEGEN"]["exe_path"]
|
|
|
|
+ self.slidegen_cache_dir = config_parser["SLIDEGEN"]["cache_dir"]
|
|
|
|
+
|
|
self.obs_slides_dir = config_parser["OBS"]["slides_dir"]
|
|
self.obs_slides_dir = config_parser["OBS"]["slides_dir"]
|
|
self.obs_target_subdir = config_parser["OBS"]["target_subdir"]
|
|
self.obs_target_subdir = config_parser["OBS"]["target_subdir"]
|
|
self.obs_min_subdirs = int(config_parser["OBS"]["min_subdirs"])
|
|
self.obs_min_subdirs = int(config_parser["OBS"]["min_subdirs"])
|
|
@@ -52,8 +65,10 @@ class Ssync:
|
|
os.unlink(file_path)
|
|
os.unlink(file_path)
|
|
elif os.path.isdir(file_path):
|
|
elif os.path.isdir(file_path):
|
|
shutil.rmtree(file_path)
|
|
shutil.rmtree(file_path)
|
|
- except Exception as e:
|
|
|
|
- error_msg("Failed to delete %s. Reason: %s" % (file_path, e))
|
|
|
|
|
|
+ except Exception as error:
|
|
|
|
+ error_msg(
|
|
|
|
+ "Failed to delete %s. Reason: %s" % (file_path, error)
|
|
|
|
+ )
|
|
|
|
|
|
def create_minimum_subdirs(self, count: int):
|
|
def create_minimum_subdirs(self, count: int):
|
|
if count >= self.obs_min_subdirs:
|
|
if count >= self.obs_min_subdirs:
|
|
@@ -66,54 +81,117 @@ class Ssync:
|
|
os.mkdir(dirname)
|
|
os.mkdir(dirname)
|
|
|
|
|
|
def slide_selection_iterator(self):
|
|
def slide_selection_iterator(self):
|
|
- iterator_prompt = "Exit now? (default=no) [y/N]: "
|
|
|
|
- dir_list_str = ""
|
|
|
|
- for directory in os.listdir(self.rclone_local_dir):
|
|
|
|
- dir_list_str += directory + "\n"
|
|
|
|
- dir_list_str = dir_list_str[:-1]
|
|
|
|
|
|
+ iterator_prompt = "Exit now? [y/N]: "
|
|
|
|
+ structure_prompt = (
|
|
|
|
+ "Choose song structure (leave blank for full song)"
|
|
|
|
+ + " eg. [1,R,2,R] / [1-4]: "
|
|
|
|
+ )
|
|
|
|
+ file_list_str = ""
|
|
|
|
+ for file in os.listdir(self.rclone_local_dir):
|
|
|
|
+ file_list_str += file + "\n"
|
|
|
|
+ file_list_str = file_list_str[:-1]
|
|
tempfile_str = ".chosen-tempfile"
|
|
tempfile_str = ".chosen-tempfile"
|
|
|
|
|
|
index = 0
|
|
index = 0
|
|
while True:
|
|
while True:
|
|
index += 1
|
|
index += 1
|
|
- prompt_answer = str(
|
|
|
|
- input(
|
|
|
|
- "[{} {}] ".format(self.obs_target_subdir, index)
|
|
|
|
- + iterator_prompt
|
|
|
|
- )
|
|
|
|
- )
|
|
|
|
|
|
+ input_song_prompt = "[{} {}] ".format(self.obs_target_subdir, index)
|
|
|
|
+ prompt_answer = str(input(input_song_prompt + iterator_prompt))
|
|
if prompt_answer.lower() == "y":
|
|
if prompt_answer.lower() == "y":
|
|
self.create_minimum_subdirs(index)
|
|
self.create_minimum_subdirs(index)
|
|
break
|
|
break
|
|
|
|
|
|
- dir_list_str = dir_list_str.replace("\n", "\\n")
|
|
|
|
|
|
+ file_list_str = file_list_str.replace("\n", "\\n")
|
|
os.system(
|
|
os.system(
|
|
- 'printf "{}" | fzf > {}'.format(dir_list_str, tempfile_str)
|
|
|
|
|
|
+ 'printf "{}" | fzf > {}'.format(file_list_str, tempfile_str)
|
|
)
|
|
)
|
|
|
|
|
|
- with open(tempfile_str, mode="r") as tempfile_file_opener:
|
|
|
|
- chosen_slides = tempfile_file_opener.read()[:-1].strip()
|
|
|
|
|
|
+ with open(
|
|
|
|
+ tempfile_str, encoding="utf-8", mode="r"
|
|
|
|
+ ) as tempfile_file_opener:
|
|
|
|
+ chosen_song_file = tempfile_file_opener.read()[:-1].strip()
|
|
|
|
|
|
- if len(chosen_slides) == 0:
|
|
|
|
|
|
+ if len(chosen_song_file) == 0:
|
|
log("no slides chosen, skipping...")
|
|
log("no slides chosen, skipping...")
|
|
else:
|
|
else:
|
|
|
|
+ structure_prompt_answer = input(
|
|
|
|
+ input_song_prompt + structure_prompt
|
|
|
|
+ )
|
|
|
|
+
|
|
log(
|
|
log(
|
|
- "copying slides '{}' to '{} {}'...".format(
|
|
|
|
- chosen_slides, self.obs_target_subdir, index
|
|
|
|
|
|
+ "generating slides '{}' to '{} {}'...".format(
|
|
|
|
+ chosen_song_file, self.obs_target_subdir, index
|
|
)
|
|
)
|
|
)
|
|
)
|
|
- src_dir = os.path.join(self.rclone_local_dir, chosen_slides)
|
|
|
|
|
|
+ src_dir = os.path.join(self.rclone_local_dir, chosen_song_file)
|
|
dest_dir = os.path.join(
|
|
dest_dir = os.path.join(
|
|
- self.obs_slides_dir,
|
|
|
|
|
|
+ self.slidegen_cache_dir,
|
|
self.obs_target_subdir + " " + str(index),
|
|
self.obs_target_subdir + " " + str(index),
|
|
)
|
|
)
|
|
- shutil.copytree(src_dir, dest_dir)
|
|
|
|
|
|
+ os.mkdir(dest_dir)
|
|
|
|
+ os.system(
|
|
|
|
+ 'python3 "{}" "{}" "{}" "{}"'.format(
|
|
|
|
+ self.slidegen_exe_path,
|
|
|
|
+ src_dir,
|
|
|
|
+ dest_dir,
|
|
|
|
+ structure_prompt_answer,
|
|
|
|
+ )
|
|
|
|
+ )
|
|
|
|
|
|
if os.path.isfile(tempfile_str):
|
|
if os.path.isfile(tempfile_str):
|
|
os.remove(tempfile_str)
|
|
os.remove(tempfile_str)
|
|
|
|
|
|
|
|
+ def cachefiles_found(self):
|
|
|
|
+ return os.path.isfile(
|
|
|
|
+ os.path.join(self.slidegen_cache_dir, CHECKFILE)
|
|
|
|
+ ) and os.path.isfile(os.path.join(self.slidegen_cache_dir, CACHEFILE))
|
|
|
|
+
|
|
|
|
+ def syncing_needed(self) -> bool:
|
|
|
|
+ if not self.cachefiles_found():
|
|
|
|
+ return True
|
|
|
|
+
|
|
|
|
+ log("checking for remote changes...")
|
|
|
|
+ os.system(
|
|
|
|
+ 'rclone md5sum {} --checkfile {} > {} 2> {}'.format(
|
|
|
|
+ self.rclone_remote_dir,
|
|
|
|
+ os.path.join(self.slidegen_cache_dir, CHECKFILE),
|
|
|
|
+ NULNAME,
|
|
|
|
+ os.path.join(self.slidegen_cache_dir, CACHEFILE),
|
|
|
|
+ )
|
|
|
|
+ )
|
|
|
|
+
|
|
|
|
+ with open(
|
|
|
|
+ os.path.join(self.slidegen_cache_dir, CACHEFILE),
|
|
|
|
+ mode="r",
|
|
|
|
+ encoding="utf-8",
|
|
|
|
+ ) as cachefile_reader:
|
|
|
|
+ cachefile_content = cachefile_reader.readlines()
|
|
|
|
+ for line in cachefile_content:
|
|
|
|
+ if re.search(": ([0-9])+ differences found$", line):
|
|
|
|
+ diffs = int(
|
|
|
|
+ line[line.rfind(":") + 1 : line.find("differences")]
|
|
|
|
+ )
|
|
|
|
+ return bool(diffs)
|
|
|
|
+ return False
|
|
|
|
+
|
|
|
|
+ def save_new_checkfile(self):
|
|
|
|
+ log("saving new checkfile...")
|
|
|
|
+ os.system(
|
|
|
|
+ 'rclone md5sum {} > "{}"'.format(
|
|
|
|
+ self.rclone_remote_dir,
|
|
|
|
+ os.path.join(self.slidegen_cache_dir, CHECKFILE),
|
|
|
|
+ )
|
|
|
|
+ )
|
|
|
|
+ if not os.path.isfile(os.path.join(self.slidegen_cache_dir, CACHEFILE)):
|
|
|
|
+ shutil.copyfile(
|
|
|
|
+ os.path.join(self.slidegen_cache_dir, CHECKFILE),
|
|
|
|
+ os.path.join(self.slidegen_cache_dir, CACHEFILE),
|
|
|
|
+ )
|
|
|
|
+
|
|
def execute(self):
|
|
def execute(self):
|
|
- self.sync_slide_repo()
|
|
|
|
|
|
+ if self.syncing_needed():
|
|
|
|
+ self.sync_slide_repo()
|
|
|
|
+ self.save_new_checkfile()
|
|
self.clear_obs_slides_dir()
|
|
self.clear_obs_slides_dir()
|
|
self.slide_selection_iterator()
|
|
self.slide_selection_iterator()
|
|
|
|
|