Explorar o código

add --offline and --sequential option to ssync.py + make slidegen and ssync fully async

Noah Vogt %!s(int64=2) %!d(string=hai) anos
pai
achega
ac42250760

+ 2 - 3
README.md

@@ -50,11 +50,11 @@ Here a short example:
 
     ./slidegen.py "../songrepo/Stille Nacht.txt" "~/Documents/Song Slides 1"
 
-The wrapper script doesn't have any additional arguments, as all the relevant variables are to be defined in the configuration file, but more on that below. Thus, execute ssync like this:
+The wrapper script does have two optional arguments, which are usually not needed. One is disables the syncing with the remote and to other disables the asynchronous slide generation, ut check out the help page as shown down below. To execute normally, use
 
     ./ssync.py
 
-Also for both programs there is a help page with `-h` or `--help`.
+and to show the help page for both programs use `-h` or `--help` interchangeably like this:
 
     ./ssync.py -h
     ./slidegen.py --help
@@ -325,7 +325,6 @@ These are some issues and possible changes that will be addressed or at least co
 
 - prevent all crashes:
     - safe `PROMPT_INPUT` parsing
-- asynchronous slide generation for start slide
 - use caching, with checksum checks for changes in the source file and the `PROMPT_INPUT`
 - provide ssync with the song structure, display it to the user and prevent him from entering a prompt that would cause slidegen to terminate unsuccessfully
 - add more documentation, especially explaining the slide generation, but also dependencies and deployment

+ 1 - 1
input/__init__.py

@@ -22,6 +22,6 @@ from .parse_file import (
     get_songchooser_cachefile_content,
 )
 from .parse_argv import parse_argv_as_tuple
-from .parse_argv import parse_ssync_args
+from .parse_argv import parse_ssync_args_as_tuple
 from .validate_config import validate_ssync_config, validate_songchooser_config
 from .slide_selection_iterator import slide_selection_iterator

+ 13 - 2
input/parse_argv.py

@@ -59,10 +59,21 @@ def parse_argv_as_tuple() -> tuple:
     log("parsing {}...".format(song_file_path))
     return song_file_path, output_dir, chosen_structure
 
-def parse_ssync_args() -> None:
+
+def parse_ssync_args_as_tuple() -> tuple:
     parser = argparse.ArgumentParser(
         prog="ssync",
         description="ssync - an interactive program syncing that lets "
         + "you choose songs to generate slides for using fzf.",
     )
-    parser.parse_args()
+    parser.add_argument(
+        "-o", "--offline", help="skips syncing with remote", action="store_true"
+    )
+    parser.add_argument(
+        "-s",
+        "--sequential",
+        help="disables async slide generation",
+        action="store_true",
+    )
+    args = parser.parse_args()
+    return args.offline, args.sequential

+ 2 - 2
input/slide_selection_iterator.py

@@ -25,7 +25,7 @@ import config as const
 import slidegen
 
 
-def slide_selection_iterator():
+def slide_selection_iterator(ssync):
     iterator_prompt = "Exit now? [y/N]: "
     structure_prompt = (
         "Choose song structure (leave blank for full song)"
@@ -90,7 +90,7 @@ def slide_selection_iterator():
                 dest_dir,
                 structure_prompt_answer,
             )
-            slidegen_instance.execute()
+            slidegen_instance.execute(ssync.disable_async)
 
     if os.path.isfile(tempfile_str):
         os.remove(tempfile_str)

+ 7 - 7
slidegen.py

@@ -25,8 +25,7 @@ from slides import (
     ClassicSongTemplate,
     ClassicStartSlide,
     ClassicSongSlide,
-    generate_start_slide,
-    generate_song_slides,
+    generate_slides,
     generate_song_template,
     count_number_of_slides_to_be_generated,
 )
@@ -60,10 +59,10 @@ class Slidegen:
         self.start_slide_form = start_slide_form
         self.song_slide_form = song_slide_form
 
-    def execute(self) -> None:
+    def execute(self, disable_async=False) -> None:
         self.parse_file()
         self.calculate_desired_structures()
-        self.generate_slides()
+        self.generate_slides(disable_async)
 
     def parse_file(self):
         parse_metadata(self)
@@ -72,14 +71,15 @@ class Slidegen:
     def calculate_desired_structures(self) -> None:
         self.chosen_structure = parse_prompt_input(self)
 
-    def generate_slides(self) -> None:
+    def generate_slides(self, disable_async: bool) -> None:
         template_img: Image = generate_song_template(self)
 
         slide_count: int = count_number_of_slides_to_be_generated(self)
         zfill_length: int = len(str(slide_count))
 
-        generate_start_slide(self, template_img, zfill_length)
-        generate_song_slides(self, slide_count, template_img, zfill_length)
+        generate_slides(
+            self, slide_count, template_img, zfill_length, disable_async
+        )
 
 
 def main() -> None:

+ 1 - 2
slides/__init__.py

@@ -23,7 +23,6 @@ from .classic_song_template import ClassicSongTemplate
 from .classic_start_slide import ClassicStartSlide
 from .classic_song_slide import ClassicSongSlide
 
-from .engine.start_slide import generate_start_slide
-from .engine.song_slides import generate_song_slides
+from .engine.generate_slides import generate_slides
 from .engine.song_template import generate_song_template
 from .engine.calc_slide_count import count_number_of_slides_to_be_generated

+ 42 - 9
slides/engine/song_slides.py → slides/engine/generate_slides.py

@@ -28,18 +28,22 @@ from utils import (
 import config as const
 
 
-def generate_song_slides(
-    slidegen,
-    slide_count,
-    template_img,
-    zfill_length,
+def generate_slides(
+    slidegen, slide_count, template_img, zfill_length, disable_async: bool
 ) -> None:
     log("generating song slides...")
     # unique_structures: list = list(set(chosen_structure))
 
     current_slide_index: int = 0
 
-    threads = []
+    log("spawning subprocess for start slide...", color="yellow")
+
+    threads = [
+        Thread(
+            target=generate_start_slide,
+            args=(slidegen, template_img, zfill_length, disable_async),
+        )
+    ]
 
     for index, structure in enumerate(slidegen.chosen_structure):
         structure_element_splitted: list = slidegen.songtext[
@@ -107,6 +111,7 @@ def generate_song_slides(
                         inner_slide,
                         current_slide_index,
                         zfill_length,
+                        disable_async,
                     ),
                 )
             )
@@ -114,8 +119,34 @@ def generate_song_slides(
     for thread in threads:
         thread.start()
 
-    for thread in threads:
-        thread.join()
+    if disable_async:
+        for thread in threads:
+            thread.join()
+
+
+def generate_start_slide(slidegen, template_img, zfill_length, disable_async):
+    first_slide = slidegen.start_slide_form()
+    start_slide_img = first_slide.get_slide(
+        template_img,
+        slidegen.metadata["book"],
+        slidegen.metadata["text"],
+        slidegen.metadata["melody"],
+    )
+    start_slide_img.format = const.IMAGE_FORMAT
+    try:
+        start_slide_img.save(
+            filename=path.join(
+                slidegen.output_dir,
+                const.FILE_NAMEING
+                + "1".zfill(zfill_length)
+                + "."
+                + const.FILE_EXTENSION,
+            )
+        )
+        if disable_async:
+            log("start slide generated and saved")
+    except BlobError:
+        error_msg("could not write start slide to target directory")
 
 
 def generate_song_slide(
@@ -128,6 +159,7 @@ def generate_song_slide(
     inner_slide,
     current_slide_index,
     zfill_length,
+    disable_async,
 ):
     song_slide_img = song_slide.get_slide(
         self=slidegen.song_slide_form(),
@@ -150,7 +182,8 @@ def generate_song_slide(
                 + const.FILE_EXTENSION,
             )
         )
-        log("song slide {} generated and saved".format(current_slide_index))
+        if disable_async:
+            log("song slide {} generated and saved".format(current_slide_index))
     except BlobError:
         error_msg(
             "could not write song slide {} to target directory".format(

+ 0 - 52
slides/engine/start_slide.py

@@ -1,52 +0,0 @@
-"""
-Copyright © 2022 Noah Vogt <noah@noahvogt.com>
-
-This program is free software: you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation, either version 3 of the License, or
-(at your option) any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with this program.  If not, see <http://www.gnu.org/licenses/>.
-"""
-
-from os import path
-
-from wand.exceptions import BlobError
-
-from utils import (
-    log,
-    error_msg,
-)
-
-import config as const
-
-
-def generate_start_slide(slidegen, template_img, zfill_length) -> None:
-    log("generating start slide...")
-
-    first_slide = slidegen.start_slide_form()
-    start_slide_img = first_slide.get_slide(
-        template_img,
-        slidegen.metadata["book"],
-        slidegen.metadata["text"],
-        slidegen.metadata["melody"],
-    )
-    start_slide_img.format = const.IMAGE_FORMAT
-    try:
-        start_slide_img.save(
-            filename=path.join(
-                slidegen.output_dir,
-                const.FILE_NAMEING
-                + "1".zfill(zfill_length)
-                + "."
-                + const.FILE_EXTENSION,
-            )
-        )
-    except BlobError:
-        error_msg("could not write start slide to target directory")

+ 7 - 6
ssync.py

@@ -23,28 +23,29 @@ from utils import clear_obs_slides_dir
 from input import (
     validate_ssync_config,
     slide_selection_iterator,
-    parse_ssync_args,
+    parse_ssync_args_as_tuple,
 )
 from sync import sync_slide_repo, save_new_checkfile, syncing_needed
 
 
 class Ssync:
-    def __init__(self):
-        parse_ssync_args()
+    def __init__(self, offline, sequential):
         validate_ssync_config()
+        self.offline_flag_enabled = offline
+        self.disable_async = sequential
 
     def execute(self):
-        if syncing_needed():
+        if syncing_needed(self):
             sync_slide_repo()
             save_new_checkfile()
         clear_obs_slides_dir()
-        slide_selection_iterator()
+        slide_selection_iterator(self)
 
 
 def main() -> None:
     colorama.init()
 
-    ssync: Ssync = Ssync()
+    ssync: Ssync = Ssync(*parse_ssync_args_as_tuple())
     ssync.execute()
 
 

+ 5 - 1
sync/syncing_needed.py

@@ -23,7 +23,11 @@ from utils import log
 import config as const
 
 
-def syncing_needed() -> bool:
+def syncing_needed(slidegen) -> bool:
+    if slidegen.offline_flag_enabled:
+        log("skipping sync with remote", color="cyan")
+        return False
+
     if not cachefiles_found():
         return True