generate_slides.py 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191
  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. current_slide_index: int = 0
  27. log("spawning subprocess for start slide...", color="yellow")
  28. threads = [
  29. Thread(
  30. target=generate_start_slide,
  31. args=(slidegen, template_img, zfill_length, disable_async),
  32. )
  33. ]
  34. for index, structure in enumerate(slidegen.chosen_structure):
  35. structure_element_splitted: list = slidegen.songtext[
  36. structure
  37. ].splitlines()
  38. line_count = len(structure_element_splitted)
  39. use_line_ranges_per_index = []
  40. use_lines_per_index = []
  41. if line_count <= const.STRUCTURE_ELEMENT_MAX_LINES:
  42. inner_slide_count = 1
  43. else:
  44. inner_slide_count: int = (
  45. line_count // const.STRUCTURE_ELEMENT_MAX_LINES + 1
  46. )
  47. use_lines_per_index = [
  48. line_count // inner_slide_count
  49. ] * inner_slide_count
  50. for inner_slide in range(inner_slide_count):
  51. if sum(use_lines_per_index) == line_count:
  52. break
  53. use_lines_per_index[inner_slide] = (
  54. use_lines_per_index[inner_slide] + 1
  55. )
  56. for inner_slide in range(inner_slide_count):
  57. use_line_ranges_per_index.append(
  58. sum(use_lines_per_index[:inner_slide])
  59. )
  60. for inner_slide in range(inner_slide_count):
  61. current_slide_index += 1
  62. log(
  63. "spawning subprocess for song slide [{} / {}]...".format(
  64. current_slide_index, slide_count
  65. ),
  66. color="yellow",
  67. )
  68. if inner_slide_count == 1:
  69. structure_element_value: str = slidegen.songtext[structure]
  70. else:
  71. splitted_wanted_range: list = structure_element_splitted[
  72. use_line_ranges_per_index[
  73. inner_slide
  74. ] : use_line_ranges_per_index[inner_slide]
  75. + use_lines_per_index[inner_slide]
  76. ]
  77. structure_element_value: str = ""
  78. for element in splitted_wanted_range:
  79. structure_element_value += element + "\n"
  80. structure_element_value = structure_element_value[:-1]
  81. threads.append(
  82. Thread(
  83. target=generate_song_slide,
  84. args=(
  85. slidegen.slide_style.song_slide_form,
  86. template_img,
  87. structure_element_value,
  88. slidegen,
  89. index,
  90. inner_slide_count,
  91. inner_slide,
  92. current_slide_index,
  93. zfill_length,
  94. disable_async,
  95. ),
  96. )
  97. )
  98. for thread in threads:
  99. thread.start()
  100. if disable_async:
  101. for thread in threads:
  102. thread.join()
  103. def generate_start_slide(slidegen, template_img, zfill_length, disable_async):
  104. first_slide = slidegen.slide_style.start_slide_form()
  105. start_slide_img = first_slide.get_slide(
  106. template_img,
  107. slidegen.metadata["book"],
  108. slidegen.metadata["text"],
  109. slidegen.metadata["melody"],
  110. )
  111. start_slide_img.format = const.IMAGE_FORMAT
  112. try:
  113. start_slide_img.save(
  114. filename=path.join(
  115. slidegen.output_dir,
  116. const.FILE_NAMEING
  117. + "1".zfill(zfill_length)
  118. + "."
  119. + const.FILE_EXTENSION,
  120. )
  121. )
  122. if disable_async:
  123. log("start slide generated and saved")
  124. except BlobError:
  125. error_msg("could not write start slide to target directory")
  126. def generate_song_slide(
  127. song_slide,
  128. template_img,
  129. structure_element_value,
  130. slidegen,
  131. index,
  132. inner_slide_count,
  133. inner_slide,
  134. current_slide_index,
  135. zfill_length,
  136. disable_async,
  137. ):
  138. song_slide_img = song_slide.get_slide(
  139. self=slidegen.slide_style.song_slide_form(),
  140. template_img=template_img,
  141. slide_text=structure_element_value,
  142. song_structure=slidegen.chosen_structure,
  143. index=index,
  144. use_arrow=bool(
  145. inner_slide_count != 1 and inner_slide != inner_slide_count - 1
  146. ),
  147. )
  148. song_slide_img.format = const.IMAGE_FORMAT
  149. try:
  150. song_slide_img.save(
  151. filename=path.join(
  152. slidegen.output_dir,
  153. const.FILE_NAMEING
  154. + str(current_slide_index + 1).zfill(zfill_length)
  155. + "."
  156. + const.FILE_EXTENSION,
  157. )
  158. )
  159. if disable_async:
  160. log("song slide {} generated and saved".format(current_slide_index))
  161. except BlobError:
  162. error_msg(
  163. "could not write song slide {} to target directory".format(
  164. current_slide_index
  165. )
  166. )