multimedia_paradise 1.1.314

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of multimedia_paradise might be problematic. Click here for more details.

Files changed (417) hide show
  1. checksums.yaml +7 -0
  2. data/README.md +2340 -0
  3. data/bin/audio_player +12 -0
  4. data/bin/auto_title +7 -0
  5. data/bin/convert_audio_to_mp4video_with_image +7 -0
  6. data/bin/cut_audio +7 -0
  7. data/bin/cut_multimedia +7 -0
  8. data/bin/extract_audio +7 -0
  9. data/bin/ffmpeg_merge +7 -0
  10. data/bin/file_duration +7 -0
  11. data/bin/gtk_radio +7 -0
  12. data/bin/loop_this_video +7 -0
  13. data/bin/merge_avi_files +7 -0
  14. data/bin/merge_mp3 +7 -0
  15. data/bin/missing_video_files +7 -0
  16. data/bin/movie_searcher +7 -0
  17. data/bin/mp3_to_opus +7 -0
  18. data/bin/mplayer_wrapper +7 -0
  19. data/bin/multimedia_information +11 -0
  20. data/bin/multimedia_paradise +9 -0
  21. data/bin/multimedia_paradise_sinatra +7 -0
  22. data/bin/play_random_simpsons_video +7 -0
  23. data/bin/playlist +7 -0
  24. data/bin/random_video +7 -0
  25. data/bin/remove_audio +9 -0
  26. data/bin/remove_last_second +7 -0
  27. data/bin/remove_subtitles +7 -0
  28. data/bin/tag_mp3_files +7 -0
  29. data/bin/to_aiff +10 -0
  30. data/bin/to_mp4 +7 -0
  31. data/bin/verbose_analyse_this_mp3_file_for_id3_tags +9 -0
  32. data/bin/video_codec +7 -0
  33. data/bin/video_information +8 -0
  34. data/bin/video_player +11 -0
  35. data/bin/video_to_images +7 -0
  36. data/bin/vp9 +9 -0
  37. data/bin/waveform +73 -0
  38. data/doc/CHANGELOG.md +44 -0
  39. data/doc/LINKS.md +6 -0
  40. data/doc/MOTIVATION_FOR_THIS_PROJECT.md +22 -0
  41. data/doc/MergingVideoLectures.md +12 -0
  42. data/doc/README.gen +2300 -0
  43. data/doc/Readme_for_the_cut_audio_component.md +168 -0
  44. data/doc/todo/todo_for_the_GUIs.md +0 -0
  45. data/doc/todo/todo_for_the_multimedia_paradise_project.md +111 -0
  46. data/lib/multimedia_paradise/audio/audio_player/audio_player.rb +83 -0
  47. data/lib/multimedia_paradise/audio/audio_player/constants.rb +136 -0
  48. data/lib/multimedia_paradise/audio/audio_player/menu.rb +164 -0
  49. data/lib/multimedia_paradise/audio/audio_player/misc.rb +718 -0
  50. data/lib/multimedia_paradise/audio/audio_player/reset.rb +77 -0
  51. data/lib/multimedia_paradise/audio/audio_player/tab.rb +35 -0
  52. data/lib/multimedia_paradise/audio/audio_tag_reader/README.md +7 -0
  53. data/lib/multimedia_paradise/audio/audio_tag_reader/audio_tag_reader.rb +503 -0
  54. data/lib/multimedia_paradise/audio/base.rb +67 -0
  55. data/lib/multimedia_paradise/audio/compress.rb +97 -0
  56. data/lib/multimedia_paradise/audio/create_m3u_playlist.rb +245 -0
  57. data/lib/multimedia_paradise/audio/extract_audio/constants.rb +37 -0
  58. data/lib/multimedia_paradise/audio/extract_audio/extract_audio.rb +417 -0
  59. data/lib/multimedia_paradise/audio/file_duration/constants.rb +53 -0
  60. data/lib/multimedia_paradise/audio/file_duration/file_duration.rb +602 -0
  61. data/lib/multimedia_paradise/audio/genres/boogie.rb +35 -0
  62. data/lib/multimedia_paradise/audio/genres/concerts.rb +35 -0
  63. data/lib/multimedia_paradise/audio/genres/constants.rb +53 -0
  64. data/lib/multimedia_paradise/audio/genres/eurodance.rb +35 -0
  65. data/lib/multimedia_paradise/audio/genres/genre.rb +696 -0
  66. data/lib/multimedia_paradise/audio/genres/hip_hop.rb +35 -0
  67. data/lib/multimedia_paradise/audio/genres/italian_songs.rb +35 -0
  68. data/lib/multimedia_paradise/audio/genres/the_1980s.rb +35 -0
  69. data/lib/multimedia_paradise/audio/genres/trance.rb +35 -0
  70. data/lib/multimedia_paradise/audio/lyrics_fetcher.rb +238 -0
  71. data/lib/multimedia_paradise/audio/merge_audio_files.rb +136 -0
  72. data/lib/multimedia_paradise/audio/modify_year_of_audio_file.rb +151 -0
  73. data/lib/multimedia_paradise/audio/n_audio_songs.rb +216 -0
  74. data/lib/multimedia_paradise/audio/play_all_audio_files.rb +122 -0
  75. data/lib/multimedia_paradise/audio/playlist/playlist.rb +1559 -0
  76. data/lib/multimedia_paradise/audio/remove_audio.rb +98 -0
  77. data/lib/multimedia_paradise/audio/remove_last_second.rb +83 -0
  78. data/lib/multimedia_paradise/audio/report_missing_id.rb +139 -0
  79. data/lib/multimedia_paradise/audio/streamripper/constants.rb +51 -0
  80. data/lib/multimedia_paradise/audio/streamripper/streamripper_wrapper.rb +279 -0
  81. data/lib/multimedia_paradise/audio/to_mp3.rb +138 -0
  82. data/lib/multimedia_paradise/audio/to_ogg.rb +104 -0
  83. data/lib/multimedia_paradise/audio/wav_to_mp3.rb +87 -0
  84. data/lib/multimedia_paradise/audio/waveform/class.rb +341 -0
  85. data/lib/multimedia_paradise/audio/waveform/constants.rb +38 -0
  86. data/lib/multimedia_paradise/audio/waveform/log.rb +101 -0
  87. data/lib/multimedia_paradise/autoinclude.rb +3 -0
  88. data/lib/multimedia_paradise/autoinclude_remove_audio.rb +6 -0
  89. data/lib/multimedia_paradise/base/base.rb +34 -0
  90. data/lib/multimedia_paradise/base/colours.rb +354 -0
  91. data/lib/multimedia_paradise/base/commandline_arguments.rb +52 -0
  92. data/lib/multimedia_paradise/base/constants.rb +19 -0
  93. data/lib/multimedia_paradise/base/encoding.rb +31 -0
  94. data/lib/multimedia_paradise/base/misc.rb +618 -0
  95. data/lib/multimedia_paradise/base/namespace.rb +36 -0
  96. data/lib/multimedia_paradise/base/time.rb +25 -0
  97. data/lib/multimedia_paradise/colours/colours.rb +82 -0
  98. data/lib/multimedia_paradise/commandline/menu.rb +498 -0
  99. data/lib/multimedia_paradise/configuration/play_zoomed.yml +1 -0
  100. data/lib/multimedia_paradise/constants/constants.rb +23 -0
  101. data/lib/multimedia_paradise/constants/conversions.rb +62 -0
  102. data/lib/multimedia_paradise/constants/directory_constants.rb +133 -0
  103. data/lib/multimedia_paradise/constants/encodings.rb +26 -0
  104. data/lib/multimedia_paradise/constants/file_constants.rb +171 -0
  105. data/lib/multimedia_paradise/constants/misc.rb +80 -0
  106. data/lib/multimedia_paradise/constants/my_video_directory.rb +30 -0
  107. data/lib/multimedia_paradise/constants/namespace.rb +14 -0
  108. data/lib/multimedia_paradise/constants/newline.rb +14 -0
  109. data/lib/multimedia_paradise/constants/video_filetypes.rb +27 -0
  110. data/lib/multimedia_paradise/constants/web_constants.rb +150 -0
  111. data/lib/multimedia_paradise/conversions/README.md +2 -0
  112. data/lib/multimedia_paradise/conversions/conversions.rb +930 -0
  113. data/lib/multimedia_paradise/css/project.css +15 -0
  114. data/lib/multimedia_paradise/data/asoundrc +12 -0
  115. data/lib/multimedia_paradise/ffmpeg/README.md +2 -0
  116. data/lib/multimedia_paradise/ffmpeg/ffmpeg.rb +620 -0
  117. data/lib/multimedia_paradise/gui/fox/play_from_radio_station.rb +75 -0
  118. data/lib/multimedia_paradise/gui/gosu/video_player/video_player.rb +109 -0
  119. data/lib/multimedia_paradise/gui/gtk2/lyrics/lyrics.rb +33 -0
  120. data/lib/multimedia_paradise/gui/gtk2/multimedia_converter/multimedia_converter.rb +33 -0
  121. data/lib/multimedia_paradise/gui/gtk2/notebook.rb +144 -0
  122. data/lib/multimedia_paradise/gui/gtk2/play_video_from_my_collection/play_video_from_my_collection.rb +43 -0
  123. data/lib/multimedia_paradise/gui/gtk2/simple_play_widget/README.md +12 -0
  124. data/lib/multimedia_paradise/gui/gtk2/simple_play_widget/simple_play_widget.rb +40 -0
  125. data/lib/multimedia_paradise/gui/gtk2/video_collection/video_collection.rb +56 -0
  126. data/lib/multimedia_paradise/gui/gtk2/widget_increase_or_decrease_audio/widget_increase_or_decrease_audio.rb +42 -0
  127. data/lib/multimedia_paradise/gui/gtk2/youtube_downloader/youtube_downloader.rb +32 -0
  128. data/lib/multimedia_paradise/gui/gtk3/change_metadata_widget/README.md +3 -0
  129. data/lib/multimedia_paradise/gui/gtk3/change_metadata_widget/change_metadata_widget.rb +150 -0
  130. data/lib/multimedia_paradise/gui/gtk3/cut_multimedia/cut_multimedia.rb +321 -0
  131. data/lib/multimedia_paradise/gui/gtk3/information_about_a_mp3_file/information_about_a_mp3_file.rb +421 -0
  132. data/lib/multimedia_paradise/gui/gtk3/lyrics/lyrics.rb +33 -0
  133. data/lib/multimedia_paradise/gui/gtk3/multimedia_converter/multimedia_converter.rb +34 -0
  134. data/lib/multimedia_paradise/gui/gtk3/multimedia_notebook/multimedia_notebook.rb +34 -0
  135. data/lib/multimedia_paradise/gui/gtk3/play_video_from_my_collection/play_video_from_my_collection.rb +34 -0
  136. data/lib/multimedia_paradise/gui/gtk3/playlist/playlist.rb +34 -0
  137. data/lib/multimedia_paradise/gui/gtk3/radio/misc.rb +487 -0
  138. data/lib/multimedia_paradise/gui/gtk3/radio/radio.rb +698 -0
  139. data/lib/multimedia_paradise/gui/gtk3/simple_play_widget/simple_play_widget.rb +38 -0
  140. data/lib/multimedia_paradise/gui/gtk3/sound_effect_widget/sound_effect_widget.rb +34 -0
  141. data/lib/multimedia_paradise/gui/gtk3/tag_mp3_files/connect_skeleton.rb +61 -0
  142. data/lib/multimedia_paradise/gui/gtk3/tag_mp3_files/create.rb +405 -0
  143. data/lib/multimedia_paradise/gui/gtk3/tag_mp3_files/misc.rb +1820 -0
  144. data/lib/multimedia_paradise/gui/gtk3/tag_mp3_files/tag_mp3_files.config +6 -0
  145. data/lib/multimedia_paradise/gui/gtk3/tag_mp3_files/tag_mp3_files.rb +66 -0
  146. data/lib/multimedia_paradise/gui/gtk3/video_collection/video_collection.rb +43 -0
  147. data/lib/multimedia_paradise/gui/gtk3/video_editor/video_editor.rb +34 -0
  148. data/lib/multimedia_paradise/gui/gtk3/video_player/video_player.rb +34 -0
  149. data/lib/multimedia_paradise/gui/gtk3/webcam_widget/webcam_widget.rb +425 -0
  150. data/lib/multimedia_paradise/gui/gtk3/widget_increase_or_decrease_audio/widget_increase_or_decrease_audio.rb +36 -0
  151. data/lib/multimedia_paradise/gui/gtk3/youtube_channels/youtube_channels.rb +210 -0
  152. data/lib/multimedia_paradise/gui/gtk3/youtube_downloader/youtube_downloader.rb +32 -0
  153. data/lib/multimedia_paradise/gui/gui_base.rb +92 -0
  154. data/lib/multimedia_paradise/gui/libui/change_metadata_widget/change_metadata_widget.rb +115 -0
  155. data/lib/multimedia_paradise/gui/libui/cut_multimedia/cut_multimedia.rb +119 -0
  156. data/lib/multimedia_paradise/gui/libui/lyrics/lyrics.rb +67 -0
  157. data/lib/multimedia_paradise/gui/libui/simple_play_widget/simple_play_widget.rb +119 -0
  158. data/lib/multimedia_paradise/gui/libui/tag_mp3_files/tag_mp3_files.rb +268 -0
  159. data/lib/multimedia_paradise/gui/libui/video_player/video_player.rb +81 -0
  160. data/lib/multimedia_paradise/gui/libui/widget_increase_or_decrease_audio/widget_increase_or_decrease_audio.rb +126 -0
  161. data/lib/multimedia_paradise/gui/libui/youtube_channels/youtube_channels.rb +116 -0
  162. data/lib/multimedia_paradise/gui/libui/youtube_downloader/youtube_downloader.rb +107 -0
  163. data/lib/multimedia_paradise/gui/shared_code/change_metadata_widget/change_metadata_widget_module.rb +538 -0
  164. data/lib/multimedia_paradise/gui/shared_code/cut_multimedia/cut_multimedia_module.rb +268 -0
  165. data/lib/multimedia_paradise/gui/shared_code/information_about_a_mp3_file/information_about_a_mp3_file_module.rb +120 -0
  166. data/lib/multimedia_paradise/gui/shared_code/lyrics/lyrics_module.rb +141 -0
  167. data/lib/multimedia_paradise/gui/shared_code/multimedia_converter/multimedia_converter_module.rb +478 -0
  168. data/lib/multimedia_paradise/gui/shared_code/multimedia_notebook/multimedia_notebook_module.rb +171 -0
  169. data/lib/multimedia_paradise/gui/shared_code/play_video_from_my_collection/play_video_from_my_collection_module.rb +464 -0
  170. data/lib/multimedia_paradise/gui/shared_code/playlist/playlist_module.rb +151 -0
  171. data/lib/multimedia_paradise/gui/shared_code/simple_play_widget/simple_play_widget_module.rb +257 -0
  172. data/lib/multimedia_paradise/gui/shared_code/sound_effect_widget/sound_effect_widget_module.rb +173 -0
  173. data/lib/multimedia_paradise/gui/shared_code/tag_mp3_files/tag_mp3_files_module.rb +73 -0
  174. data/lib/multimedia_paradise/gui/shared_code/video_editor/video_editor_module.rb +287 -0
  175. data/lib/multimedia_paradise/gui/shared_code/video_player/video_player_module.rb +185 -0
  176. data/lib/multimedia_paradise/gui/shared_code/widget_increase_or_decrease_audio/widget_increase_or_decrease_audio_module.rb +310 -0
  177. data/lib/multimedia_paradise/gui/shared_code/youtube_downloader/youtube_downloader_module.rb +339 -0
  178. data/lib/multimedia_paradise/gui/tk/tk_multimedia_wrapper.rb +60 -0
  179. data/lib/multimedia_paradise/help/help.rb +75 -0
  180. data/lib/multimedia_paradise/images/MULTIMEDIA.jpg +0 -0
  181. data/lib/multimedia_paradise/images/MULTIMEDIA_PARADISE_ID_TAG_GUI_IN_RUBY_GTK3.png +0 -0
  182. data/lib/multimedia_paradise/images/MULTIMEDIA_PARADISE_LOGO.png +0 -0
  183. data/lib/multimedia_paradise/images/UK_flag.png +0 -0
  184. data/lib/multimedia_paradise/images/US_flag.png +0 -0
  185. data/lib/multimedia_paradise/images/austrian_flag.png +0 -0
  186. data/lib/multimedia_paradise/images/french_flag.png +0 -0
  187. data/lib/multimedia_paradise/images/german_flag.png +0 -0
  188. data/lib/multimedia_paradise/images/radio_image.png +0 -0
  189. data/lib/multimedia_paradise/images/trance.png +0 -0
  190. data/lib/multimedia_paradise/java/AudioPlayer.class +0 -0
  191. data/lib/multimedia_paradise/java/AudioPlayer.java +103 -0
  192. data/lib/multimedia_paradise/java/README.md +3 -0
  193. data/lib/multimedia_paradise/misc/long_format_to_milliseconds_converter.rb +182 -0
  194. data/lib/multimedia_paradise/misc/milliseconds_to_long_format_converter.rb +186 -0
  195. data/lib/multimedia_paradise/multimedia/analyse_multimedia_file.rb +180 -0
  196. data/lib/multimedia_paradise/multimedia/avisynth/README.md +4 -0
  197. data/lib/multimedia_paradise/multimedia/avisynth/avisynth_code.avs +471 -0
  198. data/lib/multimedia_paradise/multimedia/base.rb +60 -0
  199. data/lib/multimedia_paradise/multimedia/chord.rb +174 -0
  200. data/lib/multimedia_paradise/multimedia/convert_audio_to_video_with_image.rb +171 -0
  201. data/lib/multimedia_paradise/multimedia/cut_multimedia/10_minutes_chop.rb +29 -0
  202. data/lib/multimedia_paradise/multimedia/cut_multimedia/15_minutes_chop.rb +29 -0
  203. data/lib/multimedia_paradise/multimedia/cut_multimedia/30_minutes_chop.rb +29 -0
  204. data/lib/multimedia_paradise/multimedia/cut_multimedia/5_minutes_chop.rb +29 -0
  205. data/lib/multimedia_paradise/multimedia/cut_multimedia/cut_multimedia.rb +2017 -0
  206. data/lib/multimedia_paradise/multimedia/cut_multimedia/evaluate_from_this_file.rb +79 -0
  207. data/lib/multimedia_paradise/multimedia/cut_multimedia/interactive_menu.rb +514 -0
  208. data/lib/multimedia_paradise/multimedia/interactive_shell.rb +84 -0
  209. data/lib/multimedia_paradise/multimedia/merge_multimedia.rb +125 -0
  210. data/lib/multimedia_paradise/multimedia/note.rb +500 -0
  211. data/lib/multimedia_paradise/multimedia/play_from_this_list.rb +163 -0
  212. data/lib/multimedia_paradise/multimedia/read_meta_tags.rb +173 -0
  213. data/lib/multimedia_paradise/multimedia/simulate_youtube_playlist.rb +209 -0
  214. data/lib/multimedia_paradise/multimedia/start_length_duration.rb +205 -0
  215. data/lib/multimedia_paradise/multimedia/video_downloader/video_downloader.rb +143 -0
  216. data/lib/multimedia_paradise/project/project.rb +47 -0
  217. data/lib/multimedia_paradise/requires/require_audio_files.rb +74 -0
  218. data/lib/multimedia_paradise/requires/require_cut_multimedia.rb +7 -0
  219. data/lib/multimedia_paradise/requires/require_extract_audio.rb +7 -0
  220. data/lib/multimedia_paradise/requires/require_file_duration.rb +7 -0
  221. data/lib/multimedia_paradise/requires/require_streamripper.rb +7 -0
  222. data/lib/multimedia_paradise/requires/require_the_audio_player.rb +7 -0
  223. data/lib/multimedia_paradise/requires/require_the_multimedia_paradise_project.rb +38 -0
  224. data/lib/multimedia_paradise/requires/require_the_sinatra_components.rb +7 -0
  225. data/lib/multimedia_paradise/requires/require_toplevel_methods_files.rb +25 -0
  226. data/lib/multimedia_paradise/requires/require_video_files.rb +25 -0
  227. data/lib/multimedia_paradise/requires/require_video_player.rb +7 -0
  228. data/lib/multimedia_paradise/sinatra/app.rb +311 -0
  229. data/lib/multimedia_paradise/sinatra/embeddable_interface.rb +379 -0
  230. data/lib/multimedia_paradise/sound_effects/README.md +12 -0
  231. data/lib/multimedia_paradise/sound_effects/cat_meow.mp3 +0 -0
  232. data/lib/multimedia_paradise/sound_effects/channel_opened.mp3 +0 -0
  233. data/lib/multimedia_paradise/sound_effects/phone_ring.mp3 +0 -0
  234. data/lib/multimedia_paradise/statistics/README.md +5 -0
  235. data/lib/multimedia_paradise/statistics/video.rb +84 -0
  236. data/lib/multimedia_paradise/toplevel_cut_audio.rb +16 -0
  237. data/lib/multimedia_paradise/toplevel_methods/analyze_audio_stream.rb +31 -0
  238. data/lib/multimedia_paradise/toplevel_methods/chop_into_segments_of_n_seconds_size.rb +32 -0
  239. data/lib/multimedia_paradise/toplevel_methods/chop_off_first_five_minutes.rb +22 -0
  240. data/lib/multimedia_paradise/toplevel_methods/chop_off_first_n_seconds.rb +92 -0
  241. data/lib/multimedia_paradise/toplevel_methods/chop_off_first_ten_minutes.rb +22 -0
  242. data/lib/multimedia_paradise/toplevel_methods/chop_off_first_two_minutes.rb +24 -0
  243. data/lib/multimedia_paradise/toplevel_methods/codecs.rb +50 -0
  244. data/lib/multimedia_paradise/toplevel_methods/copy_and_merge_this_video_n_times.rb +51 -0
  245. data/lib/multimedia_paradise/toplevel_methods/copy_file.rb +18 -0
  246. data/lib/multimedia_paradise/toplevel_methods/create_video_from_this_audio.rb +65 -0
  247. data/lib/multimedia_paradise/toplevel_methods/cut_from_to.rb +156 -0
  248. data/lib/multimedia_paradise/toplevel_methods/delay_audio.rb +31 -0
  249. data/lib/multimedia_paradise/toplevel_methods/denoise.rb +90 -0
  250. data/lib/multimedia_paradise/toplevel_methods/deshake.rb +43 -0
  251. data/lib/multimedia_paradise/toplevel_methods/e.rb +16 -0
  252. data/lib/multimedia_paradise/toplevel_methods/encode_this_video.rb +49 -0
  253. data/lib/multimedia_paradise/toplevel_methods/ensure_that_the_output_directory_exists.rb +27 -0
  254. data/lib/multimedia_paradise/toplevel_methods/esystem.rb +43 -0
  255. data/lib/multimedia_paradise/toplevel_methods/files_and_directories.rb +90 -0
  256. data/lib/multimedia_paradise/toplevel_methods/flip_and_rotate.rb +58 -0
  257. data/lib/multimedia_paradise/toplevel_methods/increase_volume_of_this_audio_file.rb +61 -0
  258. data/lib/multimedia_paradise/toplevel_methods/is_a_multimedia_file.rb +27 -0
  259. data/lib/multimedia_paradise/toplevel_methods/is_audio_file.rb +27 -0
  260. data/lib/multimedia_paradise/toplevel_methods/is_image_file.rb +31 -0
  261. data/lib/multimedia_paradise/toplevel_methods/is_on_roebe.rb +17 -0
  262. data/lib/multimedia_paradise/toplevel_methods/is_video_file.rb +62 -0
  263. data/lib/multimedia_paradise/toplevel_methods/merge_multimedia_file.rb +327 -0
  264. data/lib/multimedia_paradise/toplevel_methods/merge_these_videos.rb +105 -0
  265. data/lib/multimedia_paradise/toplevel_methods/misc.rb +885 -0
  266. data/lib/multimedia_paradise/toplevel_methods/n_local_videos.rb +56 -0
  267. data/lib/multimedia_paradise/toplevel_methods/opn.rb +24 -0
  268. data/lib/multimedia_paradise/toplevel_methods/output_directory.rb +59 -0
  269. data/lib/multimedia_paradise/toplevel_methods/player_in_use.rb +80 -0
  270. data/lib/multimedia_paradise/toplevel_methods/query_the_audio_codec_of_this_file.rb +24 -0
  271. data/lib/multimedia_paradise/toplevel_methods/radio.rb +360 -0
  272. data/lib/multimedia_paradise/toplevel_methods/rds.rb +24 -0
  273. data/lib/multimedia_paradise/toplevel_methods/return_all_video_files.rb +64 -0
  274. data/lib/multimedia_paradise/toplevel_methods/return_data_from_video_collection_file_for_this_entry.rb +38 -0
  275. data/lib/multimedia_paradise/toplevel_methods/return_duration_of_this_multimedia_file.rb +27 -0
  276. data/lib/multimedia_paradise/toplevel_methods/return_full_name_for_video_at_this_position.rb +54 -0
  277. data/lib/multimedia_paradise/toplevel_methods/return_path_to_random_simpsons_video_file.rb +43 -0
  278. data/lib/multimedia_paradise/toplevel_methods/return_random_video_file_from_the_video_collection.rb +73 -0
  279. data/lib/multimedia_paradise/toplevel_methods/return_screen_resolution.rb +24 -0
  280. data/lib/multimedia_paradise/toplevel_methods/run_sys_command.rb +30 -0
  281. data/lib/multimedia_paradise/toplevel_methods/scale_video.rb +27 -0
  282. data/lib/multimedia_paradise/toplevel_methods/set_title_of.rb +65 -0
  283. data/lib/multimedia_paradise/toplevel_methods/slow_down_this_video_file.rb +33 -0
  284. data/lib/multimedia_paradise/toplevel_methods/start_screencast.rb +70 -0
  285. data/lib/multimedia_paradise/toplevel_methods/subtitles.rb +59 -0
  286. data/lib/multimedia_paradise/toplevel_methods/to_flac.rb +30 -0
  287. data/lib/multimedia_paradise/toplevel_methods/to_mp4.rb +24 -0
  288. data/lib/multimedia_paradise/toplevel_methods/total_duration.rb +35 -0
  289. data/lib/multimedia_paradise/toplevel_methods/use_lame_codec.rb +32 -0
  290. data/lib/multimedia_paradise/toplevel_methods/video_dataset.rb +76 -0
  291. data/lib/multimedia_paradise/version/version.rb +28 -0
  292. data/lib/multimedia_paradise/video/all_videos.rb +101 -0
  293. data/lib/multimedia_paradise/video/capture_screen.rb +285 -0
  294. data/lib/multimedia_paradise/video/check_numbers.rb +215 -0
  295. data/lib/multimedia_paradise/video/columbo/columbo.rb +139 -0
  296. data/lib/multimedia_paradise/video/copy_missing_video_files.rb +293 -0
  297. data/lib/multimedia_paradise/video/copy_random_video.rb +98 -0
  298. data/lib/multimedia_paradise/video/correct_video_numbers.rb +278 -0
  299. data/lib/multimedia_paradise/video/create_dvd.rb +50 -0
  300. data/lib/multimedia_paradise/video/encode_video.rb +81 -0
  301. data/lib/multimedia_paradise/video/ffmpeg_options.rb +156 -0
  302. data/lib/multimedia_paradise/video/find_video/constants.rb +23 -0
  303. data/lib/multimedia_paradise/video/find_video/find_video.rb +493 -0
  304. data/lib/multimedia_paradise/video/fix_married_with_children_videos.rb +70 -0
  305. data/lib/multimedia_paradise/video/guess_video_name.rb +189 -0
  306. data/lib/multimedia_paradise/video/imdb_rating/imdb_rating.rb +141 -0
  307. data/lib/multimedia_paradise/video/mike_hammer/mike_hammer.rb +74 -0
  308. data/lib/multimedia_paradise/video/missing_video_files/missing_video_files.rb +286 -0
  309. data/lib/multimedia_paradise/video/movie_searcher.rb +281 -0
  310. data/lib/multimedia_paradise/video/mplayer_wrapper.rb +504 -0
  311. data/lib/multimedia_paradise/video/play_random_file.rb +91 -0
  312. data/lib/multimedia_paradise/video/play_random_realvideo.rb +87 -0
  313. data/lib/multimedia_paradise/video/prepare_video_lecture.rb +272 -0
  314. data/lib/multimedia_paradise/video/random_video.rb +310 -0
  315. data/lib/multimedia_paradise/video/registered_video_file.rb +131 -0
  316. data/lib/multimedia_paradise/video/remove_metadata.rb +52 -0
  317. data/lib/multimedia_paradise/video/rename_video_file.rb +149 -0
  318. data/lib/multimedia_paradise/video/report_local_videos.rb +106 -0
  319. data/lib/multimedia_paradise/video/report_missing_videos_in_the_yaml_file.rb +107 -0
  320. data/lib/multimedia_paradise/video/resolution.rb +159 -0
  321. data/lib/multimedia_paradise/video/simpsons.rb +129 -0
  322. data/lib/multimedia_paradise/video/speed_up_video.rb +135 -0
  323. data/lib/multimedia_paradise/video/split_this_video.rb +126 -0
  324. data/lib/multimedia_paradise/video/srt_regex.rb +211 -0
  325. data/lib/multimedia_paradise/video/store_available_video_files.rb +138 -0
  326. data/lib/multimedia_paradise/video/the_simpsons/README.md +9 -0
  327. data/lib/multimedia_paradise/video/the_simpsons/good_the_simpsons_episodes.rb +107 -0
  328. data/lib/multimedia_paradise/video/the_simpsons/the_simpsons.rb +82 -0
  329. data/lib/multimedia_paradise/video/video.rb +14 -0
  330. data/lib/multimedia_paradise/video/video_encoding_settings.rb +57 -0
  331. data/lib/multimedia_paradise/video/video_genres.rb +337 -0
  332. data/lib/multimedia_paradise/video/video_information.rb +443 -0
  333. data/lib/multimedia_paradise/video/video_metadata.rb +132 -0
  334. data/lib/multimedia_paradise/video/video_player.rb +581 -0
  335. data/lib/multimedia_paradise/video/video_renamer.rb +160 -0
  336. data/lib/multimedia_paradise/video/watermark.rb +290 -0
  337. data/lib/multimedia_paradise/video/youtube/youtube.rb +17 -0
  338. data/lib/multimedia_paradise/video/youtube_embedder.rb +235 -0
  339. data/lib/multimedia_paradise/www/GIS/GIS.cgi +147 -0
  340. data/lib/multimedia_paradise/www/HDMI/HDMI.cgi +34 -0
  341. data/lib/multimedia_paradise/www/TALES_FROM_THE_CRYPT.html +71 -0
  342. data/lib/multimedia_paradise/www/alsa/alsa.cgi +7 -0
  343. data/lib/multimedia_paradise/www/alsa/alsa.rb +309 -0
  344. data/lib/multimedia_paradise/www/alsa/alsa.sinatra +56 -0
  345. data/lib/multimedia_paradise/www/audacity.cgi +30 -0
  346. data/lib/multimedia_paradise/www/audio/audio.cgi +9 -0
  347. data/lib/multimedia_paradise/www/audio/audio.rb +2739 -0
  348. data/lib/multimedia_paradise/www/audio/audio.sinatra +56 -0
  349. data/lib/multimedia_paradise/www/avisynth/avisynth.cgi +172 -0
  350. data/lib/multimedia_paradise/www/best_voices/best_voices.cgi +60 -0
  351. data/lib/multimedia_paradise/www/cassette/cassette.cgi +723 -0
  352. data/lib/multimedia_paradise/www/codecs/codecs.cgi +95 -0
  353. data/lib/multimedia_paradise/www/componists/vivaldi.cgi +218 -0
  354. data/lib/multimedia_paradise/www/decibel.cgi +79 -0
  355. data/lib/multimedia_paradise/www/ffmpeg/ffmpeg.cgi +439 -0
  356. data/lib/multimedia_paradise/www/lame/lame.cgi +7 -0
  357. data/lib/multimedia_paradise/www/lame/lame.rb +101 -0
  358. data/lib/multimedia_paradise/www/lame/lame.sinatra +56 -0
  359. data/lib/multimedia_paradise/www/lilypond.cgi +96 -0
  360. data/lib/multimedia_paradise/www/lyrics/lyrics.cgi +49 -0
  361. data/lib/multimedia_paradise/www/midi/al_adagi.mid +0 -0
  362. data/lib/multimedia_paradise/www/play_songs.cgi +102 -0
  363. data/lib/multimedia_paradise/www/play_this_video_file.cgi +100 -0
  364. data/lib/multimedia_paradise/www/pulseaudio/pulseaudio.cgi +7 -0
  365. data/lib/multimedia_paradise/www/pulseaudio/pulseaudio.rb +168 -0
  366. data/lib/multimedia_paradise/www/pulseaudio/pulseaudio.sinatra +56 -0
  367. data/lib/multimedia_paradise/www/rhythmbox/rhythmbox.cgi +120 -0
  368. data/lib/multimedia_paradise/www/sound_theory.cgi +163 -0
  369. data/lib/multimedia_paradise/www/tv/tv.cgi +182 -0
  370. data/lib/multimedia_paradise/www/video/video.cgi +7 -0
  371. data/lib/multimedia_paradise/www/video/video.rb +7709 -0
  372. data/lib/multimedia_paradise/www/video/video.sinatra +52 -0
  373. data/lib/multimedia_paradise/www/web_streams.cgi +58 -0
  374. data/lib/multimedia_paradise/yaml/audio_formats.yml +14 -0
  375. data/lib/multimedia_paradise/yaml/best_songs_in_an_era/eurodance/top20.yml +28 -0
  376. data/lib/multimedia_paradise/yaml/game_shows/ruck_zuck/ruck_zuck.yml +25 -0
  377. data/lib/multimedia_paradise/yaml/genres/1980s.yml +198 -0
  378. data/lib/multimedia_paradise/yaml/genres/README.md +5 -0
  379. data/lib/multimedia_paradise/yaml/genres/boogie.yml +68 -0
  380. data/lib/multimedia_paradise/yaml/genres/concerts.yml +29 -0
  381. data/lib/multimedia_paradise/yaml/genres/eurodance.yml +456 -0
  382. data/lib/multimedia_paradise/yaml/genres/hip_hop.yml +49 -0
  383. data/lib/multimedia_paradise/yaml/genres/italian_songs.yml +53 -0
  384. data/lib/multimedia_paradise/yaml/genres/trance.yml +167 -0
  385. data/lib/multimedia_paradise/yaml/good_horror_movies/good_horror_movies.yml +12 -0
  386. data/lib/multimedia_paradise/yaml/good_movie_actors/good_movie_actors.yml +6 -0
  387. data/lib/multimedia_paradise/yaml/image_formats.yml +8 -0
  388. data/lib/multimedia_paradise/yaml/internal/README.md +2 -0
  389. data/lib/multimedia_paradise/yaml/internal/installed_binaries.yml +31 -0
  390. data/lib/multimedia_paradise/yaml/lyrics.yml +6275 -0
  391. data/lib/multimedia_paradise/yaml/movie_reviews/the_hateful_eight_september_2016.md +305 -0
  392. data/lib/multimedia_paradise/yaml/music_genres.yml +51 -0
  393. data/lib/multimedia_paradise/yaml/playlist.yml +127 -0
  394. data/lib/multimedia_paradise/yaml/radio/README.md +5 -0
  395. data/lib/multimedia_paradise/yaml/radio/radio_stations.yml +359 -0
  396. data/lib/multimedia_paradise/yaml/song_tags.yml +815 -0
  397. data/lib/multimedia_paradise/yaml/tales_from_the_crypt/tales_from_the_crypt.yml +418 -0
  398. data/lib/multimedia_paradise/yaml/tom_and_jerry/README.md +2 -0
  399. data/lib/multimedia_paradise/yaml/tom_and_jerry/tom_and_jerry_episodes.yml +27 -0
  400. data/lib/multimedia_paradise/yaml/tv_channels/tv_channels.yml +46 -0
  401. data/lib/multimedia_paradise/yaml/use_this_video_player.yml +1 -0
  402. data/lib/multimedia_paradise/yaml/video/video.yml +26 -0
  403. data/lib/multimedia_paradise/yaml/video_collection/video_collection.yml +1933 -0
  404. data/lib/multimedia_paradise/yaml/video_encoding_settings.yml +62 -0
  405. data/lib/multimedia_paradise/yaml/video_filter_aliases.yml +221 -0
  406. data/lib/multimedia_paradise/yaml/youtube/alltagsgeschichte/alltagsgeschichte.yml +172 -0
  407. data/lib/multimedia_paradise/yaml/youtube/songs/README.md +3 -0
  408. data/lib/multimedia_paradise/yaml/youtube/songs/songs.yml +6 -0
  409. data/lib/multimedia_paradise/yaml/youtube_playlist/youtube_playlist.yml +6 -0
  410. data/lib/multimedia_paradise.rb +5 -0
  411. data/multimedia_paradise.gemspec +76 -0
  412. data/test/testing_audio_player.rb +15 -0
  413. data/test/testing_ffmpeg_options.rb +14 -0
  414. data/test/testing_file_duration.rb +17 -0
  415. data/test/testing_modify_year_of_audio_file.rb +14 -0
  416. data/test/testing_multimedia_paradise_project.rb +151 -0
  417. metadata +581 -0
@@ -0,0 +1,1820 @@
1
+ #!/usr/bin/ruby -w
2
+ # Encoding: UTF-8
3
+ # frozen_string_literal: true
4
+ # =========================================================================== #
5
+ # require 'multimedia_paradise/gui/gtk3/tag_mp3_files/misc.rb'
6
+ # =========================================================================== #
7
+ module MultimediaParadise
8
+
9
+ module GUI
10
+
11
+ module Gtk
12
+
13
+ class TagMp3Files < ::Gtk::Box # === MultimediaParadise::GUI::Gtk::TagMp3Files
14
+
15
+ # ========================================================================= #
16
+ # === initialize
17
+ # ========================================================================= #
18
+ def initialize(
19
+ commandline_arguments = ARGV,
20
+ run_already = true
21
+ )
22
+ super(:vertical)
23
+ reset
24
+ set_commandline_arguments(
25
+ commandline_arguments
26
+ )
27
+ run if run_already
28
+ end
29
+
30
+ # ========================================================================= #
31
+ # === reset (reset tag)
32
+ # ========================================================================= #
33
+ def reset
34
+ reset_the_internal_variables
35
+ infer_the_namespace
36
+ # ======================================================================= #
37
+ # === @configuration
38
+ # ======================================================================= #
39
+ @configuration = [true, __dir__, namespace?]
40
+ title_width_height_font(TITLE, WIDTH, HEIGHT, USE_THIS_FONT)
41
+ infer_the_size_automatically
42
+ handle_CSS_rules # Should be called from the reset() method.
43
+ # ======================================================================= #
44
+ # === @information_about_a_mp3_file
45
+ # ======================================================================= #
46
+ @information_about_a_mp3_file = return_widget_information_about_a_mp3_file
47
+ # ======================================================================= #
48
+ # === @metadata_for_the_song
49
+ #
50
+ # This variable will change when the metadata of a song is analysed.
51
+ # It will contain the dataset of that song, including the audio
52
+ # tags, at a later point - whenever a .mp3 file is analysed.
53
+ # ======================================================================= #
54
+ @metadata_for_the_song = nil
55
+ require_the_appropriate_id_tagger
56
+ end
57
+
58
+ # ========================================================================= #
59
+ # === require_the_appropriate_id_tagger
60
+ #
61
+ # This method will load the correct id-tagger for .mp3 files. We need
62
+ # to make this flexible, in the event that the user wants to use
63
+ # another id-tagger rather than the "default" one.
64
+ # ========================================================================= #
65
+ def require_the_appropriate_id_tagger(
66
+ i = ID_TAGGER_TO_USE_FOR_THE_MP3_FILES
67
+ )
68
+ case i
69
+ # ======================================================================= #
70
+ # === :taglib
71
+ #
72
+ # Note that since as of the year 2021, taglib is the default id3-tagger
73
+ # that will be used by this application, thus replacing the older
74
+ # id3lib code. The latter is still retained, though, in the event
75
+ # we may have to switch again one day. But in my opinion taglib is
76
+ # actually better than idlib.
77
+ # ======================================================================= #
78
+ when :taglib
79
+ begin
80
+ require 'taglib'
81
+ rescue LoadError
82
+ e "the taglib gem is not available. Please install it."
83
+ e
84
+ e ' gem install taglib-ruby # The github-page is at: '\
85
+ 'https://github.com/robinst/taglib-ruby'
86
+ e
87
+ if is_on_roebe?
88
+ e 'As we are on roebe we will install the gem next.'
89
+ e
90
+ system 'gem install taglib-ruby'
91
+ e
92
+ begin
93
+ require 'taglib'
94
+ rescue LoadError; end
95
+ end
96
+ end
97
+ # ======================================================================= #
98
+ # === when :idlib
99
+ # ======================================================================= #
100
+ when :idlib
101
+ begin
102
+ require 'id3lib'
103
+ rescue LoadError
104
+ e "ruby-id3lib not available. Please install it."
105
+ e
106
+ e ' gem install id3lib-ruby'
107
+ e
108
+ end
109
+ else
110
+ e "Unknown ID-tagger #{i}"
111
+ end
112
+ end
113
+
114
+ # ========================================================================= #
115
+ # === padding?
116
+ # ========================================================================= #
117
+ def padding?
118
+ 4
119
+ end
120
+
121
+ # ========================================================================= #
122
+ # === border_size?
123
+ # ========================================================================= #
124
+ def border_size?
125
+ 2
126
+ end
127
+
128
+ # ========================================================================= #
129
+ # === header_bar?
130
+ # ========================================================================= #
131
+ def header_bar?
132
+ @header_bar
133
+ end; alias header? header_bar? # === header?
134
+
135
+ # ========================================================================= #
136
+ # === do_focus_on_the_entry_containing_the_title_of_the_song
137
+ # ========================================================================= #
138
+ def do_focus_on_the_entry_containing_the_title_of_the_song
139
+ @entry_for_the_title_of_the_song.do_focus
140
+ end
141
+
142
+ # ========================================================================= #
143
+ # === return_all_entries_on_the_right_side_widget
144
+ # ========================================================================= #
145
+ def return_all_entries_on_the_right_side_widget
146
+ [ # Let's keep them ordered how we want to display them.
147
+ @entry_for_the_artist,
148
+ @entry_for_the_year,
149
+ @entry_for_the_album,
150
+ @entry_for_the_comment,
151
+ @entry_for_the_track_number,
152
+ @entry_for_the_genre,
153
+ @entry_for_the_title_of_the_song
154
+ ]
155
+ end
156
+
157
+ # ========================================================================= #
158
+ # === reset_all_main_entries
159
+ # ========================================================================= #
160
+ def reset_all_main_entries
161
+ @entry_for_the_title_of_the_song.set_text('')
162
+ @entry_for_the_year.set_text('')
163
+ @entry_for_the_artist.set_text('')
164
+ @entry_for_the_genre.set_text('')
165
+ @entry_for_the_comment.set_text('')
166
+ end
167
+
168
+ # ========================================================================= #
169
+ # === song_name?
170
+ # ========================================================================= #
171
+ def song_name?
172
+ @entry_for_the_title_of_the_song.text?
173
+ end
174
+
175
+ # ========================================================================= #
176
+ # === sync_artist_onto_entry
177
+ # ========================================================================= #
178
+ def sync_artist_onto_entry
179
+ if metadata?
180
+ @entry_for_the_artist.set_text(metadata?.artist.to_s)
181
+ end
182
+ end
183
+
184
+ # ========================================================================= #
185
+ # === sync_year_onto_entry
186
+ # ========================================================================= #
187
+ def sync_year_onto_entry
188
+ dataset = dataset?
189
+ if dataset
190
+ @entry_for_the_year.set_text(dataset.year.to_s)
191
+ end
192
+ end
193
+
194
+ # ========================================================================= #
195
+ # === do_empty_the_tags
196
+ #
197
+ # This method will empty our tags.
198
+ # ========================================================================= #
199
+ def do_empty_the_tags
200
+ dataset = dataset?
201
+ if dataset
202
+ dataset.album = ''
203
+ dataset.artist = ''
204
+ dataset.comment = ''
205
+ dataset.genre = ''
206
+ dataset.title = ''
207
+ dataset.track = ''
208
+ dataset.year = ''
209
+ @button_save.sensitive = true
210
+ end
211
+ end; alias empty_tags do_empty_the_tags # === empty_tags
212
+
213
+ # ========================================================================= #
214
+ # === artist?
215
+ # ========================================================================= #
216
+ def artist?
217
+ @entry_for_the_artist.text?
218
+ end
219
+
220
+ # ========================================================================= #
221
+ # === show_debug_information
222
+ #
223
+ # This method can be used to show some debug-related information.
224
+ # ========================================================================= #
225
+ def show_debug_information
226
+ e
227
+ e '@width and @height are: '+
228
+ @width.to_s+', '+
229
+ @height.to_s
230
+ e
231
+ end
232
+
233
+ # ========================================================================= #
234
+ # === parent_widget=
235
+ # ========================================================================= #
236
+ def parent_widget=(i = ARGV)
237
+ i = i.first if i.is_a? Array
238
+ @parent_widget = i
239
+ end
240
+
241
+ # ========================================================================= #
242
+ # === menu (menu tag)
243
+ #
244
+ # The most important aspect for menu() is to allow the user to load
245
+ # up a specific .mp3 file, on startup of this application.
246
+ #
247
+ # Usage example for this on my home system:
248
+ #
249
+ # tag_mp3_files /home/x/songs/Womack_and_Womack_Teardrops.mp3
250
+ # gtkidrenamer /home/x/songs/2Pac_GhettoGospel.mp3
251
+ #
252
+ # ========================================================================= #
253
+ def menu(
254
+ i = commandline_arguments?
255
+ )
256
+ if i and i.is_a?(Array)
257
+ i.each {|entry| menu(entry) }
258
+ else
259
+ unless i.start_with?('--')
260
+ _ = i.to_s
261
+ _ = File.expand_path(i).to_s.delete('-')
262
+ @entry_file_path.set_text(_)
263
+ if File.exist? _ # Safeguard.
264
+ do_analyse_the_default_file
265
+ set_all_relevant_entries_based_on_the_metadata
266
+ end
267
+ end
268
+ end
269
+ end; alias parse_the_commandline_arguments menu # === parse_the_commandline_arguments
270
+
271
+ # ========================================================================= #
272
+ # === return_entry_from_the_combo_box_entry_for_genre_select_or_from_the_entry_for_the_genre
273
+ # ========================================================================= #
274
+ def return_entry_from_the_combo_box_entry_for_genre_select_or_from_the_entry_for_the_genre
275
+ _ = @combo_box_entry_for_genre_select.active_text
276
+ unless @entry_for_the_genre.text.to_s.empty?
277
+ _ = @entry_for_the_genre.text.to_s
278
+ end
279
+ return _
280
+ end
281
+
282
+ # ========================================================================= #
283
+ # === do_perform_a_google_search
284
+ #
285
+ # This method will "perform" a browser search. We will simply open
286
+ # the browser; on linux this works fine. :-)
287
+ # ========================================================================= #
288
+ def do_perform_a_google_search(
289
+ song_name = song_name?,
290
+ artist_name = artist?
291
+ )
292
+ unless Object.const_defined? :Open
293
+ begin
294
+ require 'open'
295
+ rescue LoadError; end
296
+ end
297
+ _ = ''.dup
298
+ _ << 'https://www.google.com/search?q='
299
+ _ << 'wikipedia+' # Preface with "wikipedia".
300
+ _ << song_name.to_s.tr(' ','+')+'+'
301
+ _ << artist_name.to_s.tr(' ','+')
302
+ _ << '&ie=utf-8&oe=utf-8'
303
+ Open.in_browser(_)
304
+ end
305
+
306
+ # ========================================================================= #
307
+ # === add_this_text_to_the_status_bar
308
+ # ========================================================================= #
309
+ def add_this_text_to_the_status_bar(this_text)
310
+ @status_bar.push(
311
+ @status_bar_context_id, this_text
312
+ )
313
+ end
314
+
315
+ # ========================================================================= #
316
+ # === return_random_audio_file
317
+ #
318
+ # This method can be used to return a random audio file from a given
319
+ # (local) directory. This will only work, evidently, when the directory
320
+ # contains audio files.
321
+ # ========================================================================= #
322
+ def return_random_audio_file(
323
+ from_this_directory =
324
+ @entry_use_this_as_the_directory_to_the_local_songs.text?
325
+ )
326
+ if File.directory? from_this_directory.delete('*')
327
+ _ = from_this_directory.delete('*')+'*'
328
+ this_file = Dir[_].select {|entry|
329
+ entry.end_with?('.mp3')
330
+ }.sample
331
+ return this_file
332
+ end
333
+ return nil
334
+ end
335
+
336
+ # ========================================================================= #
337
+ # === return_the_save_button
338
+ # ========================================================================= #
339
+ def return_the_save_button(
340
+ make_use_of_special_CSS_rules = true
341
+ )
342
+ case make_use_of_special_CSS_rules
343
+ # ======================================================================= #
344
+ # === :do_not_make_use_of_a_special_CSS_class
345
+ # ======================================================================= #
346
+ when :do_not_make_use_of_a_special_CSS_class
347
+ make_use_of_special_CSS_rules = false
348
+ end
349
+ button_save = gtk_button_with_label(' _Save', use_underline: true) # (:save) # (save tag)
350
+ use_this_icon_name = 'folder-download'
351
+ icon = load_icon(use_this_icon_name, 32, 0) # Use the window-close example.
352
+ button_save.set_image(icon)
353
+ button_save.set_border_width(1)
354
+ button_save.set_size_request(125, 68)
355
+ button_save.set_always_show_image(true)
356
+ if make_use_of_special_CSS_rules
357
+ button_save.css_class('save_button')
358
+ end
359
+ button_save.hint = 'Click this button in order to <b>save</b> the id3 '\
360
+ 'tags into the .mp3 file at hand.'
361
+ button_save.on_clicked {
362
+ do_save_tags
363
+ }
364
+ return button_save
365
+ end
366
+
367
+ # ========================================================================= #
368
+ # === widget_in_the_middle
369
+ # ========================================================================= #
370
+ def widget_in_the_middle
371
+ @information_about_a_mp3_file
372
+ end
373
+
374
+ # ========================================================================= #
375
+ # === return_button_play
376
+ # ========================================================================= #
377
+ def return_button_play
378
+ button_play = gtk_button_with_label(' _Play')
379
+ use_this_icon_name = 'video-x-generic-symbolic.symbolic'
380
+ icon = load_icon(use_this_icon_name, 32, 0) # Use the video-x-generic button.
381
+ button_play.set_image(icon)
382
+ button_play.set_always_show_image(true)
383
+ button_play.set_border_width(1)
384
+ button_play.set_size_request(120, 65)
385
+ button_play.lightgreen
386
+ button_play.hint =
387
+ 'Click this button in order to <b>play</b> the selected song. '\
388
+ 'Make sure to select a .mp3 file that exists locally as well.'
389
+ button_play.on_clicked {
390
+ do_play_the_selected_song
391
+ }
392
+ return button_play
393
+ end
394
+
395
+ # ========================================================================= #
396
+ # === MultimediaParadise::GUI::Gtk::TagMp3Files[]
397
+ # ========================================================================= #
398
+ def self.[](i = ARGV)
399
+ new(i)
400
+ end
401
+
402
+ # ========================================================================= #
403
+ # === MultimediaParadise::GUI::Gtk::TagMp3Files.run
404
+ # ========================================================================= #
405
+ def self.run(
406
+ i = ARGV
407
+ )require 'gtk_paradise/app/app'
408
+ tag_mp3_files = ::MultimediaParadise::GUI::Gtk::TagMp3Files.new(i)
409
+ r = ::Gtk.app
410
+ r << tag_mp3_files
411
+ r.on_button_press_event { |widget, event|
412
+ if ::Gtk.right_mouse_click?(event) # right mouse click event.
413
+ tag_mp3_files.context_menu?.popup_based_on_this_event(event)
414
+ end
415
+ }
416
+ tag_mp3_files.parent_widget = r
417
+ r.automatic_size_then_automatic_title
418
+ r.top_left_then_run
419
+ end; self.instance_eval { alias run_the_gtk_widget run } # === MultimediaParadise::GUI::Gtk::IdRenamerModule.run_the_gtk_widget
420
+
421
+ # ========================================================================= #
422
+ # === widget_second_row
423
+ #
424
+ # This widget contains the "File path: " string.
425
+ # ========================================================================= #
426
+ def widget_second_row
427
+ _ = gtk_hbox
428
+ _.pad2px
429
+ # ======================================================================= #
430
+ # === The label containing "Input the path to a local .mp3 file: "
431
+ # ======================================================================= #
432
+ label = label('File path: ')
433
+ label.align_to_the_left
434
+ label.hint = 'To the right of this text you can designate the '\
435
+ 'path to the local .mp3 file.'
436
+ _.minimal(label, 6)
437
+ eventbox_arrow_right = gtk_eventbox(emoji(:arrow_right))
438
+ eventbox_arrow_right.on_clicked {
439
+ do_open_a_local_file_and_then_set_the_proper_entry
440
+ }
441
+ _.minimal(eventbox_arrow_right, 2)
442
+ _.maximal(entry_file_path?, 4)
443
+ button_open_local_file = gtk_button('Open local file')
444
+ button_open_local_file.use_this_font = slightly_smaller_font?
445
+ button_open_local_file.hint = 'Click on this button to open a local file.'
446
+ button_open_local_file.on_clicked {
447
+ do_look_for_a_local_file_and_then_analyse_the_audio_file_at_once
448
+ }
449
+ _.minimal(button_open_local_file, 4)
450
+ _.minimal(gtk_vspacer)
451
+ _.minimal(gtk_vspacer, 1)
452
+ return _
453
+ end
454
+
455
+ # ========================================================================= #
456
+ # === do_popup_the_settings_widget (settings tag)
457
+ # ========================================================================= #
458
+ def do_popup_the_settings_widget
459
+ if @settings_popover.nil?
460
+ @settings_popover = return_popover(
461
+ '',
462
+ header?, # This is the header bar actually.
463
+ :default_padding, # This is the default padding to use.
464
+ @settings_vbox
465
+ )
466
+ end
467
+ @settings_popover.popup
468
+ end
469
+
470
+ # ========================================================================= #
471
+ # === widget_right
472
+ #
473
+ # This is the large vbox that appears on the very left side, containing
474
+ # tons of buttons.
475
+ # ========================================================================= #
476
+ def widget_right
477
+ vbox_containing_the_buttons = gtk_vbox
478
+ vbox_containing_the_buttons.border_width = 6
479
+ vbox_containing_the_buttons.minimal(@button_debug, 1)
480
+ vbox_containing_the_buttons.minimal(@box_for_the_button_analyse_the_mp3_file, 1)
481
+ vbox_containing_the_buttons.minimal(@event_box_open_file, 1)
482
+ vbox_containing_the_buttons.minimal(@button_perform_a_google_search, 1)
483
+ vbox_containing_the_buttons.minimal(@button_open_a_random_audio_file, 1)
484
+ vbox_containing_the_buttons.minimal(@button_delete_the_tags, 1)
485
+ vbox_containing_the_buttons.minimal(@button_update, 1)
486
+ vbox_containing_the_buttons.minimal(@button_play, 1)
487
+ vbox_containing_the_buttons.minimal(@button_save, 1)
488
+ vbox_containing_the_buttons.minimal(@button_close, 1)
489
+ vbox_containing_the_buttons.use_this_font = slightly_smaller_font?
490
+ return vbox_containing_the_buttons
491
+ end; alias return_vbox_containing_the_buttons widget_right # === return_vbox_containing_the_buttons
492
+
493
+ # ========================================================================= #
494
+ # === entry_for_the_title_of_the_song?
495
+ # ========================================================================= #
496
+ def entry_for_the_title_of_the_song?
497
+ @entry_for_the_title_of_the_song
498
+ end; alias entry_for_the_song_name? entry_for_the_title_of_the_song? # === entry_for_the_song_name?
499
+
500
+ # ========================================================================= #
501
+ # === label_duration_content?
502
+ # ========================================================================= #
503
+ def label_duration_content?
504
+ @information_about_a_mp3_file.label_duration_content?
505
+ end
506
+
507
+ # ========================================================================= #
508
+ # === set_the_bitrate
509
+ #
510
+ # This method will update the appropriate label in the grid, containing
511
+ # the bitrate of the .mp3 file.
512
+ # ========================================================================= #
513
+ def set_the_bitrate(i)
514
+ @information_about_a_mp3_file.label_bit_rate_content?.set_text(i.to_s)
515
+ end
516
+
517
+ # ========================================================================= #
518
+ # === set_the_samplerate
519
+ # ========================================================================= #
520
+ def set_the_samplerate(i)
521
+ @information_about_a_mp3_file.label_sample_rate_content.set_text(i.to_s)
522
+ end
523
+
524
+ # ========================================================================= #
525
+ # === sync_genre_onto_entry
526
+ # ========================================================================= #
527
+ def sync_genre_onto_entry(
528
+ this_text = :infer_from_the_dataset
529
+ )
530
+ if dataset?
531
+ this_text = dataset?.genre.to_s
532
+ @entry_for_the_genre.set_text(this_text)
533
+ end
534
+ end
535
+
536
+ # ========================================================================= #
537
+ # === comment_entry?
538
+ # ========================================================================= #
539
+ def comment_entry?
540
+ @entry_for_the_comment
541
+ end
542
+
543
+ # ========================================================================= #
544
+ # === widget_left
545
+ # ========================================================================= #
546
+ def widget_left
547
+ _ = @widget_on_the_right_side_including_the_title_of_the_song = gtk_vbox
548
+ _.set_border_width(2)
549
+ # ======================================================================= #
550
+ # === Title of the song
551
+ # ======================================================================= #
552
+ label_title = modify_bold_label(
553
+ 'Title of the song:',
554
+ 'black', :right
555
+ ).center # align_left_and_center_in_the_middle
556
+ # label_with_the_audio_symbol = gtk_label(:three_stars) # This used to be :audio3
557
+ another_tiny_hbox = gtk_hbox
558
+ use_this_icon_name = 'audio-speakers'
559
+ icon = icon_theme?.load_icon(use_this_icon_name, 32, 0)
560
+ label_with_the_audio_symbol = gtk_image_pixbuf(icon)
561
+
562
+ another_tiny_hbox.minimal(label_with_the_audio_symbol)
563
+ another_tiny_hbox.maximal(label_title)
564
+ mini_vbox = gtk_vbox
565
+ # mini_vbox.pack_start(label_title)
566
+ mini_vbox.maximal(another_tiny_hbox)
567
+ arrow_to_the_right = gtk_label('→ ')
568
+ tiny_hbox = gtk_hbox
569
+ tiny_hbox.minimal(arrow_to_the_right)
570
+ # ======================================================================= #
571
+ # Add the entry for the title of the song next.
572
+ # ======================================================================= #
573
+ tiny_hbox.maximal(@entry_for_the_title_of_the_song)
574
+ mini_vbox.maximal(tiny_hbox)
575
+ _.minimal(mini_vbox, 0)
576
+ # ======================================================================= #
577
+ # Create the grid next that is situated on the right side.
578
+ # ======================================================================= #
579
+ @grid_on_the_right_side = gtk_grid
580
+ @grid_on_the_right_side.set_column_spacing(1)
581
+ @grid_on_the_right_side.set_row_spacing(1)
582
+ _.minimal(@grid_on_the_right_side, 2)
583
+ # ======================================================================= #
584
+ # === Artist
585
+ # ======================================================================= #
586
+ label_the_artist = gtk_label('Artist: ').align_left_and_center_in_the_middle
587
+ label_the_artist.make_bold
588
+ # ======================================================================= #
589
+ # === @entry_for_the_artist
590
+ # ======================================================================= #
591
+ @entry_for_the_artist = gtk_entry
592
+ @entry_for_the_artist.set_max_length(40)
593
+ @entry_for_the_artist.set_size_request(300, 40)
594
+
595
+ @grid_on_the_right_side.attach(label_the_artist, 0, 0, 1, 1) # left, top, width, height
596
+ @grid_on_the_right_side.attach(@entry_for_the_artist, 1, 0, 1, 1)
597
+
598
+ # ======================================================================= #
599
+ # === Year
600
+ # ======================================================================= #
601
+ label_for_the_year = gtk_label('Year: ').align_left_and_center_in_the_middle
602
+ label_for_the_year.make_bold
603
+ label_for_the_year.hint = 'The <b>Year</b> entry should ideally '\
604
+ 'indicate when a song was released officially. Some songs were '\
605
+ 'recorded in a year before, but the more relevant entry will '\
606
+ 'be the year in which that song was released.'
607
+ # ======================================================================= #
608
+ # === @entry_for_the_year
609
+ # ======================================================================= #
610
+ @entry_for_the_year = gtk_entry
611
+ @entry_for_the_year.set_max_length(50)
612
+ @entry_for_the_year.allow_only_numbers
613
+ @entry_for_the_year.focus_on_click_event
614
+
615
+ @grid_on_the_right_side.attach(label_for_the_year, 0, 1, 1, 1) # left, top, width, height
616
+ hbox = gtk_hbox
617
+ hbox.maximal(@entry_for_the_year, 1)
618
+ combo_box_entry = gtk_combo_box_entry
619
+ combo_box_entry.populate(
620
+ (1960 .. 2050).to_a.map(&:to_s)
621
+ )
622
+ combo_box_entry.this_entry_is_active(30)
623
+ combo_box_entry.on_changed {
624
+ @entry_for_the_year.set_text(combo_box_entry.text?)
625
+ }
626
+ hbox.minimal(combo_box_entry)
627
+ @grid_on_the_right_side.attach(hbox, 1, 1, 1, 1)
628
+
629
+ # ======================================================================= #
630
+ # === Album
631
+ # ======================================================================= #
632
+ label_for_the_album = gtk_label('Album: ').align_left_and_center_in_the_middle
633
+ label_for_the_album.make_bold
634
+ # ======================================================================= #
635
+ # === @entry_for_the_album
636
+ # ======================================================================= #
637
+ @entry_for_the_album = gtk_entry
638
+ @entry_for_the_album.set_max_length(75)
639
+
640
+ @grid_on_the_right_side.attach(label_for_the_album, 0, 2, 1, 1) # left, top, width, height
641
+ @grid_on_the_right_side.attach(@entry_for_the_album, 1, 2, 1, 1)
642
+
643
+ # ======================================================================= #
644
+ # === Comment (comment tag)
645
+ #
646
+ # Personally I use this field as a placeholder for a remote URL,
647
+ # to some of the .mp3 songs. This may be useful in other graphical
648
+ # applications.
649
+ # ======================================================================= #
650
+ label_for_the_comment = gtk_label('Comment: ').align_left_and_center_in_the_middle
651
+ label_for_the_comment.make_bold
652
+ event_box_with_left_arrow = gtk_eventbox(emoji(:left_arrow))
653
+ event_box_with_left_arrow.hint = 'Click on this arrow '\
654
+ 'to open the URL (if there is one), via the browser.'
655
+ event_box_with_left_arrow.on_clicked {
656
+ require 'open' unless Object.const_defined? :Open
657
+ Open.in_browser('"'+comment_entry?.text.to_s.strip+'"') unless comment_entry?.text.to_s.empty?
658
+ }
659
+ mini_hbox = gtk_hbox
660
+ mini_hbox.maximal(@entry_for_the_comment)
661
+ mini_hbox.minimal(event_box_with_left_arrow)
662
+ @grid_on_the_right_side.attach(label_for_the_comment, 0, 3, 1, 1) # left, top, width, height
663
+ @grid_on_the_right_side.attach(mini_hbox, 1, 3, 1, 1)
664
+
665
+ # ======================================================================= #
666
+ # === Track number
667
+ # ======================================================================= #
668
+ label_for_the_track_number = gtk_label('Track number: ').align_left_and_center_in_the_middle
669
+ label_for_the_track_number.make_bold
670
+ # ======================================================================= #
671
+ # === @entry_for_the_track_number
672
+ # ======================================================================= #
673
+ @entry_for_the_track_number = gtk_entry
674
+ @entry_for_the_track_number.set_max_length(3)
675
+ @entry_for_the_track_number.set_size_request(50, -1)
676
+ @entry_for_the_track_number.allow_only_numbers
677
+ unless @dataset.nil?
678
+ save_this = @dataset
679
+ save_this = @dataset.track if @dataset.respond_to? :track
680
+ @entry_for_the_track_number.set_text(save_this)
681
+ do_activate_the_save_button
682
+ end
683
+
684
+ @grid_on_the_right_side.attach(label_for_the_track_number, 0, 4, 1, 1) # left, top, width, height
685
+ @grid_on_the_right_side.attach(@entry_for_the_track_number, 1, 4, 1, 1)
686
+
687
+ # ======================================================================= #
688
+ # === Genre
689
+ # ======================================================================= #
690
+ label_for_the_genre = gtk_label('Genre: ').align_left_and_center_in_the_middle
691
+ label_for_the_genre.make_bold
692
+ label_for_the_genre.set_size_request(125, 40)
693
+ @entry_for_the_genre = gtk_entry
694
+ @entry_for_the_genre.set_size_request(125, 40)
695
+ @entry_for_the_genre.make_bold
696
+
697
+ @grid_on_the_right_side.attach(label_for_the_genre, 0, 5, 1, 1) # left, top, width, height
698
+ @grid_on_the_right_side.attach(@entry_for_the_genre, 1, 5, 1, 1)
699
+ # ======================================================================= #
700
+ # === Genre (select)
701
+ #
702
+ # This will load the file called "music_genres.yml", which in turn
703
+ # contains the most commonly used genre entries. Note that this file
704
+ # will NOT contain all genres, as that would lead to a very long
705
+ # dropdown listing.
706
+ # ======================================================================= #
707
+ label_for_the_genre_select = gtk_label('Genre (select): ').align_left_and_center_in_the_middle
708
+ label_for_the_genre_select.make_bold
709
+ create_the_combo_box_entry_for_genre_select
710
+ # ======================================================================= #
711
+ # Next build up the hbox that contains the label and the combo box:
712
+ # ======================================================================= #
713
+ hbox_for_the_genre_select_components = gtk_hbox(
714
+ label_for_the_genre_select,
715
+ @combo_box_entry_for_genre_select
716
+ )
717
+ hbox_for_the_genre_select_components.pack_end(
718
+ @button_assume, padding: 2
719
+ )
720
+ _.minimal(
721
+ hbox_for_the_genre_select_components, 0
722
+ )
723
+ _.minimal(return_the_save_button, 2)
724
+ return _
725
+ end; alias create_and_return_the_pane_holding_various_file_related_entries widget_left # === create_and_return_the_pane_holding_various_file_related_entries
726
+
727
+ # ========================================================================= #
728
+ # === report_artist
729
+ # ========================================================================= #
730
+ def report_artist(i = @artist)
731
+ e sfancy(' Artist: '.ljust(N_PAD))+
732
+ right_colour(i.to_s)
733
+ end
734
+
735
+ # ========================================================================= #
736
+ # === report_album
737
+ # ========================================================================= #
738
+ def report_album(i = @album)
739
+ e sfancy(' Album: '.ljust(N_PAD))+
740
+ right_colour(i.to_s)
741
+ end
742
+
743
+ # ========================================================================= #
744
+ # === report_comment
745
+ # ========================================================================= #
746
+ def report_comment(i = @comment)
747
+ e sfancy(' Comment: '.ljust(N_PAD))+
748
+ right_colour(i.to_s)
749
+ end
750
+
751
+ # ========================================================================= #
752
+ # === report_genre
753
+ #
754
+ # To get all available genres, see:
755
+ #
756
+ # https://en.wikipedia.org/wiki/ID3#Genre_list_in_ID3v1[12]
757
+ #
758
+ # ========================================================================= #
759
+ def report_genre(i = @genre)
760
+ e sfancy(' Genre: '.ljust(N_PAD))+
761
+ right_colour(i.to_s)
762
+ end
763
+
764
+ # ========================================================================= #
765
+ # === report_year
766
+ # ========================================================================= #
767
+ def report_year(i = @year)
768
+ e sfancy(' Year: '.ljust(N_PAD))+
769
+ right_colour(i.to_s)
770
+ end
771
+
772
+ # ========================================================================= #
773
+ # === report_length_in_seconds
774
+ # ========================================================================= #
775
+ def report_length_in_seconds(
776
+ i = @length_in_seconds
777
+ )
778
+ e sfancy(' Duration (in seconds): '.ljust(N_PAD))+
779
+ right_colour(i.to_s)
780
+ end
781
+
782
+ # ========================================================================= #
783
+ # === tag?
784
+ # ========================================================================= #
785
+ def tag?
786
+ @tag
787
+ end; alias tag tag? # === tag
788
+
789
+ # ========================================================================= #
790
+ # === title?
791
+ # ========================================================================= #
792
+ def title?
793
+ @title
794
+ end; alias title title? # === title?
795
+
796
+ # ========================================================================= #
797
+ # === artist?
798
+ # ========================================================================= #
799
+ def artist?
800
+ @artist
801
+ end; alias artist artist? # === artist
802
+
803
+ # ========================================================================= #
804
+ # === date?
805
+ # ========================================================================= #
806
+ def date?
807
+ @date
808
+ end; alias date date? # === date
809
+
810
+ # ========================================================================= #
811
+ # === disc?
812
+ # ========================================================================= #
813
+ def disc?
814
+ @disc
815
+ end; alias disc disc? # === disc
816
+
817
+ # ========================================================================= #
818
+ # === bpm?
819
+ # ========================================================================= #
820
+ def bpm?
821
+ @bpm
822
+ end; alias bpm bpm? # === bpm
823
+
824
+ # ========================================================================= #
825
+ # === album?
826
+ # ========================================================================= #
827
+ def album?
828
+ @album
829
+ end; alias album album? # === album
830
+
831
+ # ========================================================================= #
832
+ # === year?
833
+ # ========================================================================= #
834
+ def year?
835
+ @year
836
+ end; alias year year? # === year
837
+
838
+ # ========================================================================= #
839
+ # === band?
840
+ # ========================================================================= #
841
+ def band?
842
+ @band
843
+ end; alias band band? # === band
844
+
845
+ # ========================================================================= #
846
+ # === genre?
847
+ # ========================================================================= #
848
+ def genre?
849
+ @genre
850
+ end; alias genre genre? # === genre
851
+
852
+ # ========================================================================= #
853
+ # === performer?
854
+ # ========================================================================= #
855
+ def performer?
856
+ @performer
857
+ end; alias performer performer? # === performer
858
+
859
+ # ========================================================================= #
860
+ # === comment?
861
+ # ========================================================================= #
862
+ def comment?
863
+ @comment
864
+ end; alias comment comment? # === comment
865
+
866
+ # ========================================================================= #
867
+ # === track?
868
+ # ========================================================================= #
869
+ def track?
870
+ @track
871
+ end; alias track track? # === track
872
+
873
+ # ========================================================================= #
874
+ # === set_title
875
+ # ========================================================================= #
876
+ def set_title(i)
877
+ @title = i.to_s
878
+ end; alias title= set_title # === title=
879
+
880
+ # ========================================================================= #
881
+ # === set_album
882
+ # ========================================================================= #
883
+ def set_album(i)
884
+ @album = i.to_s
885
+ end; alias album= set_album # === album=
886
+
887
+ # ========================================================================= #
888
+ # === set_artist
889
+ # ========================================================================= #
890
+ def set_artist(i)
891
+ @artist = i.to_s
892
+ end; alias artist= set_artist # === artist=
893
+
894
+ # ========================================================================= #
895
+ # === set_comment
896
+ # ========================================================================= #
897
+ def set_comment(i)
898
+ @comment = i.to_s
899
+ end; alias comment= set_comment # === comment=
900
+
901
+ # ========================================================================= #
902
+ # === set_track
903
+ # ========================================================================= #
904
+ def set_track(i)
905
+ @track = i.to_i # This must be an Integer.
906
+ end; alias track= set_track # === track=
907
+
908
+ # ========================================================================= #
909
+ # === set_year
910
+ # ========================================================================= #
911
+ def set_year(i)
912
+ @year = i.to_i # This must be an Integer.
913
+ end; alias year= set_year # === year=
914
+
915
+ # ========================================================================= #
916
+ # === set_genre
917
+ # ========================================================================= #
918
+ def set_genre(i)
919
+ @genre = i.to_s
920
+ end; alias genre= set_genre # === genre=
921
+
922
+ # ========================================================================= #
923
+ # === set_new_year
924
+ # ========================================================================= #
925
+ def set_new_year(i)
926
+ @tag.year = i.to_i # This must be an Integer.
927
+ end
928
+
929
+ # ========================================================================= #
930
+ # === set_new_album
931
+ # ========================================================================= #
932
+ def set_new_album(i)
933
+ @tag.album = i
934
+ end
935
+
936
+ # ========================================================================= #
937
+ # === report_everything
938
+ #
939
+ # This method will report as much as possible about the song at hand.
940
+ #
941
+ # "track" would also be a tag that could be shown. Personally I don't
942
+ # really need it, though.
943
+ # ========================================================================= #
944
+ def report_everything
945
+ report_title
946
+ report_artist
947
+ report_album
948
+ report_year
949
+ report_genre
950
+ report_comment
951
+ report_length_in_seconds
952
+ end; alias report report_everything # === report
953
+
954
+ # ========================================================================= #
955
+ # === work_on_this_file
956
+ # ========================================================================= #
957
+ def work_on_this_file(
958
+ this_file = @this_file
959
+ )
960
+ unless Object.const_defined? :TagLib
961
+ text = <<-EOF
962
+ Please install TagLib first via:
963
+
964
+ gem install taglib
965
+
966
+ EOF
967
+ e text
968
+ return text
969
+ end
970
+ # ======================================================================= #
971
+ # Load up the file via TagLib first.
972
+ # ======================================================================= #
973
+ TagLib::FileRef.open(this_file) { |fileref| # of class TagLib::FileRef.
974
+ unless fileref.null?
975
+ @tag = fileref.tag # Keep a reference to it here.
976
+ @title = @tag.title # => "Wake Up"
977
+ @artist = @tag.artist # => "DJ Punk"
978
+ @album = @tag.album # => "Funeral"
979
+ @year = @tag.year # => 2004
980
+ @genre = @tag.genre # => "Indie Rock"
981
+ @comment = @tag.comment
982
+ @track = @tag.track
983
+ # @band = @tag.band # Does not exist.
984
+ @performer = @tag.performer if @tag.respond_to? :performer
985
+ @properties = fileref.audio_properties
986
+ do_determine_the_length_of_the_song(this_file)
987
+ if @may_we_report
988
+ e
989
+ report_everything
990
+ e
991
+ end
992
+ end
993
+ } # File is automatically closed at block end.
994
+ end
995
+
996
+ # ========================================================================= #
997
+ # === this_file?
998
+ # ========================================================================= #
999
+ def this_file?
1000
+ @this_file
1001
+ end; alias main_file? this_file? # === main_file?
1002
+
1003
+ # ========================================================================= #
1004
+ # === length_in_seconds?
1005
+ # ========================================================================= #
1006
+ def length_in_seconds?
1007
+ @length_in_seconds
1008
+ end
1009
+
1010
+ # ========================================================================= #
1011
+ # === do_determine_the_length_of_the_song
1012
+ #
1013
+ # The first argument should be the name of the .mp3 file at hand.
1014
+ # ========================================================================= #
1015
+ def do_determine_the_length_of_the_song(
1016
+ this_file = main_file?
1017
+ )
1018
+ # ======================================================================= #
1019
+ # The way for the mp3-library goes like this:
1020
+ # @length_in_seconds = @properties.length_in_seconds # => 335 (song length)
1021
+ # But this was buggy for me, so we query ffmpeg instead. The code above
1022
+ # is retained, though, in the event that we may want to re-instate it
1023
+ # one day. (Noted this down at 26.10.2021)
1024
+ # ======================================================================= #
1025
+ @length_in_seconds = ::MultimediaParadise.length_of?(this_file)
1026
+ end
1027
+
1028
+ # ========================================================================= #
1029
+ # === try_to_require_the_tablib_gem
1030
+ # ========================================================================= #
1031
+ def try_to_require_the_tablib_gem
1032
+ begin
1033
+ # ===================================================================== #
1034
+ # Require the taglib-ruby gem.
1035
+ #
1036
+ # See: https://rubygems.org/gems/taglib-ruby
1037
+ # ===================================================================== #
1038
+ require 'taglib'
1039
+ rescue LoadError; end
1040
+ end
1041
+
1042
+ # ========================================================================= #
1043
+ # === update!
1044
+ #
1045
+ # This method can be used to update the tags.
1046
+ # ========================================================================= #
1047
+ def update!(
1048
+ this_file = @this_file
1049
+ )
1050
+ TagLib::FileRef.open(this_file) { |fileref| # of class TagLib::FileRef.
1051
+ unless fileref.null?
1052
+ @tag = fileref.tag # Keep a reference to it here.
1053
+ set_new_album(@album) # Use the old reference.
1054
+ set_new_year(@year) # Use the old reference, via @year.
1055
+ @tag.title = @title.to_s
1056
+ @tag.artist = @artist.to_s
1057
+ @tag.genre = @genre.to_s
1058
+ @tag.comment = @comment.to_s
1059
+ if @track
1060
+ @tag.track = @track.to_i # This must be an integer.
1061
+ end
1062
+ fileref.save
1063
+ end
1064
+ }
1065
+ end
1066
+
1067
+ # ========================================================================= #
1068
+ # === save
1069
+ # ========================================================================= #
1070
+ def save
1071
+ @tag.save
1072
+ end
1073
+
1074
+ # ========================================================================= #
1075
+ # === set_this_file
1076
+ # ========================================================================= #
1077
+ def set_this_file(i)
1078
+ @this_file = i
1079
+ end
1080
+
1081
+ # ========================================================================= #
1082
+ # === report_title
1083
+ # ========================================================================= #
1084
+ def report_title(i = @title)
1085
+ e sfancy(' Title: '.ljust(N_PAD))+
1086
+ right_colour(i.to_s)
1087
+ end
1088
+
1089
+ # ========================================================================= #
1090
+ # === right_colour
1091
+ # ========================================================================= #
1092
+ def right_colour(i)
1093
+ mediumpurple(i)
1094
+ end
1095
+
1096
+ # ========================================================================= #
1097
+ # === instantiate_the_metadata_from_this_file
1098
+ #
1099
+ # This will set @metadata_for_the_song.
1100
+ # ========================================================================= #
1101
+ def instantiate_the_metadata_from_this_file(this_file)
1102
+ # ======================================================================= #
1103
+ # === @metadata_for_the_song
1104
+ # ======================================================================= #
1105
+ @metadata_for_the_song = MultimediaParadise.analyse_tags_of_this_mp3_file(this_file)
1106
+ end
1107
+
1108
+ # ========================================================================= #
1109
+ # === metadata_for_the_song?
1110
+ # ========================================================================= #
1111
+ def metadata_for_the_song?
1112
+ @metadata_for_the_song
1113
+ end; alias metadata? metadata_for_the_song? # === metadata?
1114
+ alias dataset? metadata_for_the_song? # === dataset?
1115
+
1116
+ # ========================================================================= #
1117
+ # === sync_the_duration_of_the_file_onto_the_correct_entry
1118
+ # ========================================================================= #
1119
+ def sync_the_duration_of_the_file_onto_the_correct_entry(
1120
+ _ = @metadata_for_the_song
1121
+ )
1122
+ if _
1123
+ use_this_duration = _.length_in_seconds?.round(5).to_s
1124
+ label_duration_content?.set_text(use_this_duration)
1125
+ label_duration_content?.make_bold
1126
+ end
1127
+ end
1128
+
1129
+ # ========================================================================= #
1130
+ # === header_bar_height?
1131
+ # ========================================================================= #
1132
+ def header_bar_height?
1133
+ 54
1134
+ end
1135
+
1136
+ # ========================================================================= #
1137
+ # === return_widget_information_about_a_mp3_file
1138
+ # ========================================================================= #
1139
+ def return_widget_information_about_a_mp3_file
1140
+ @information_about_a_mp3_file = MultimediaParadise::GUI::Gtk::InformationAboutAMp3File.new
1141
+ @information_about_a_mp3_file.set_parent_widget(self)
1142
+ return @information_about_a_mp3_file
1143
+ end; alias return_the_grid_containing_the_bitrate_and_associated_values return_widget_information_about_a_mp3_file # === return_the_grid_containing_the_bitrate_and_associated_values
1144
+ alias create_table1 return_widget_information_about_a_mp3_file # === create_table1
1145
+
1146
+ # ========================================================================= #
1147
+ # === do_open_a_random_audio_file_and_then_set_the_proper_entry
1148
+ #
1149
+ # The first argument to this method must be the file path to the
1150
+ # local .mp3 file at hand.
1151
+ # ========================================================================= #
1152
+ def do_open_a_random_audio_file_and_then_set_the_proper_entry(
1153
+ _ = return_random_audio_file
1154
+ )
1155
+ clear_old_entries # We must clear old entries as well.
1156
+ entry_file_path?.set_text(_.to_s)
1157
+ # ======================================================================= #
1158
+ # If the file exists we will also update the file size label.
1159
+ # ======================================================================= #
1160
+ if File.exist? _
1161
+ do_analyse_the_audio_file(entry_file_path_text?)
1162
+ set_all_relevant_entries_based_on_the_metadata
1163
+ # ===================================================================== #
1164
+ # Empty the status bar as well whenever a new file is assigned.
1165
+ # ===================================================================== #
1166
+ add_this_text_to_the_status_bar('')
1167
+ end
1168
+ end
1169
+
1170
+ # ========================================================================= #
1171
+ # === set_main_entry
1172
+ # ========================================================================= #
1173
+ def set_main_entry(i)
1174
+ @entry_file_path.set_text(i)
1175
+ if File.exist? i # Safeguard.
1176
+ do_analyse_the_default_file
1177
+ set_all_relevant_entries_based_on_the_metadata
1178
+ end
1179
+ end
1180
+
1181
+ # ========================================================================= #
1182
+ # === do_analyse_the_mp3_file (analyse tag, load tag)
1183
+ #
1184
+ # This is closely related to the method called
1185
+ # do_analyse_the_audio_file_then_set_all_relevant_entries().
1186
+ #
1187
+ # This is the method that should be called when the user wants to obtain
1188
+ # information about the metadata of the song (.mp3 file) at hand.
1189
+ #
1190
+ # It will not do anything with the different gtk-widgets in use, so you
1191
+ # have to call other methods if you want to sync towards the gtk-widgets.
1192
+ #
1193
+ # We also need to check whether ID3Lib is available if this is used; in
1194
+ # particular windows-users may often not have it installed by default.
1195
+ # ========================================================================= #
1196
+ def do_analyse_the_mp3_file(
1197
+ _ = entry_file_path_text?
1198
+ )
1199
+ if _ and !_.empty? and File.exist?(_)
1200
+ # ===================================================================== #
1201
+ # First we have to honour the correct id-tagger to use, as specified
1202
+ # by the user.
1203
+ # ===================================================================== #
1204
+ case ID_TAGGER_TO_USE_FOR_THE_MP3_FILES
1205
+ # ===================================================================== #
1206
+ # === :taglib
1207
+ #
1208
+ # We must notify the user that taglib is mandatory - otherwise the
1209
+ # application will not work properly.
1210
+ # ===================================================================== #
1211
+ when :taglib
1212
+ unless Object.const_defined? :TagLib
1213
+ text_to_display = <<-EOF
1214
+ Please install TagLib first via:
1215
+
1216
+ <b>gem install taglib-ruby</b>
1217
+
1218
+ EOF
1219
+ custom_widget = gtk_vbox
1220
+ custom_widget.pad12px
1221
+ custom_widget.bblack1
1222
+ button_to_use = button('gem install taglib-ruby')
1223
+ button_to_use.on_clicked {
1224
+ esystem(button_to_use.text?)
1225
+ }
1226
+ custom_widget.maximal(button_to_use)
1227
+ custom_widget.show_all
1228
+ a_new_popup = return_popover(
1229
+ text_to_display,
1230
+ entry_on_top?,
1231
+ 25, # Padding is 25 px.
1232
+ custom_widget
1233
+ )
1234
+ a_new_popup.popup
1235
+ end
1236
+ # ===================================================================== #
1237
+ # === :id3lib
1238
+ # ===================================================================== #
1239
+ when :id3lib
1240
+ if Object.const_defined? :ID3Lib
1241
+ this_song = ID3Lib::Tag.new(this_song)
1242
+ # Enable the save-button functionality. This is currently (2021)
1243
+ # not needed anymore.
1244
+ # the_save_button_is_available_again
1245
+ else
1246
+ e 'ID3Lib is not available/installed. Please install '\
1247
+ 'it for your platform / operating-system.'
1248
+ end
1249
+ end
1250
+ @spinner.start_spinning
1251
+ Thread.new {
1252
+ # =================================================================== #
1253
+ # Clear the old status-bar message first.
1254
+ # =================================================================== #
1255
+ add_this_text_to_the_status_bar('')
1256
+ # =================================================================== #
1257
+ # The class here is: MultimediaParadise::AudioTagReader.
1258
+ # The old code used MultimediaParadise::AudioTagReader.new()
1259
+ # directly. In September 2021 this was changed to a
1260
+ # toplevel-method instead.
1261
+ # =================================================================== #
1262
+ clear_old_entries
1263
+ e steelblue('-' * 60)
1264
+ instantiate_the_metadata_from_this_file(_)# This will set @metadata_for_the_song
1265
+ @metadata_for_the_song.report # This can be used for debugging.
1266
+ @information_about_a_mp3_file.set_duration(@metadata_for_the_song.length_in_seconds?.to_s)
1267
+ file_size = File.size(_)
1268
+ @information_about_a_mp3_file.set_filesize(file_size.to_s)
1269
+ # entry_for_the_title_of_the_song?.set_text(@metadata_for_the_song.title?.to_s)
1270
+ do_assume_the_name_of_the_song_and_the_artist_from_the_filename_directly
1271
+ sync_everything
1272
+ @spinner.stop_spinning # Now we can stop spinning.
1273
+ if is_on_roebe?
1274
+ display_information_about_the_song
1275
+ e 'Next, as we are on roebe, we will display the '+
1276
+ ::Colours.steelblue('@dataset')+' variable.'
1277
+ pp dataset?
1278
+ end
1279
+ }
1280
+ else
1281
+ e 'First assign a path, please.'
1282
+ end
1283
+ end; alias load_the_id3_dataset_from_this_file do_analyse_the_mp3_file # === load_the_id3_dataset_from_this_file
1284
+ alias do_analyse_the_audio_file_at_once do_analyse_the_mp3_file # === do_analyse_the_audio_file_at_once
1285
+ alias do_open_a_local_file_and_then_set_the_proper_entry do_analyse_the_mp3_file # === do_open_a_local_file_and_then_set_the_proper_entry
1286
+ alias do_analyse_the_audio_file do_analyse_the_mp3_file # === do_analyse_the_audio_file
1287
+ alias determine_the_metadata_for_this_song do_analyse_the_mp3_file # === determine_the_metadata_for_this_song
1288
+ alias analyse_this_song do_analyse_the_mp3_file # === analyse_this_song
1289
+ alias do_analyse_the_audio_file do_analyse_the_mp3_file # === do_analyse_the_audio_file
1290
+ alias do_analyse_the_default_file do_analyse_the_mp3_file # === do_analyse_the_default_file
1291
+ alias ensure_that_we_have_a_dataset do_analyse_the_mp3_file # === ensure_that_we_have_a_dataset
1292
+
1293
+ # ========================================================================= #
1294
+ # === return_event_box_for_opening_a_file
1295
+ #
1296
+ # The first two arguments can designate a certain width and height
1297
+ # for the widget.
1298
+ # ========================================================================= #
1299
+ def return_event_box_for_opening_a_file(
1300
+ width = 110,
1301
+ height = 65
1302
+ )
1303
+ event_box_open_file = gtk_event_box
1304
+ # ======================================================================= #
1305
+ # In April 2021 the code below this comment was changed to an image.
1306
+ #
1307
+ # Relying on an emoji is unfortunately not that reliable, because
1308
+ # we depend on the emojis available on the local computer. This
1309
+ # may not always work, whereas with an image we can depend on
1310
+ # more reliably so.
1311
+ #
1312
+ # event_box_open_file << emoji(:open_file)
1313
+ #
1314
+ # ======================================================================= #
1315
+ # event_box_open_file << gtk_image(:open_local_file)
1316
+ event_box_open_file << text('Open a local file')
1317
+ event_box_open_file.set_border_width(1)
1318
+ event_box_open_file.set_size_request(125, 68)
1319
+ event_box_open_file.css_class('button_class')
1320
+ event_box_open_file.pad5px
1321
+ event_box_open_file.on_clicked {
1322
+ do_look_for_a_local_file_and_then_analyse_the_audio_file_at_once
1323
+ }
1324
+ event_box_open_file.hint =
1325
+ 'Click on this button to open '\
1326
+ '<b>a local .mp3 file</b>.'
1327
+ return event_box_open_file
1328
+ end
1329
+
1330
+ # ========================================================================= #
1331
+ # === do_look_for_a_local_file_and_then_analyse_the_audio_file_at_once (open tag)
1332
+ # ========================================================================= #
1333
+ def do_look_for_a_local_file_and_then_analyse_the_audio_file_at_once
1334
+ look_for_a_local_file {{
1335
+ filter_for: %w( .mp3 .ogg ),
1336
+ start_directory: return_path_to_the_local_songs_directory_or_return_pwd,
1337
+ additional_directories: [return_pwd] # Always add the current working directory.
1338
+ }}
1339
+ @entry_file_path.set_text(::Gtk.main_file?.to_s)
1340
+ do_analyse_the_audio_file_at_once
1341
+ end; alias do_open_the_file_opener_dialog do_look_for_a_local_file_and_then_analyse_the_audio_file_at_once # === do_open_the_file_opener_dialog
1342
+ alias do_open_file do_look_for_a_local_file_and_then_analyse_the_audio_file_at_once # === do_open_file
1343
+ alias open_local_file do_look_for_a_local_file_and_then_analyse_the_audio_file_at_once # === open_local_file
1344
+
1345
+ # ========================================================================= #
1346
+ # === return_button_open_a_random_audio_file
1347
+ # ========================================================================= #
1348
+ def return_button_open_a_random_audio_file(
1349
+ options = nil
1350
+ )
1351
+ use_this_icon_name = 'folder-music'
1352
+ icon = load_icon(use_this_icon_name, 32, 0)
1353
+ case options
1354
+ # ======================================================================= #
1355
+ # === :no_text
1356
+ # ======================================================================= #
1357
+ when :no_text
1358
+ button = create_button
1359
+ button.set_image(icon)
1360
+ else
1361
+ button = gtk_button_with_label('Open _random audio-file')
1362
+ button.set_image(icon)
1363
+ button.set_always_show_image(true)
1364
+ button.set_border_width(1)
1365
+ button.set_size_request(125, 68)
1366
+ end
1367
+ button.hint =
1368
+ "This button can, upon being clicked, be used to <b>open a random</b> .mp3 "\
1369
+ "file.\n\n"\
1370
+ "Take note that the path to these random audio files default to "\
1371
+ "a hardcoded path specified based on a constant, "\
1372
+ "so you may have to change this to fit to your own "\
1373
+ "computer system.\n\n"+
1374
+ "The constant that determines this is called "\
1375
+ "<span weight=\"bold\" foreground=\"gold\" background=\"black\">PATH_TO_THE_LOCAL_AUDIO_DIRECTORY</span>,"\
1376
+ "and it currently points at "\
1377
+ "<span weight=\"bold\" foreground=\"gold\" background=\"black\">#{@entry_use_this_as_the_directory_to_the_local_songs.text?}</span>,"\
1378
+ ", so make sure that you adapt this to your own setup.\n"
1379
+ button.on_clicked {
1380
+ do_open_a_random_audio_file_and_then_set_the_proper_entry
1381
+ }
1382
+ return button
1383
+ end
1384
+
1385
+ # ========================================================================= #
1386
+ # === widget_top
1387
+ # ========================================================================= #
1388
+ def widget_top
1389
+ # ======================================================================= #
1390
+ # === @header_bar
1391
+ #
1392
+ # This is the widget that will be found on the very top of this
1393
+ # application.
1394
+ # ======================================================================= #
1395
+ _ = default_header_bar
1396
+ _.show_close_button = true
1397
+ _.has_close_button
1398
+ _.set_name('header_bar_on_top')
1399
+ _.set_custom_title(@label_description)
1400
+ _.spacing = 2
1401
+ _.use_this_font = normal_font?
1402
+
1403
+ button_open_a_random_audio_file = return_button_open_a_random_audio_file(:no_text)
1404
+ button_open_a_random_audio_file.hint =
1405
+ 'Click this button to <b>open and assign a random .mp3 file</b>.'
1406
+ _.pack_start(button_open_a_random_audio_file)
1407
+
1408
+ # ======================================================================= #
1409
+ # === Open a local file, as part of the menu-interface
1410
+ # ======================================================================= #
1411
+ open_a_local_file = gtk_button('Open a local file')
1412
+ open_a_local_file.on_activate {
1413
+ do_open_a_local_file_and_then_set_the_proper_entry
1414
+ }
1415
+ _.pack_start(open_a_local_file)
1416
+
1417
+ # ======================================================================= #
1418
+ # === Show about-information, as part of the top header-bar
1419
+ #
1420
+ # It will be appended, aka .pack_end() is used.
1421
+ # ======================================================================= #
1422
+ button_about = button('About')
1423
+ button_about.hint = 'This will display information about this '\
1424
+ 'application.'
1425
+ button_about.on_clicked {
1426
+ do_show_information_about_this_application
1427
+ }
1428
+ _.pack_end(button_about)
1429
+
1430
+ # ======================================================================= #
1431
+ # === button_show_the_settings
1432
+ # ======================================================================= #
1433
+ button_show_the_settings = gtk_button('Settings')
1434
+ button_show_the_settings.hint = 'This button allows you to change a few '\
1435
+ 'settings of this application.'
1436
+ button_show_the_settings.on_clicked {
1437
+ do_popup_the_settings_widget
1438
+ }
1439
+ _.pack_start(button_show_the_settings)
1440
+ return _
1441
+ end; alias return_the_header_bar widget_top # === create_the_header_bar
1442
+
1443
+ # ========================================================================= #
1444
+ # === do_assign_a_new_random_audio_file
1445
+ # ========================================================================= #
1446
+ def do_assign_a_new_random_audio_file
1447
+ _ = return_random_audio_file.to_s
1448
+ unless _.empty? # Check against no results.
1449
+ entry_file_path?.set_text(_)
1450
+ do_open_a_random_audio_file_and_then_set_the_proper_entry
1451
+ end
1452
+ end
1453
+
1454
+ # ========================================================================= #
1455
+ # === do_save_the_tags (save tag)
1456
+ #
1457
+ # This method applies all changes by invoking metadata?.update!
1458
+ # ========================================================================= #
1459
+ def do_save_the_tags
1460
+ metadata = metadata?
1461
+ return unless metadata
1462
+ display_information_about_the_song if is_on_roebe?
1463
+ # ======================================================================= #
1464
+ # Squeeze the entry for the comment, so that leading and trailing ' '
1465
+ # are not retained.
1466
+ # ======================================================================= #
1467
+ _ = @entry_for_the_comment.text?
1468
+ if _ and !_.empty?
1469
+ @entry_for_the_comment.set_text(_.strip)
1470
+ end
1471
+ metadata.title = @entry_for_the_title_of_the_song.text
1472
+ metadata.album = @entry_for_the_album.text
1473
+ metadata.artist = @entry_for_the_artist.text
1474
+ metadata.comment = @entry_for_the_comment.text
1475
+ metadata.track = @entry_for_the_track_number.text
1476
+ metadata.year = @entry_for_the_year.text
1477
+ metadata.genre = return_entry_from_the_combo_box_entry_for_genre_select_or_from_the_entry_for_the_genre
1478
+ # ======================================================================= #
1479
+ # Next we will update the dataset and apply the changes made above.
1480
+ # ======================================================================= #
1481
+ metadata.update!
1482
+ display_information_about_the_song if is_on_roebe?
1483
+ # ======================================================================= #
1484
+ # Update the status-bar as well.
1485
+ # ======================================================================= #
1486
+ add_this_text_to_the_status_bar(
1487
+ 'The meta-data was saved (on '+
1488
+ ::MultimediaParadise.return_ss_mm_hh.to_s+').'
1489
+ )
1490
+ end; alias do_save_tags do_save_the_tags # === do_save_tags
1491
+
1492
+ # ========================================================================= #
1493
+ # === update_the_MPEG_entry
1494
+ # ========================================================================= #
1495
+ def update_the_MPEG_entry(
1496
+ i = which_file?
1497
+ )
1498
+ _ = MultimediaParadise.return_the_mpeg_layer_from_this_mp3_file(i)
1499
+ @information_about_a_mp3_file.label_mpeg_level_content.set_text(_.to_s)
1500
+ end
1501
+
1502
+ # ========================================================================= #
1503
+ # === sync_this_text_onto_the_genre_entry
1504
+ #
1505
+ # This method can be used to "sync" onto the entry containing the genre
1506
+ # tag. We won't do any additional sanitizing or checks within this
1507
+ # method, excluding .to_s, so you have to ensure that the given
1508
+ # input is valid, as-is.
1509
+ # ========================================================================= #
1510
+ def sync_this_text_onto_the_genre_entry(i)
1511
+ @entry_for_the_genre.set_text(i.to_s)
1512
+ @entry_for_the_genre.make_bold
1513
+ end
1514
+
1515
+ require 'multimedia_paradise/version/version.rb'
1516
+ # ========================================================================= #
1517
+ # === do_show_information_about_this_application (about tag)
1518
+ # ========================================================================= #
1519
+ def do_show_information_about_this_application
1520
+ dialog = gtk_about_dialog
1521
+ authors = ['Robert A. Heiler']
1522
+ documenters = ['Robert A. Heiler']
1523
+ begin
1524
+ logo = GdkPixbuf::Pixbuf.new(
1525
+ pixbuf: return_pixbuf_based_on_the_default_icon_theme(:inode_directory)
1526
+ )
1527
+ dialog.set_logo(logo)
1528
+ rescue Exception => error
1529
+ pp error
1530
+ end
1531
+ dialog.set_name('tag_mp3_files')
1532
+ dialog.set_version(::MultimediaParadise::VERSION)
1533
+ dialog.set_copyright("(C) 2022 Robert A. Heiler")
1534
+ dialog.set_comments(
1535
+ "This application can be used to rename the meta-tags "\
1536
+ "of .mp3 files. It is recommended to install the "\
1537
+ "taglib-ruby gem, in order to use this application."
1538
+ )
1539
+ dialog.license = 'GPL-2.0'
1540
+ dialog.set_website(
1541
+ 'https://rubygems.org/gems/multimedia_paradise'
1542
+ )
1543
+ dialog.set_website_label('https://rubygems.org/gems/multimedia_paradise')
1544
+ dialog.set_authors(authors)
1545
+ dialog.set_documenters(documenters)
1546
+ dialog.set_program_name('tag_mp3_files')
1547
+ dialog.signal_connect(:response) {
1548
+ dialog.destroy
1549
+ }
1550
+ dialog.run
1551
+ end
1552
+
1553
+ # ========================================================================= #
1554
+ # === do_analyse_the_audio_file_then_set_all_relevant_entries
1555
+ # ========================================================================= #
1556
+ def do_analyse_the_audio_file_then_set_all_relevant_entries
1557
+ do_analyse_the_audio_file(entry_file_path_text?)
1558
+ set_all_relevant_entries_based_on_the_metadata
1559
+ end
1560
+
1561
+ # ========================================================================= #
1562
+ # === add_custom_CSS_rules (CSS tag)
1563
+ #
1564
+ # This method is used to add additional CSS rules to this widget.
1565
+ # ========================================================================= #
1566
+ def add_custom_CSS_rules
1567
+ # ======================================================================= #
1568
+ # The first rule is to style the separator.
1569
+ # ======================================================================= #
1570
+ more_CSS_rules_then_apply_them '
1571
+ button {
1572
+ border-color: steelblue;
1573
+ border-width: 2px;
1574
+ }
1575
+
1576
+ .button_class {
1577
+ border: 2px solid steelblue;;
1578
+ }
1579
+
1580
+ #fancy_separator separator {
1581
+ border: 1px dotted lightgrey;
1582
+ padding: 0px;
1583
+ margin: 4px;
1584
+ }
1585
+
1586
+ .save_button {
1587
+ border: 3px dashed steelblue;
1588
+ padding: 2px;
1589
+ margin: 4px;
1590
+ }
1591
+
1592
+ .fancy_combobox window.popup {
1593
+ color: royalblue;
1594
+ font-weight: bold;
1595
+ border: 3px dashed lightgreen;
1596
+ }
1597
+
1598
+ /* style the top header bar next */
1599
+ #header_bar_on_top {
1600
+ border: 2px dotted royalblue;
1601
+ }
1602
+
1603
+ '
1604
+ end
1605
+
1606
+ # ========================================================================= #
1607
+ # === set_the_file_size_from_this_file
1608
+ # ========================================================================= #
1609
+ def set_the_file_size_from_this_file(
1610
+ this_file = @entry_file_path.text?
1611
+ )
1612
+ @information_about_a_mp3_file.label_file_size_content.set_text(
1613
+ "#{(File.size(this_file) / 1024.0 / 1000.0).round(2)} MB".
1614
+ rjust(8)
1615
+ )
1616
+ end
1617
+
1618
+ # ========================================================================= #
1619
+ # === sync_comment_onto_entry
1620
+ # ========================================================================= #
1621
+ def sync_comment_onto_entry
1622
+ dataset = dataset?
1623
+ if dataset
1624
+ _ = dataset.comment.to_s.dup
1625
+ # ===================================================================== #
1626
+ # We have to use the proper encoding for the comment-field.
1627
+ # ===================================================================== #
1628
+ _ = _.force_encoding(::MultimediaParadise::UTF_ENCODING)
1629
+ @entry_for_the_comment.set_text(_)
1630
+ end
1631
+ end
1632
+
1633
+ # ========================================================================= #
1634
+ # === set_a_uniform_background_for_the_entries_on_the_right_side_widget
1635
+ #
1636
+ # This is currently (August 2021) not in use. I realized that it actually
1637
+ # rather distracts then enhances. I keep it here if we want to
1638
+ # re-enable it again at one moment in time.
1639
+ # ========================================================================= #
1640
+ def set_a_uniform_background_for_the_entries_on_the_right_side_widget(
1641
+ array = return_all_entries_on_the_right_side_widget
1642
+ )
1643
+ array.each {|this_entry|
1644
+ this_entry.clear_background
1645
+ this_entry.very_light_yellowish_background
1646
+ }
1647
+ end
1648
+
1649
+ # ========================================================================= #
1650
+ # === entry_use_which_audio_file?
1651
+ # ========================================================================= #
1652
+ def entry_use_which_audio_file?
1653
+ @entry_file_path
1654
+ end; alias entry_on_top? entry_use_which_audio_file? # === entry_on_top?
1655
+ alias entry_file_path? entry_use_which_audio_file? # === entry_file_path?
1656
+
1657
+ # ========================================================================= #
1658
+ # === the_save_button_is_available_again
1659
+ #
1660
+ # This is currently (January 2021) not in use. I am not sure whether
1661
+ # it will be re-enabled, but for now the method will remain part of
1662
+ # the widget.
1663
+ # ========================================================================= #
1664
+ def the_save_button_is_available_again
1665
+ @button_save.is_sensitive_again
1666
+ end; alias do_activate_the_save_button the_save_button_is_available_again # === do_activate_the_save_button
1667
+
1668
+ # ========================================================================= #
1669
+ # === sync_title_onto_entry
1670
+ # ========================================================================= #
1671
+ def sync_title_onto_entry
1672
+ dataset = dataset?
1673
+ if dataset
1674
+ @entry_for_the_title_of_the_song.set_text(dataset.title.to_s)
1675
+ end
1676
+ end
1677
+
1678
+ # ========================================================================= #
1679
+ # === display_information_about_the_song (debug tag)
1680
+ #
1681
+ # This method exists mostly to simplify debugging the application at hand.
1682
+ # ========================================================================= #
1683
+ def display_information_about_the_song
1684
+ # ======================================================================= #
1685
+ # Get and set text frames with convenience methods.
1686
+ # ======================================================================= #
1687
+ e horizontal_unicode_bar*80
1688
+ dataset = metadata?
1689
+ if dataset
1690
+ ee 'Title: '.ljust(30); pp dataset.title # => "Talk"
1691
+ ee 'Album: '.ljust(30); pp dataset.album # new album setter
1692
+ ee 'Performer: (not in use) '.ljust(30);pp dataset.performer # performer; this is not in use by this application though.
1693
+ ee 'Artist: '.ljust(30); pp dataset.artist
1694
+ ee 'Band: '.ljust(30); pp dataset.band
1695
+ ee 'bpm: '.ljust(30); pp dataset.bpm
1696
+ ee 'Date: '.ljust(30); pp dataset.date
1697
+ ee 'Disc: '.ljust(30); pp dataset.disc
1698
+ ee 'Genre: '.ljust(30); pp dataset.genre
1699
+ ee 'time: '.ljust(30); pp dataset.time if dataset.respond_to? :time
1700
+ ee 'track: '.ljust(30); pp dataset.track if dataset.respond_to? :track
1701
+ ee 'language: '.ljust(30); pp dataset.language if dataset.respond_to? :language
1702
+ ee 'Grouping: '.ljust(30); pp dataset.grouping if dataset.respond_to? :grouping
1703
+ ee 'Encoded by: '.ljust(30);pp dataset.encoded_by if dataset.respond_to? :encoded_by
1704
+ ee 'composer: '.ljust(30); pp dataset.composer if dataset.respond_to? :composer
1705
+ ee 'Track: '.ljust(30); pp dataset.track if dataset.respond_to? :track # new track setter
1706
+ ee 'Year: '.ljust(30); pp dataset.year # 2000, query year.
1707
+ ee 'Comment: '.ljust(30); pp dataset.comment # Comments are listed there.
1708
+ e horizontal_unicode_bar*80
1709
+ e
1710
+ else
1711
+ e 'No dataset has been assigned yet.'
1712
+ end
1713
+ end; alias do_debug display_information_about_the_song # === do_debug
1714
+
1715
+ # ========================================================================= #
1716
+ # === handle_CSS_rules (CSS tag)
1717
+ # ========================================================================= #
1718
+ def handle_CSS_rules
1719
+ use_gtk_paradise_project_css_file
1720
+ append_project_css_file
1721
+ add_custom_CSS_rules
1722
+ end
1723
+
1724
+ # ========================================================================= #
1725
+ # === clear_old_entries
1726
+ # ========================================================================= #
1727
+ def clear_old_entries
1728
+ @entry_for_the_album.set_text('')
1729
+ @information_about_a_mp3_file.label_mpeg_level_content.set_text('')
1730
+ end
1731
+
1732
+ # ========================================================================= #
1733
+ # === filename?
1734
+ # ========================================================================= #
1735
+ def filename?
1736
+ @entry_file_path.text?.to_s
1737
+ end
1738
+
1739
+ # ========================================================================= #
1740
+ # === do_assume_the_name_of_the_song_and_the_artist_from_the_filename_directly
1741
+ # ========================================================================= #
1742
+ def do_assume_the_name_of_the_song_and_the_artist_from_the_filename_directly
1743
+ _ = filename?
1744
+ if _ and File.exist?(_)
1745
+ raw_name = File.basename(_)
1746
+ # ===================================================================== #
1747
+ # Get rid of the extension.
1748
+ # ===================================================================== #
1749
+ raw_name.delete_suffix!(
1750
+ File.extname(raw_name)
1751
+ )
1752
+ if raw_name.include? '_'
1753
+ splitted = raw_name.split('_')
1754
+ artist_name = splitted.first.to_s
1755
+ song_name = splitted.last.to_s
1756
+ @entry_for_the_artist.set_text(artist_name)
1757
+ entry_for_the_song_name?.set_text(song_name)
1758
+ else
1759
+ @entry_for_the_artist.set_text(raw_name)
1760
+ end
1761
+ else
1762
+ e 'No file has been assigned yet. Please assign a file first.'
1763
+ end
1764
+ end
1765
+
1766
+ # ========================================================================= #
1767
+ # === set_all_relevant_entries_based_on_the_metadata (sync tag)
1768
+ #
1769
+ # This method will sync all relevant entries into the corresponding
1770
+ # gtk-entry at hand.
1771
+ # ========================================================================= #
1772
+ def set_all_relevant_entries_based_on_the_metadata(
1773
+ this_file = main_file?
1774
+ )
1775
+ # ======================================================================= #
1776
+ # First ensure that the file exists.
1777
+ # ======================================================================= #
1778
+ if this_file.nil? or !File.exist?(this_file)
1779
+ e "No file exists at `#{sfile(this_file)}`."
1780
+ _ = return_popover("No file exists at #{this_file}.", entry_on_top?)
1781
+ _.popup
1782
+ return
1783
+ end
1784
+ set_the_file_size_from_this_file
1785
+ # ======================================================================= #
1786
+ # Keep track of the song's duration as well.
1787
+ # ======================================================================= #
1788
+ sync_the_duration_of_the_file_onto_the_correct_entry
1789
+ sync_title_onto_entry
1790
+ sync_year_onto_entry
1791
+ sync_artist_onto_entry
1792
+ sync_genre_onto_entry
1793
+ sync_comment_onto_entry
1794
+ set_the_bitrate(
1795
+ MultimediaParadise.bitrate_of_this_song(this_file)
1796
+ )
1797
+ set_the_samplerate(
1798
+ MultimediaParadise.samplerate_of_this_song(this_file)
1799
+ )
1800
+ update_the_MPEG_entry(this_file)
1801
+ end; alias sync_everything set_all_relevant_entries_based_on_the_metadata # === sync_everything
1802
+
1803
+ # ========================================================================= #
1804
+ # === context_menu?
1805
+ # ========================================================================= #
1806
+ def context_menu?
1807
+ @context_menu
1808
+ end
1809
+
1810
+ # ========================================================================= #
1811
+ # === run (run tag)
1812
+ # ========================================================================= #
1813
+ def run
1814
+ create_skeleton_then_connect_skeleton
1815
+ menu # Must come after the skeleton has been created.
1816
+ do_focus_on_the_entry_containing_the_title_of_the_song
1817
+ apply_the_CSS_rules
1818
+ end
1819
+
1820
+ end; end; end; end