generate_slides.py 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192
  1. """
  2. Copyright © 2022 Noah Vogt <noah@noahvogt.com>
  3. This program is free software: you can redistribute it and/or modify
  4. it under the terms of the GNU General Public License as published by
  5. the Free Software Foundation, either version 3 of the License, or
  6. (at your option) any later version.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. GNU General Public License for more details.
  11. You should have received a copy of the GNU General Public License
  12. along with this program. If not, see <http://www.gnu.org/licenses/>.
  13. """
  14. from threading import Thread
  15. from os import path
  16. from wand.exceptions import BlobError
  17. from utils import (
  18. log,
  19. error_msg,
  20. )
  21. import config as const
  22. def generate_slides(
  23. slidegen, slide_count, template_img, zfill_length, disable_async: bool
  24. ) -> None:
  25. log("generating song slides...")
  26. # unique_structures: list = list(set(chosen_structure))
  27. current_slide_index: int = 0
  28. log("spawning subprocess for start slide...", color="yellow")
  29. threads = [
  30. Thread(
  31. target=generate_start_slide,
  32. args=(slidegen, template_img, zfill_length, disable_async),
  33. )
  34. ]
  35. for index, structure in enumerate(slidegen.chosen_structure):
  36. structure_element_splitted: list = slidegen.songtext[
  37. structure
  38. ].splitlines()
  39. line_count = len(structure_element_splitted)
  40. use_line_ranges_per_index = []
  41. use_lines_per_index = []
  42. if line_count <= const.STRUCTURE_ELEMENT_MAX_LINES:
  43. inner_slide_count = 1
  44. else:
  45. inner_slide_count: int = (
  46. line_count // const.STRUCTURE_ELEMENT_MAX_LINES + 1
  47. )
  48. use_lines_per_index = [
  49. line_count // inner_slide_count
  50. ] * inner_slide_count
  51. for inner_slide in range(inner_slide_count):
  52. if sum(use_lines_per_index) == line_count:
  53. break
  54. use_lines_per_index[inner_slide] = (
  55. use_lines_per_index[inner_slide] + 1
  56. )
  57. for inner_slide in range(inner_slide_count):
  58. use_line_ranges_per_index.append(
  59. sum(use_lines_per_index[:inner_slide])
  60. )
  61. for inner_slide in range(inner_slide_count):
  62. current_slide_index += 1
  63. log(
  64. "spawning subprocess for song slide [{} / {}]...".format(
  65. current_slide_index, slide_count
  66. ),
  67. color="yellow",
  68. )
  69. if inner_slide_count == 1:
  70. structure_element_value: str = slidegen.songtext[structure]
  71. else:
  72. splitted_wanted_range: list = structure_element_splitted[
  73. use_line_ranges_per_index[
  74. inner_slide
  75. ] : use_line_ranges_per_index[inner_slide]
  76. + use_lines_per_index[inner_slide]
  77. ]
  78. structure_element_value: str = ""
  79. for element in splitted_wanted_range:
  80. structure_element_value += element + "\n"
  81. structure_element_value = structure_element_value[:-1]
  82. threads.append(
  83. Thread(
  84. target=generate_song_slide,
  85. args=(
  86. slidegen.song_slide_form,
  87. template_img,
  88. structure_element_value,
  89. slidegen,
  90. index,
  91. inner_slide_count,
  92. inner_slide,
  93. current_slide_index,
  94. zfill_length,
  95. disable_async,
  96. ),
  97. )
  98. )
  99. for thread in threads:
  100. thread.start()
  101. if disable_async:
  102. for thread in threads:
  103. thread.join()
  104. def generate_start_slide(slidegen, template_img, zfill_length, disable_async):
  105. first_slide = slidegen.start_slide_form()
  106. start_slide_img = first_slide.get_slide(
  107. template_img,
  108. slidegen.metadata["book"],
  109. slidegen.metadata["text"],
  110. slidegen.metadata["melody"],
  111. )
  112. start_slide_img.format = const.IMAGE_FORMAT
  113. try:
  114. start_slide_img.save(
  115. filename=path.join(
  116. slidegen.output_dir,
  117. const.FILE_NAMEING
  118. + "1".zfill(zfill_length)
  119. + "."
  120. + const.FILE_EXTENSION,
  121. )
  122. )
  123. if disable_async:
  124. log("start slide generated and saved")
  125. except BlobError:
  126. error_msg("could not write start slide to target directory")
  127. def generate_song_slide(
  128. song_slide,
  129. template_img,
  130. structure_element_value,
  131. slidegen,
  132. index,
  133. inner_slide_count,
  134. inner_slide,
  135. current_slide_index,
  136. zfill_length,
  137. disable_async,
  138. ):
  139. song_slide_img = song_slide.get_slide(
  140. self=slidegen.song_slide_form(),
  141. template_img=template_img,
  142. slide_text=structure_element_value,
  143. song_structure=slidegen.chosen_structure,
  144. index=index,
  145. use_arrow=bool(
  146. inner_slide_count != 1 and inner_slide != inner_slide_count - 1
  147. ),
  148. )
  149. song_slide_img.format = const.IMAGE_FORMAT
  150. try:
  151. song_slide_img.save(
  152. filename=path.join(
  153. slidegen.output_dir,
  154. const.FILE_NAMEING
  155. + str(current_slide_index + 1).zfill(zfill_length)
  156. + "."
  157. + const.FILE_EXTENSION,
  158. )
  159. )
  160. if disable_async:
  161. log("song slide {} generated and saved".format(current_slide_index))
  162. except BlobError:
  163. error_msg(
  164. "could not write song slide {} to target directory".format(
  165. current_slide_index
  166. )
  167. )