multimedia_paradise 1.1.344

Sign up to get free protection for your applications and to get access to all the features.
Files changed (382) hide show
  1. checksums.yaml +7 -0
  2. data/README.md +2720 -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/extract_images_from_this_video_file +7 -0
  10. data/bin/ffmpeg_merge +7 -0
  11. data/bin/file_duration +7 -0
  12. data/bin/gtk_radio +7 -0
  13. data/bin/has_audio +7 -0
  14. data/bin/loop_this_video +7 -0
  15. data/bin/merge_avi_files +7 -0
  16. data/bin/merge_mp3 +7 -0
  17. data/bin/missing_video_files +7 -0
  18. data/bin/movie_searcher +7 -0
  19. data/bin/mp3_to_opus +7 -0
  20. data/bin/mpg_to_mp4 +7 -0
  21. data/bin/mplayer_wrapper +7 -0
  22. data/bin/multimedia_information +11 -0
  23. data/bin/multimedia_paradise +9 -0
  24. data/bin/multimedia_paradise_sinatra +7 -0
  25. data/bin/play_random_simpsons_video +7 -0
  26. data/bin/playlist +7 -0
  27. data/bin/random_video +7 -0
  28. data/bin/remove_audio +9 -0
  29. data/bin/remove_last_second +7 -0
  30. data/bin/remove_subtitles +7 -0
  31. data/bin/reverse_video +7 -0
  32. data/bin/rubio +58 -0
  33. data/bin/tag_mp3_files +7 -0
  34. data/bin/to_aiff +10 -0
  35. data/bin/to_mp4 +7 -0
  36. data/bin/verbose_analyse_this_mp3_file_for_id3_tags +9 -0
  37. data/bin/video_codec +7 -0
  38. data/bin/video_information +8 -0
  39. data/bin/video_player +11 -0
  40. data/bin/video_thumbnail +7 -0
  41. data/bin/video_to_images +7 -0
  42. data/bin/vp9 +9 -0
  43. data/bin/waveform +73 -0
  44. data/doc/CHANGELOG.md +44 -0
  45. data/doc/LINKS.md +6 -0
  46. data/doc/MOTIVATION_FOR_THIS_PROJECT.md +22 -0
  47. data/doc/MergingVideoLectures.md +12 -0
  48. data/doc/README.gen +2658 -0
  49. data/doc/Readme_for_the_cut_audio_component.md +168 -0
  50. data/doc/todo/todo_for_the_GUIs.md +0 -0
  51. data/doc/todo/todo_for_the_multimedia_paradise_project.md +111 -0
  52. data/lib/multimedia_paradise/audio/audio_player/audio_player.rb +1143 -0
  53. data/lib/multimedia_paradise/audio/audio_tag_reader/README.md +7 -0
  54. data/lib/multimedia_paradise/audio/audio_tag_reader/audio_tag_reader.rb +503 -0
  55. data/lib/multimedia_paradise/audio/base.rb +67 -0
  56. data/lib/multimedia_paradise/audio/compress.rb +97 -0
  57. data/lib/multimedia_paradise/audio/create_m3u_playlist.rb +256 -0
  58. data/lib/multimedia_paradise/audio/extract_audio/constants.rb +37 -0
  59. data/lib/multimedia_paradise/audio/extract_audio/extract_audio.rb +417 -0
  60. data/lib/multimedia_paradise/audio/file_duration/constants.rb +53 -0
  61. data/lib/multimedia_paradise/audio/file_duration/file_duration.rb +606 -0
  62. data/lib/multimedia_paradise/audio/genres/boogie.rb +35 -0
  63. data/lib/multimedia_paradise/audio/genres/concerts.rb +35 -0
  64. data/lib/multimedia_paradise/audio/genres/constants.rb +53 -0
  65. data/lib/multimedia_paradise/audio/genres/eurodance.rb +35 -0
  66. data/lib/multimedia_paradise/audio/genres/genre.rb +696 -0
  67. data/lib/multimedia_paradise/audio/genres/hip_hop.rb +35 -0
  68. data/lib/multimedia_paradise/audio/genres/italian_songs.rb +35 -0
  69. data/lib/multimedia_paradise/audio/genres/the_1980s.rb +35 -0
  70. data/lib/multimedia_paradise/audio/genres/trance.rb +35 -0
  71. data/lib/multimedia_paradise/audio/lyrics_fetcher.rb +238 -0
  72. data/lib/multimedia_paradise/audio/merge_audio_files.rb +114 -0
  73. data/lib/multimedia_paradise/audio/modify_year_of_audio_file.rb +136 -0
  74. data/lib/multimedia_paradise/audio/n_audio_songs.rb +208 -0
  75. data/lib/multimedia_paradise/audio/play_all_audio_files.rb +122 -0
  76. data/lib/multimedia_paradise/audio/playlist/playlist.rb +1636 -0
  77. data/lib/multimedia_paradise/audio/remove_audio.rb +98 -0
  78. data/lib/multimedia_paradise/audio/remove_last_second.rb +83 -0
  79. data/lib/multimedia_paradise/audio/report_missing_id.rb +131 -0
  80. data/lib/multimedia_paradise/audio/streamripper/constants.rb +51 -0
  81. data/lib/multimedia_paradise/audio/streamripper/streamripper_wrapper.rb +279 -0
  82. data/lib/multimedia_paradise/audio/to_mp3.rb +138 -0
  83. data/lib/multimedia_paradise/audio/to_ogg.rb +104 -0
  84. data/lib/multimedia_paradise/audio/wav_to_mp3.rb +87 -0
  85. data/lib/multimedia_paradise/audio/waveform/class.rb +341 -0
  86. data/lib/multimedia_paradise/audio/waveform/constants.rb +38 -0
  87. data/lib/multimedia_paradise/audio/waveform/log.rb +101 -0
  88. data/lib/multimedia_paradise/autoinclude.rb +3 -0
  89. data/lib/multimedia_paradise/autoinclude_remove_audio.rb +6 -0
  90. data/lib/multimedia_paradise/base/base.rb +34 -0
  91. data/lib/multimedia_paradise/base/colours.rb +391 -0
  92. data/lib/multimedia_paradise/base/commandline_arguments.rb +60 -0
  93. data/lib/multimedia_paradise/base/constants.rb +19 -0
  94. data/lib/multimedia_paradise/base/encoding.rb +31 -0
  95. data/lib/multimedia_paradise/base/misc.rb +665 -0
  96. data/lib/multimedia_paradise/base/namespace.rb +36 -0
  97. data/lib/multimedia_paradise/base/time.rb +25 -0
  98. data/lib/multimedia_paradise/colours/colours.rb +89 -0
  99. data/lib/multimedia_paradise/commandline/menu.rb +463 -0
  100. data/lib/multimedia_paradise/configuration/play_zoomed.yml +1 -0
  101. data/lib/multimedia_paradise/constants/constants.rb +23 -0
  102. data/lib/multimedia_paradise/constants/conversions.rb +62 -0
  103. data/lib/multimedia_paradise/constants/directory_constants.rb +139 -0
  104. data/lib/multimedia_paradise/constants/encodings.rb +26 -0
  105. data/lib/multimedia_paradise/constants/file_constants.rb +176 -0
  106. data/lib/multimedia_paradise/constants/misc.rb +80 -0
  107. data/lib/multimedia_paradise/constants/my_video_directory.rb +30 -0
  108. data/lib/multimedia_paradise/constants/namespace.rb +14 -0
  109. data/lib/multimedia_paradise/constants/newline.rb +14 -0
  110. data/lib/multimedia_paradise/constants/video_filetypes.rb +27 -0
  111. data/lib/multimedia_paradise/constants/web_constants.rb +150 -0
  112. data/lib/multimedia_paradise/conversions/README.md +2 -0
  113. data/lib/multimedia_paradise/conversions/conversions.rb +930 -0
  114. data/lib/multimedia_paradise/css/project.css +15 -0
  115. data/lib/multimedia_paradise/data/asoundrc +12 -0
  116. data/lib/multimedia_paradise/ffmpeg/README.md +2 -0
  117. data/lib/multimedia_paradise/ffmpeg/ffmpeg.rb +620 -0
  118. data/lib/multimedia_paradise/gui/fox/play_from_radio_station.rb +75 -0
  119. data/lib/multimedia_paradise/gui/glimmer/rubio/model/bookmark.rb +61 -0
  120. data/lib/multimedia_paradise/gui/glimmer/rubio/model/player.rb +226 -0
  121. data/lib/multimedia_paradise/gui/glimmer/rubio/model/radio_browser.rb +57 -0
  122. data/lib/multimedia_paradise/gui/glimmer/rubio/model/radio_presenter.rb +132 -0
  123. data/lib/multimedia_paradise/gui/glimmer/rubio/model/station.rb +48 -0
  124. data/lib/multimedia_paradise/gui/glimmer/rubio/view/radio.rb +296 -0
  125. data/lib/multimedia_paradise/gui/gosu/video_player/video_player.rb +109 -0
  126. data/lib/multimedia_paradise/gui/gtk2/multimedia_converter/multimedia_converter.rb +33 -0
  127. data/lib/multimedia_paradise/gui/gtk2/notebook.rb +144 -0
  128. data/lib/multimedia_paradise/gui/gtk2/play_video_from_my_collection/play_video_from_my_collection.rb +43 -0
  129. data/lib/multimedia_paradise/gui/gtk2/simple_play_widget/README.md +12 -0
  130. data/lib/multimedia_paradise/gui/gtk2/simple_play_widget/simple_play_widget.rb +40 -0
  131. data/lib/multimedia_paradise/gui/gtk2/widget_increase_or_decrease_audio/widget_increase_or_decrease_audio.rb +42 -0
  132. data/lib/multimedia_paradise/gui/gtk2/youtube_downloader/youtube_downloader.rb +32 -0
  133. data/lib/multimedia_paradise/gui/gtk3/lyrics/lyrics.rb +0 -0
  134. data/lib/multimedia_paradise/gui/gtk3/multimedia_converter/multimedia_converter.rb +34 -0
  135. data/lib/multimedia_paradise/gui/gtk3/multimedia_notebook/multimedia_notebook.rb +34 -0
  136. data/lib/multimedia_paradise/gui/gtk3/play_video_from_my_collection/play_video_from_my_collection.rb +34 -0
  137. data/lib/multimedia_paradise/gui/gtk3/playlist/playlist.rb +34 -0
  138. data/lib/multimedia_paradise/gui/gtk3/simple_play_widget/simple_play_widget.rb +38 -0
  139. data/lib/multimedia_paradise/gui/gtk3/video_editor/video_editor.rb +34 -0
  140. data/lib/multimedia_paradise/gui/gtk3/video_player/video_player.rb +34 -0
  141. data/lib/multimedia_paradise/gui/gtk3/webcam_widget/webcam_widget.rb +425 -0
  142. data/lib/multimedia_paradise/gui/gtk3/widget_increase_or_decrease_audio/widget_increase_or_decrease_audio.rb +36 -0
  143. data/lib/multimedia_paradise/gui/gtk3/youtube_channels/youtube_channels.rb +210 -0
  144. data/lib/multimedia_paradise/gui/gtk3/youtube_downloader/youtube_downloader.rb +32 -0
  145. data/lib/multimedia_paradise/gui/gui_base.rb +92 -0
  146. data/lib/multimedia_paradise/gui/libui/change_metadata_widget/change_metadata_widget.rb +115 -0
  147. data/lib/multimedia_paradise/gui/libui/cut_multimedia/cut_multimedia.rb +119 -0
  148. data/lib/multimedia_paradise/gui/libui/lyrics/lyrics.rb +67 -0
  149. data/lib/multimedia_paradise/gui/libui/simple_play_widget/simple_play_widget.rb +119 -0
  150. data/lib/multimedia_paradise/gui/libui/video_player/video_player.rb +81 -0
  151. data/lib/multimedia_paradise/gui/libui/widget_increase_or_decrease_audio/widget_increase_or_decrease_audio.rb +126 -0
  152. data/lib/multimedia_paradise/gui/libui/youtube_channels/youtube_channels.rb +116 -0
  153. data/lib/multimedia_paradise/gui/libui/youtube_downloader/youtube_downloader.rb +107 -0
  154. data/lib/multimedia_paradise/gui/shared_code/lyrics/lyrics_module.rb +0 -0
  155. data/lib/multimedia_paradise/gui/shared_code/multimedia_converter/multimedia_converter_module.rb +478 -0
  156. data/lib/multimedia_paradise/gui/shared_code/multimedia_notebook/multimedia_notebook_module.rb +171 -0
  157. data/lib/multimedia_paradise/gui/shared_code/play_video_from_my_collection/play_video_from_my_collection_module.rb +464 -0
  158. data/lib/multimedia_paradise/gui/shared_code/playlist/playlist_module.rb +151 -0
  159. data/lib/multimedia_paradise/gui/shared_code/simple_play_widget/simple_play_widget_module.rb +257 -0
  160. data/lib/multimedia_paradise/gui/shared_code/sound_effect_widget/sound_effect_widget_module.rb +0 -0
  161. data/lib/multimedia_paradise/gui/shared_code/video_editor/video_editor_module.rb +287 -0
  162. data/lib/multimedia_paradise/gui/shared_code/video_player/video_player_module.rb +185 -0
  163. data/lib/multimedia_paradise/gui/shared_code/widget_increase_or_decrease_audio/widget_increase_or_decrease_audio_module.rb +310 -0
  164. data/lib/multimedia_paradise/gui/shared_code/youtube_downloader/youtube_downloader_module.rb +339 -0
  165. data/lib/multimedia_paradise/gui/tk/tk_multimedia_wrapper.rb +60 -0
  166. data/lib/multimedia_paradise/gui/universal_widgets/change_metadata_widget/README.md +3 -0
  167. data/lib/multimedia_paradise/gui/universal_widgets/change_metadata_widget/change_metadata_widget.rb +751 -0
  168. data/lib/multimedia_paradise/gui/universal_widgets/cut_multimedia/cut_multimedia.rb +657 -0
  169. data/lib/multimedia_paradise/gui/universal_widgets/information_about_a_mp3_file/information_about_a_mp3_file.rb +597 -0
  170. data/lib/multimedia_paradise/gui/universal_widgets/lyrics/lyrics.rb +265 -0
  171. data/lib/multimedia_paradise/gui/universal_widgets/radio/radio.rb +1364 -0
  172. data/lib/multimedia_paradise/gui/universal_widgets/sound_effect_widget/sound_effect_widget.rb +265 -0
  173. data/lib/multimedia_paradise/gui/universal_widgets/tag_mp3_files/tag_mp3_files.config +6 -0
  174. data/lib/multimedia_paradise/gui/universal_widgets/tag_mp3_files/tag_mp3_files.rb +2429 -0
  175. data/lib/multimedia_paradise/gui/universal_widgets/video_collection/video_collection.rb +246 -0
  176. data/lib/multimedia_paradise/help/help.rb +75 -0
  177. data/lib/multimedia_paradise/images/MULTIMEDIA.jpg +0 -0
  178. data/lib/multimedia_paradise/images/MULTIMEDIA_PARADISE_ID_TAG_GUI_IN_RUBY_GTK3.png +0 -0
  179. data/lib/multimedia_paradise/images/MULTIMEDIA_PARADISE_LOGO.png +0 -0
  180. data/lib/multimedia_paradise/images/UK_flag.png +0 -0
  181. data/lib/multimedia_paradise/images/US_flag.png +0 -0
  182. data/lib/multimedia_paradise/images/austrian_flag.png +0 -0
  183. data/lib/multimedia_paradise/images/french_flag.png +0 -0
  184. data/lib/multimedia_paradise/images/german_flag.png +0 -0
  185. data/lib/multimedia_paradise/images/radio_image.png +0 -0
  186. data/lib/multimedia_paradise/images/trance.png +0 -0
  187. data/lib/multimedia_paradise/java/AudioPlayer.class +0 -0
  188. data/lib/multimedia_paradise/java/AudioPlayer.java +103 -0
  189. data/lib/multimedia_paradise/java/README.md +3 -0
  190. data/lib/multimedia_paradise/misc/long_format_to_milliseconds_converter.rb +182 -0
  191. data/lib/multimedia_paradise/misc/milliseconds_to_long_format_converter.rb +186 -0
  192. data/lib/multimedia_paradise/multimedia/analyse_multimedia_file.rb +180 -0
  193. data/lib/multimedia_paradise/multimedia/avisynth/README.md +4 -0
  194. data/lib/multimedia_paradise/multimedia/avisynth/avisynth_code.avs +471 -0
  195. data/lib/multimedia_paradise/multimedia/base.rb +60 -0
  196. data/lib/multimedia_paradise/multimedia/chord.rb +174 -0
  197. data/lib/multimedia_paradise/multimedia/convert_audio_to_video_with_image.rb +171 -0
  198. data/lib/multimedia_paradise/multimedia/cut_multimedia/10_minutes_chop.rb +29 -0
  199. data/lib/multimedia_paradise/multimedia/cut_multimedia/15_minutes_chop.rb +29 -0
  200. data/lib/multimedia_paradise/multimedia/cut_multimedia/30_minutes_chop.rb +29 -0
  201. data/lib/multimedia_paradise/multimedia/cut_multimedia/5_minutes_chop.rb +29 -0
  202. data/lib/multimedia_paradise/multimedia/cut_multimedia/cut_multimedia.rb +2021 -0
  203. data/lib/multimedia_paradise/multimedia/cut_multimedia/evaluate_from_this_file.rb +79 -0
  204. data/lib/multimedia_paradise/multimedia/cut_multimedia/interactive_menu.rb +525 -0
  205. data/lib/multimedia_paradise/multimedia/interactive_shell.rb +84 -0
  206. data/lib/multimedia_paradise/multimedia/merge_multimedia.rb +127 -0
  207. data/lib/multimedia_paradise/multimedia/note.rb +500 -0
  208. data/lib/multimedia_paradise/multimedia/play_from_this_list.rb +163 -0
  209. data/lib/multimedia_paradise/multimedia/read_meta_tags.rb +173 -0
  210. data/lib/multimedia_paradise/multimedia/simulate_youtube_playlist.rb +209 -0
  211. data/lib/multimedia_paradise/multimedia/start_length_duration.rb +205 -0
  212. data/lib/multimedia_paradise/multimedia/video_downloader/video_downloader.rb +135 -0
  213. data/lib/multimedia_paradise/project/project.rb +47 -0
  214. data/lib/multimedia_paradise/requires/require_audio_files.rb +74 -0
  215. data/lib/multimedia_paradise/requires/require_cut_multimedia.rb +7 -0
  216. data/lib/multimedia_paradise/requires/require_extract_audio.rb +7 -0
  217. data/lib/multimedia_paradise/requires/require_file_duration.rb +7 -0
  218. data/lib/multimedia_paradise/requires/require_streamripper.rb +7 -0
  219. data/lib/multimedia_paradise/requires/require_the_audio_player.rb +7 -0
  220. data/lib/multimedia_paradise/requires/require_the_multimedia_paradise_project.rb +38 -0
  221. data/lib/multimedia_paradise/requires/require_the_sinatra_components.rb +7 -0
  222. data/lib/multimedia_paradise/requires/require_toplevel_methods_files.rb +25 -0
  223. data/lib/multimedia_paradise/requires/require_video_files.rb +25 -0
  224. data/lib/multimedia_paradise/requires/require_video_player.rb +7 -0
  225. data/lib/multimedia_paradise/sinatra/app.rb +318 -0
  226. data/lib/multimedia_paradise/sinatra/embeddable_interface.rb +379 -0
  227. data/lib/multimedia_paradise/sound_effects/README.md +12 -0
  228. data/lib/multimedia_paradise/sound_effects/cat_meow.mp3 +0 -0
  229. data/lib/multimedia_paradise/sound_effects/channel_opened.mp3 +0 -0
  230. data/lib/multimedia_paradise/sound_effects/phone_ring.mp3 +0 -0
  231. data/lib/multimedia_paradise/statistics/README.md +5 -0
  232. data/lib/multimedia_paradise/statistics/video.rb +84 -0
  233. data/lib/multimedia_paradise/toplevel_cut_audio.rb +16 -0
  234. data/lib/multimedia_paradise/toplevel_methods/analyze_audio_stream.rb +31 -0
  235. data/lib/multimedia_paradise/toplevel_methods/chop_into_segments_of_n_seconds_size.rb +32 -0
  236. data/lib/multimedia_paradise/toplevel_methods/chop_off_first_five_minutes.rb +22 -0
  237. data/lib/multimedia_paradise/toplevel_methods/chop_off_first_n_seconds.rb +92 -0
  238. data/lib/multimedia_paradise/toplevel_methods/chop_off_first_ten_minutes.rb +22 -0
  239. data/lib/multimedia_paradise/toplevel_methods/chop_off_first_two_minutes.rb +24 -0
  240. data/lib/multimedia_paradise/toplevel_methods/codecs.rb +50 -0
  241. data/lib/multimedia_paradise/toplevel_methods/copy_and_merge_this_video_n_times.rb +51 -0
  242. data/lib/multimedia_paradise/toplevel_methods/copy_file.rb +18 -0
  243. data/lib/multimedia_paradise/toplevel_methods/create_video_from_this_audio.rb +65 -0
  244. data/lib/multimedia_paradise/toplevel_methods/cut_from_to.rb +156 -0
  245. data/lib/multimedia_paradise/toplevel_methods/delay_audio.rb +31 -0
  246. data/lib/multimedia_paradise/toplevel_methods/denoise.rb +90 -0
  247. data/lib/multimedia_paradise/toplevel_methods/deshake.rb +43 -0
  248. data/lib/multimedia_paradise/toplevel_methods/e.rb +16 -0
  249. data/lib/multimedia_paradise/toplevel_methods/encode_this_video.rb +49 -0
  250. data/lib/multimedia_paradise/toplevel_methods/ensure_that_the_output_directory_exists.rb +27 -0
  251. data/lib/multimedia_paradise/toplevel_methods/esystem.rb +43 -0
  252. data/lib/multimedia_paradise/toplevel_methods/files_and_directories.rb +92 -0
  253. data/lib/multimedia_paradise/toplevel_methods/flip_and_rotate.rb +58 -0
  254. data/lib/multimedia_paradise/toplevel_methods/has_audio.rb +48 -0
  255. data/lib/multimedia_paradise/toplevel_methods/increase_volume_of_this_audio_file.rb +61 -0
  256. data/lib/multimedia_paradise/toplevel_methods/is_a_multimedia_file.rb +27 -0
  257. data/lib/multimedia_paradise/toplevel_methods/is_audio_file.rb +27 -0
  258. data/lib/multimedia_paradise/toplevel_methods/is_image_file.rb +31 -0
  259. data/lib/multimedia_paradise/toplevel_methods/is_on_roebe.rb +17 -0
  260. data/lib/multimedia_paradise/toplevel_methods/is_video_file.rb +62 -0
  261. data/lib/multimedia_paradise/toplevel_methods/merge_multimedia_file.rb +331 -0
  262. data/lib/multimedia_paradise/toplevel_methods/merge_these_videos.rb +106 -0
  263. data/lib/multimedia_paradise/toplevel_methods/misc.rb +964 -0
  264. data/lib/multimedia_paradise/toplevel_methods/opn.rb +24 -0
  265. data/lib/multimedia_paradise/toplevel_methods/output_directory.rb +61 -0
  266. data/lib/multimedia_paradise/toplevel_methods/player_in_use.rb +80 -0
  267. data/lib/multimedia_paradise/toplevel_methods/query_the_audio_codec_of_this_file.rb +24 -0
  268. data/lib/multimedia_paradise/toplevel_methods/radio.rb +381 -0
  269. data/lib/multimedia_paradise/toplevel_methods/rds.rb +24 -0
  270. data/lib/multimedia_paradise/toplevel_methods/return_all_video_files.rb +64 -0
  271. data/lib/multimedia_paradise/toplevel_methods/return_data_from_video_collection_file_for_this_entry.rb +38 -0
  272. data/lib/multimedia_paradise/toplevel_methods/return_duration_of_this_multimedia_file.rb +27 -0
  273. data/lib/multimedia_paradise/toplevel_methods/return_full_name_for_video_at_this_position.rb +54 -0
  274. data/lib/multimedia_paradise/toplevel_methods/return_path_to_random_simpsons_video_file.rb +43 -0
  275. data/lib/multimedia_paradise/toplevel_methods/return_random_video_file_from_the_video_collection.rb +73 -0
  276. data/lib/multimedia_paradise/toplevel_methods/return_screen_resolution.rb +24 -0
  277. data/lib/multimedia_paradise/toplevel_methods/run_sys_command.rb +30 -0
  278. data/lib/multimedia_paradise/toplevel_methods/scale_video.rb +27 -0
  279. data/lib/multimedia_paradise/toplevel_methods/set_title_of.rb +65 -0
  280. data/lib/multimedia_paradise/toplevel_methods/slow_down_this_video_file.rb +33 -0
  281. data/lib/multimedia_paradise/toplevel_methods/start_screencast.rb +70 -0
  282. data/lib/multimedia_paradise/toplevel_methods/subtitles.rb +59 -0
  283. data/lib/multimedia_paradise/toplevel_methods/to_flac.rb +30 -0
  284. data/lib/multimedia_paradise/toplevel_methods/to_mp4.rb +24 -0
  285. data/lib/multimedia_paradise/toplevel_methods/total_duration.rb +35 -0
  286. data/lib/multimedia_paradise/toplevel_methods/use_lame_codec.rb +32 -0
  287. data/lib/multimedia_paradise/toplevel_methods/video_dataset.rb +76 -0
  288. data/lib/multimedia_paradise/version/version.rb +28 -0
  289. data/lib/multimedia_paradise/video/all_videos.rb +101 -0
  290. data/lib/multimedia_paradise/video/capture_screen.rb +285 -0
  291. data/lib/multimedia_paradise/video/check_numbers.rb +215 -0
  292. data/lib/multimedia_paradise/video/columbo/columbo.rb +139 -0
  293. data/lib/multimedia_paradise/video/copy_missing_video_files.rb +292 -0
  294. data/lib/multimedia_paradise/video/copy_random_video.rb +98 -0
  295. data/lib/multimedia_paradise/video/correct_video_numbers.rb +263 -0
  296. data/lib/multimedia_paradise/video/create_dvd.rb +50 -0
  297. data/lib/multimedia_paradise/video/create_video_thumbnails.rb +137 -0
  298. data/lib/multimedia_paradise/video/encode_video.rb +81 -0
  299. data/lib/multimedia_paradise/video/ffmpeg_options.rb +156 -0
  300. data/lib/multimedia_paradise/video/find_video/find_video.rb +668 -0
  301. data/lib/multimedia_paradise/video/fix_married_with_children_videos.rb +70 -0
  302. data/lib/multimedia_paradise/video/genres.rb +333 -0
  303. data/lib/multimedia_paradise/video/guess_video_name.rb +189 -0
  304. data/lib/multimedia_paradise/video/imdb_rating/imdb_rating.rb +133 -0
  305. data/lib/multimedia_paradise/video/mike_hammer/mike_hammer.rb +74 -0
  306. data/lib/multimedia_paradise/video/missing_video_files/missing_video_files.rb +286 -0
  307. data/lib/multimedia_paradise/video/movie_searcher.rb +281 -0
  308. data/lib/multimedia_paradise/video/mplayer_wrapper.rb +504 -0
  309. data/lib/multimedia_paradise/video/n_videos.rb +142 -0
  310. data/lib/multimedia_paradise/video/play_random_file.rb +91 -0
  311. data/lib/multimedia_paradise/video/play_random_realvideo.rb +92 -0
  312. data/lib/multimedia_paradise/video/prepare_video_lecture.rb +267 -0
  313. data/lib/multimedia_paradise/video/random_video.rb +302 -0
  314. data/lib/multimedia_paradise/video/registered_video_file.rb +131 -0
  315. data/lib/multimedia_paradise/video/remove_metadata.rb +52 -0
  316. data/lib/multimedia_paradise/video/rename_video_file.rb +149 -0
  317. data/lib/multimedia_paradise/video/report_local_videos.rb +106 -0
  318. data/lib/multimedia_paradise/video/report_missing_videos_in_the_yaml_file.rb +107 -0
  319. data/lib/multimedia_paradise/video/resolution.rb +194 -0
  320. data/lib/multimedia_paradise/video/reverse_video.rb +74 -0
  321. data/lib/multimedia_paradise/video/simpsons.rb +129 -0
  322. data/lib/multimedia_paradise/video/smart_animals/smart_animals.rb +188 -0
  323. data/lib/multimedia_paradise/video/speed_up_video.rb +135 -0
  324. data/lib/multimedia_paradise/video/split_this_video.rb +126 -0
  325. data/lib/multimedia_paradise/video/srt_regex.rb +211 -0
  326. data/lib/multimedia_paradise/video/store_available_video_files.rb +138 -0
  327. data/lib/multimedia_paradise/video/the_simpsons/README.md +9 -0
  328. data/lib/multimedia_paradise/video/the_simpsons/good_the_simpsons_episodes.rb +107 -0
  329. data/lib/multimedia_paradise/video/the_simpsons/the_simpsons.rb +87 -0
  330. data/lib/multimedia_paradise/video/video.rb +14 -0
  331. data/lib/multimedia_paradise/video/video_encoding_settings.rb +57 -0
  332. data/lib/multimedia_paradise/video/video_information.rb +445 -0
  333. data/lib/multimedia_paradise/video/video_metadata.rb +132 -0
  334. data/lib/multimedia_paradise/video/video_player.rb +580 -0
  335. data/lib/multimedia_paradise/video/video_renamer.rb +161 -0
  336. data/lib/multimedia_paradise/video/watermark.rb +282 -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/yaml/audio_formats.yml +14 -0
  340. data/lib/multimedia_paradise/yaml/best_songs_in_an_era/eurodance/top20.yml +28 -0
  341. data/lib/multimedia_paradise/yaml/game_shows/ruck_zuck/ruck_zuck.yml +25 -0
  342. data/lib/multimedia_paradise/yaml/genres/1980s.yml +198 -0
  343. data/lib/multimedia_paradise/yaml/genres/README.md +5 -0
  344. data/lib/multimedia_paradise/yaml/genres/boogie.yml +68 -0
  345. data/lib/multimedia_paradise/yaml/genres/concerts.yml +29 -0
  346. data/lib/multimedia_paradise/yaml/genres/eurodance.yml +456 -0
  347. data/lib/multimedia_paradise/yaml/genres/hip_hop.yml +49 -0
  348. data/lib/multimedia_paradise/yaml/genres/italian_songs.yml +53 -0
  349. data/lib/multimedia_paradise/yaml/genres/trance.yml +167 -0
  350. data/lib/multimedia_paradise/yaml/good_horror_movies/good_horror_movies.yml +12 -0
  351. data/lib/multimedia_paradise/yaml/good_movie_actors/good_movie_actors.yml +6 -0
  352. data/lib/multimedia_paradise/yaml/image_formats.yml +8 -0
  353. data/lib/multimedia_paradise/yaml/internal/README.md +2 -0
  354. data/lib/multimedia_paradise/yaml/internal/installed_binaries.yml +31 -0
  355. data/lib/multimedia_paradise/yaml/lyrics.yml +6323 -0
  356. data/lib/multimedia_paradise/yaml/movie_reviews/the_hateful_eight_september_2016.md +305 -0
  357. data/lib/multimedia_paradise/yaml/music_genres.yml +51 -0
  358. data/lib/multimedia_paradise/yaml/playlist.yml +130 -0
  359. data/lib/multimedia_paradise/yaml/radio/README.md +5 -0
  360. data/lib/multimedia_paradise/yaml/radio/radio_stations.yml +359 -0
  361. data/lib/multimedia_paradise/yaml/song_tags.yml +818 -0
  362. data/lib/multimedia_paradise/yaml/tales_from_the_crypt/tales_from_the_crypt.yml +426 -0
  363. data/lib/multimedia_paradise/yaml/tom_and_jerry/README.md +2 -0
  364. data/lib/multimedia_paradise/yaml/tom_and_jerry/tom_and_jerry_episodes.yml +27 -0
  365. data/lib/multimedia_paradise/yaml/tv_channels/tv_channels.yml +46 -0
  366. data/lib/multimedia_paradise/yaml/use_this_video_player.yml +1 -0
  367. data/lib/multimedia_paradise/yaml/video/video.yml +26 -0
  368. data/lib/multimedia_paradise/yaml/video_collection/video_collection.yml +1933 -0
  369. data/lib/multimedia_paradise/yaml/video_encoding_settings.yml +62 -0
  370. data/lib/multimedia_paradise/yaml/video_filter_aliases.yml +221 -0
  371. data/lib/multimedia_paradise/yaml/youtube/alltagsgeschichte/alltagsgeschichte.yml +190 -0
  372. data/lib/multimedia_paradise/yaml/youtube/songs/README.md +3 -0
  373. data/lib/multimedia_paradise/yaml/youtube/songs/songs.yml +6 -0
  374. data/lib/multimedia_paradise/yaml/youtube_playlist/youtube_playlist.yml +6 -0
  375. data/lib/multimedia_paradise.rb +5 -0
  376. data/multimedia_paradise.gemspec +74 -0
  377. data/test/testing_audio_player.rb +15 -0
  378. data/test/testing_ffmpeg_options.rb +14 -0
  379. data/test/testing_file_duration.rb +17 -0
  380. data/test/testing_modify_year_of_audio_file.rb +14 -0
  381. data/test/testing_multimedia_paradise_project.rb +151 -0
  382. metadata +560 -0
@@ -0,0 +1,964 @@
1
+ #!/usr/bin/ruby -w
2
+ # Encoding: UTF-8
3
+ # frozen_string_literal: true
4
+ # =========================================================================== #
5
+ # require 'multimedia_paradise/toplevel_methods/misc.rb'
6
+ # MultimediaParadise.extract_images_from_this_video_file
7
+ # MultimediaParadise.bitrate_of_this_song
8
+ # MultimediaParadise.verbose_analyse_this_mp3_file_for_id3_tags
9
+ # MultimediaParadise.return_video_codec_of_this_file
10
+ # MultimediaParadise.mpg_to_mp4
11
+ # =========================================================================== #
12
+ module MultimediaParadise
13
+
14
+ require 'multimedia_paradise/constants/misc.rb'
15
+ require 'multimedia_paradise/toplevel_methods/esystem.rb'
16
+ require 'multimedia_paradise/ffmpeg/ffmpeg.rb'
17
+
18
+ # ========================================================================= #
19
+ # === MultimediaParadise.return_all_video_files_from_the_current_directory
20
+ # ========================================================================= #
21
+ def self.return_all_video_files_from_the_current_directory
22
+ Dir['**'].select {|entry| is_a_video_file?(entry) }
23
+ end
24
+
25
+ # ========================================================================= #
26
+ # === MultimediaParadise.automatically_create_a_thumbnail_for_this_video
27
+ # ========================================================================= #
28
+ def self.automatically_create_a_thumbnail_for_this_video(
29
+ this_video,
30
+ output_file = :infer
31
+ )
32
+ result = []
33
+ [this_video].flatten.compact.each {|this_video_file|
34
+ case output_file
35
+ # ===================================================================== #
36
+ # === :infer
37
+ # ===================================================================== #
38
+ when :infer
39
+ output_file = 'thumbnail_for_'+
40
+ File.basename(this_video_file).
41
+ delete_suffix(File.extname(this_video_file))+'.png'
42
+ end
43
+ _ = "ffmpeg -i #{this_video_file} -vf \"thumbnail=150\" -frames:v 1 -y #{output_file}"
44
+ e
45
+ esystem(_)
46
+ e
47
+ result << output_file
48
+ }
49
+ return result
50
+ end; self.instance_eval { alias thumbnail automatically_create_a_thumbnail_for_this_video } # === MultimediaParadise.thumbnail
51
+
52
+ # ========================================================================= #
53
+ # === MultimediaParadise.mpg_to_mp4
54
+ #
55
+ # This is an opinionated method.
56
+ #
57
+ # You have to pass the filename to this method, in order to convert
58
+ # the .mpg files into .mp4 files.
59
+ # ========================================================================= #
60
+ def self.mpg_to_mp4(*i)
61
+ # ======================================================================= #
62
+ # Going with crf 26 - that seems to be a bit better than 25, actually.
63
+ # ======================================================================= #
64
+ crf_value_to_use = '26' # 25-28 should suffice; lower value means higher quality and larger file size.
65
+ result = []
66
+ i.flatten.each {|this_file|
67
+ this_file = File.absolute_path(this_file)
68
+ output_file = File.dirname(this_file)+'/'+
69
+ 'output_'+
70
+ File.basename(this_file).
71
+ delete_suffix(
72
+ File.extname(this_file)
73
+ )+'.mp4'
74
+ _ = 'ffmpeg -i '+this_file.to_s+' -c:v libx265 -c:a libmp3lame '\
75
+ '-crf '+crf_value_to_use.to_s+' '\
76
+ '-preset:v veryslow '+
77
+ output_file
78
+ e
79
+ esystem _
80
+ e
81
+ result << File.absolute_path(output_file)
82
+ }
83
+ result # We must return the output files here.
84
+ end
85
+
86
+ # ========================================================================= #
87
+ # === MultimediaParadise.extract_images_from_this_video_file
88
+ #
89
+ # This variant uses 1 image per 1 second by default. If we'd omit this,
90
+ # then the default rate would be 25 images per second.
91
+ #
92
+ # Usage examples:
93
+ #
94
+ # MultimediaParadise.extract_images_from_this_video_file('foobar.mp4')
95
+ # MultimediaParadise.extract_images_from_this_video_file('100_0002.mov')
96
+ #
97
+ # ========================================================================= #
98
+ def self.extract_images_from_this_video_file(
99
+ i = '*mov',
100
+ time_interval = 1 # This means "1 image per 1 second".
101
+ )
102
+ result = []
103
+ [i].flatten.compact.each {|this_file|
104
+ _ = "ffmpeg -i #{this_file} "\
105
+ "-vf fps=#{time_interval} "\
106
+ "out%d.png"
107
+ esystem(_)
108
+ all_files_created = Dir['out*.png']
109
+ result << all_files_created
110
+ }
111
+ return result
112
+ end
113
+
114
+ # ========================================================================= #
115
+ # === MultimediaParadise.return_video_codec_of_this_file
116
+ #
117
+ # This method will use ffmpeg's ffprobe and return the video codec of the
118
+ # given file at hand.
119
+ # ========================================================================= #
120
+ def self.return_video_codec_of_this_file(
121
+ i = ARGV
122
+ )
123
+ if i
124
+ result = []
125
+ [i].flatten.each {|this_file|
126
+ cmd = "ffprobe -v error -select_streams v:0 "\
127
+ "-show_entries stream=codec_name -of default=noprint_wrappers=1:nokey=1 #{this_file}"
128
+ result_of_the_command = `#{cmd}`
129
+ result << result_of_the_command
130
+ }
131
+ return result
132
+ end
133
+ return nil
134
+ end; self.instance_eval { alias video_codec return_video_codec_of_this_file } # === MultimediaParadise.video_codec
135
+ self.instance_eval { alias video_codec? return_video_codec_of_this_file } # === MultimediaParadise.video_codec?
136
+
137
+ # ========================================================================= #
138
+ # === MultimediaParadise.return_the_mpeg_layer_from_this_mp3_file
139
+ #
140
+ # This method will make use of the binary called "mpg123".
141
+ # ========================================================================= #
142
+ def self.return_the_mpeg_layer_from_this_mp3_file(i)
143
+ cmd = "mpg123 -t #{i} 2>&1"
144
+ result = `#{cmd}`
145
+ splitted = result.split("\n")
146
+ selected = splitted.select {|line|
147
+ line.start_with? 'MPEG ' # Obtain the MPEG layer here.
148
+ }.uniq
149
+ result = selected.first # Pick the first result here.
150
+ # ======================================================================= #
151
+ # We may have to clean up that result a little bit still.
152
+ # ======================================================================= #
153
+ if result and result.include?(' ') and result.include?('III')
154
+ result = result[0 .. (result.index('III')+2)]
155
+ end
156
+ return result
157
+ end
158
+
159
+ # ========================================================================= #
160
+ # === MultimediaParadise.loop_this_video
161
+ #
162
+ # This method can be used to loop a video, via ffmpeg.
163
+ #
164
+ # A commandline variant for this would look as follows:
165
+ #
166
+ # ffmpeg -stream_loop 3 -i Tata.webm -c copy output.webm
167
+ #
168
+ # ========================================================================= #
169
+ def self.loop_this_video(this_video = 'foobar.webm', n_times = '5x')
170
+ result = []
171
+ [this_video].flatten.compact.each {|work_on_this_video_file|
172
+ n_times = n_times.to_s.delete('x').sub(/ times/,'')
173
+ output_file = "output_#{work_on_this_video_file}"
174
+ result << output_file
175
+ cmd = "ffmpeg -stream_loop #{n_times} -i #{work_on_this_video_file} -c copy #{output_file}"
176
+ esystem cmd
177
+ }
178
+ return result
179
+ end
180
+
181
+ # ========================================================================= #
182
+ # === MultimediaParadise.bin_dir?
183
+ # ========================================================================= #
184
+ def self.bin_dir?
185
+ RbConfig::CONFIG['bindir'].to_s+'/' # Ensure trailing '/'.
186
+ end; self.instance_eval { alias bindir? bin_dir? } # === MultimediaParadise.bindir?
187
+
188
+ # ========================================================================= #
189
+ # === MultimediaParadise.copy_bin_directory
190
+ #
191
+ # This method can be used to copy the content of the bin/ directory
192
+ # onto the current working directory.
193
+ #
194
+ # Usage example from within ruby code:
195
+ #
196
+ # require 'multimedia_paradise'; MultimediaParadise.copy_bin_directory
197
+ #
198
+ # ========================================================================= #
199
+ def self.copy_bin_directory
200
+ file_installed_binaries = "#{MultimediaParadise.project_base_directory?}"\
201
+ "yaml/internal/installed_binaries.yml"
202
+ mkdir('bin/')
203
+ cd('bin/')
204
+ if File.exist? file_installed_binaries
205
+ e 'Making use of the file '+sfile(file_installed_binaries)+'.'
206
+ install_these_binaries = YAML.load_file(file_installed_binaries)
207
+ installation_directory = `gem env`.split("\n").select {|line| # Check for INSTALLATION DIRECTORY: /root/.gem
208
+ line.include? 'INSTALLATION DIRECTORY:'
209
+ }.first.
210
+ scan(/INSTALLATION DIRECTORY: (.+)$/).flatten.first
211
+ install_these_binaries.each {|entry|
212
+ target = installation_directory+'/bin/'+entry
213
+ if File.exist? target
214
+ e "Copying the file #{target} into the current working "\
215
+ "directory next."
216
+ copy_file(target, Dir.pwd)
217
+ else
218
+ # ================================================================= #
219
+ # Since as of January 2023 first try the bin_dir, before giving up.
220
+ # ================================================================= #
221
+ target = MultimediaParadise.bin_dir?+File.basename(entry)
222
+ if File.exist? target
223
+ e "Copying the file #{target} into the current working "\
224
+ "directory next."
225
+ copy_file(target, Dir.pwd)
226
+ else
227
+ no_file_exists_at(target)
228
+ end
229
+ end
230
+ }
231
+ end
232
+ end
233
+
234
+ # ========================================================================= #
235
+ # === MultimediaParadise.to_gif
236
+ #
237
+ # This method can be used to quickly turn an .avi file or a .mp4
238
+ # file into an animated .gif.
239
+ #
240
+ # The quality is pretty low, so this is not ideal, but if you
241
+ # have a use case for animated .gif files then this is one
242
+ # way to do so.
243
+ #
244
+ # Usage example:
245
+ #
246
+ # MultimediaParadise.to_gif('foobar.mp4')
247
+ #
248
+ # ========================================================================= #
249
+ def self.to_gif(i)
250
+ [i].flatten.compact.each {|this_video_file|
251
+ _ = File.basename(this_video_file).
252
+ delete_suffix(
253
+ File.extname(this_video_file)
254
+ )
255
+ name_of_the_output_gif_file = "output_#{_}.gif"
256
+ cmd = "ffmpeg -i #{this_video_file} -pix_fmt rgb8 #{name_of_the_output_gif_file}" # Or use 0rgb.
257
+ esystem(cmd)
258
+ return name_of_the_output_gif_file
259
+ }
260
+ end
261
+
262
+ # ========================================================================= #
263
+ # === MultimediaParadise.create_noise_profile
264
+ #
265
+ # Note that this method depends on the external program called "sox".
266
+ #
267
+ # Usage example:
268
+ #
269
+ # MultimediaParadise.create_noise_profile('foobar.mp3')
270
+ #
271
+ # ========================================================================= #
272
+ def self.create_noise_profile(
273
+ of_this_mp3_file
274
+ )
275
+ array_results = []
276
+ [of_this_mp3_file].flatten.compact.each {|work_on_this_mp3_file|
277
+ work_on_this_mp3_file = File.absolute_path(work_on_this_mp3_file)
278
+ filename_without_extension = work_on_this_mp3_file.delete_suffix('.mp3')
279
+ this_profile_file_is_to_be_created = "noise_profile_based_on_#{File.basename(filename_without_extension)}"
280
+ if File.exist?(this_profile_file_is_to_be_created) # Always remove old profiles.
281
+ File.delete(this_profile_file_is_to_be_created)
282
+ end
283
+ cmd_to_run = "sox #{work_on_this_mp3_file} -n noiseprof #{this_profile_file_is_to_be_created}.profile"
284
+ e cmd_to_run
285
+ `#{cmd_to_run}`
286
+ array_results << this_profile_file_is_to_be_created
287
+ }
288
+ return array_results
289
+ end
290
+
291
+ # ========================================================================= #
292
+ # === MultimediaParadise.shrink_quality_of_these_mp3_files
293
+ #
294
+ # This method can be used to batch-shrink several .mp3 files in one go.
295
+ #
296
+ # Usage example:
297
+ #
298
+ # MultimediaParadise.shrink_quality_of_these_mp3_files(Dir['*.mp3'])
299
+ #
300
+ # ========================================================================= #
301
+ def self.shrink_quality_of_these_mp3_files(*array)
302
+ array.flatten.each {|this_mp3_file|
303
+ esystem "lame --mp3input -b 64 #{this_mp3_file}"
304
+ }
305
+ end
306
+
307
+ # ========================================================================= #
308
+ # === MultimediaParadise.report_how_many_real_videos_are_stored
309
+ #
310
+ # This method will report how many "real" videos are stored in the
311
+ # file video_collection.yml, which is distributed as part of
312
+ # this gem. You can, however had, also specify your own .yml
313
+ # file, as first argument to this method.
314
+ #
315
+ # To tap into this method, do issue:
316
+ #
317
+ # mpa --n-videos?
318
+ #
319
+ # ========================================================================= #
320
+ def self.report_how_many_real_videos_are_stored(
321
+ in_this_yaml_file = file_video_collection?
322
+ )
323
+ if File.exist? in_this_yaml_file
324
+ dataset = YAML.load_file(in_this_yaml_file)
325
+ e rev+
326
+ 'There are '+sfancy(dataset.keys.size)+' registered videos '+
327
+ 'in the file'
328
+ e '`'+sfile(in_this_yaml_file)+'`.'
329
+ else
330
+ e 'Please supply an existing yaml file (.yml) to this method.'
331
+ end
332
+ end
333
+
334
+ # ========================================================================= #
335
+ # === MultimediaParadise.overlay_two_audio_files
336
+ #
337
+ # This method can merge in two audio files, usually .mp3 files.
338
+ #
339
+ # The functionality depends on "sox".
340
+ # ========================================================================= #
341
+ def self.overlay_two_audio_files(
342
+ first,
343
+ second
344
+ )
345
+ output_file = 'output_file.mp3'
346
+ esystem 'sox --combine mix '+
347
+ first.to_s+
348
+ ' '+
349
+ second.to_s+
350
+ ' '+
351
+ output_file
352
+ end
353
+
354
+ # ========================================================================= #
355
+ # === MultimediaParadise.samplerate_of_this_song
356
+ #
357
+ # Usage example:
358
+ #
359
+ # MultimediaParadise.samplerate_of_this_song('foobar.mp3') # => 44100
360
+ #
361
+ # ========================================================================= #
362
+ def self.samplerate_of_this_song(this_song)
363
+ if this_song.is_a? Array
364
+ this_song = this_song.first
365
+ end
366
+ result = `ffprobe -select_streams a -show_streams #{this_song} 2>&1`
367
+ if result
368
+ result = result.split("\n").select {|entry|
369
+ entry.start_with? 'sample_rate'
370
+ }.first.to_s
371
+ end
372
+ if result and result.include?('=')
373
+ result = result.split('=').last
374
+ end
375
+ return result
376
+ end
377
+
378
+ # ========================================================================= #
379
+ # === MultimediaParadise.bitrate_of_this_song
380
+ #
381
+ # This method will make use of ffmpeg's ffprobe to query the bitrate of
382
+ # e. g. a .mp3 song. The return value is a String such as "192 kb/s".
383
+ #
384
+ # The commandline variant would be the following:
385
+ #
386
+ # ffprobe foobar.mp3 2>&1 | grep Stream
387
+ #
388
+ # Result:
389
+ #
390
+ # Stream #0:0: Audio: mp3, 11025 Hz, mono, s16p, 32 kb/s
391
+ #
392
+ # Usage example:
393
+ #
394
+ # MultimediaParadise.bitrate_of_this_song('foobar.mp3') # => "192 kb"
395
+ #
396
+ # ========================================================================= #
397
+ def self.bitrate_of_this_song(this_song)
398
+ use_this_regex = /(\d{1,3} ?kb)\/s/ # See: https://rubular.com/r/CfmHoK5w0goYpU
399
+ if this_song.is_a? Array
400
+ this_song = this_song.first
401
+ end
402
+ result = `ffprobe #{this_song} 2>&1 | grep Stream`.strip
403
+ result = result.scan(use_this_regex).flatten.first.to_s
404
+ return result
405
+ end
406
+
407
+ # ========================================================================= #
408
+ # === MultimediaParadise.reverse_audio
409
+ #
410
+ # Reverse an audio file.
411
+ # ========================================================================= #
412
+ def self.reverse_audio(
413
+ this_file = 'output.wav'
414
+ )
415
+ output_file = 'reversed_'+this_file
416
+ cmd = 'sox -n '+this_file+' '+output_file+' reverse'
417
+ run_sys_command cmd
418
+ return output_file
419
+ end
420
+
421
+ # ========================================================================= #
422
+ # === MultimediaParadise.generate_sine_tone
423
+ #
424
+ # Generate a n-second sine tone.
425
+ # ========================================================================= #
426
+ def self.generate_sine_tone(
427
+ n_seconds = 5
428
+ )
429
+ output_file = 'output.wav'
430
+ esystem 'sox -n '+output_file+' synth '+n_seconds.to_s+' sine 440'
431
+ return output_file
432
+ end
433
+
434
+ # ========================================================================= #
435
+ # === MultimediaParadise.generate_sine_tone_sweep
436
+ #
437
+ # Generate a n-second sine tone sweep.
438
+ # ========================================================================= #
439
+ def self.generate_sine_tone_sweep(
440
+ n_seconds = 5
441
+ )
442
+ output_file = 'output.wav'
443
+ esystem 'sox -n '+output_file+' synth '+n_seconds.to_s+' sine 0:800'
444
+ return output_file
445
+ end
446
+
447
+ # ========================================================================= #
448
+ # === MultimediaParadise.repeat_this_song_n_times
449
+ #
450
+ # This will make use of sox and repeat a given song n times.
451
+ # ========================================================================= #
452
+ def self.repeat_this_song_n_times(
453
+ this_song = ARGV,
454
+ n_times = 3
455
+ )
456
+ [this_song].flatten.compact.each {|a_song|
457
+ if File.exist? a_song
458
+ esystem 'sox '+a_song+' repeated_song_'+a_song+' repeat '+n_times.to_s
459
+ else
460
+ no_file_exists_at(a_song)
461
+ end
462
+ }
463
+ end
464
+
465
+ # ========================================================================= #
466
+ # === MultimediaParadise.append_silence_to_this_song
467
+ #
468
+ # Note that this method currently depends on sox. Perhaps someone knows
469
+ # how to do so via ffmpeg; I don't right now.
470
+ #
471
+ # The first argument to this method is the delay, in n seconds. You can
472
+ # use a fraction, such as 0.25 here as well.
473
+ #
474
+ # The second argument is the song, such as "bla.mp3". This filename should
475
+ # exist.
476
+ #
477
+ # The method will then simply add "silence" to the song at hand - it
478
+ # will append "silence".
479
+ #
480
+ # Usage examples:
481
+ #
482
+ # MultimediaParadise.append_silence_to_this_song(5, 'foobar.mp3')
483
+ # MultimediaParadise.append_silence_to_this_song(5, 'ack.mp3')
484
+ # MultimediaParadise.append_silence_to_this_song(.027, 'foobar.mp3')
485
+ #
486
+ # ========================================================================= #
487
+ def self.append_silence_to_this_song(
488
+ add_this_delay = 5,
489
+ work_on_these_songs = ['foobar.mp3']
490
+ )
491
+ [work_on_these_songs].flatten.compact.each {|this_song|
492
+ if File.exist? this_song
493
+ cmd = "sox #{this_song} padded_#{this_song} pad 0 #{add_this_delay.to_f}"
494
+ esystem cmd
495
+ else
496
+ e 'No file exists at '+this_song.to_s+'.'
497
+ end
498
+ }
499
+ end
500
+
501
+ # ========================================================================= #
502
+ # === MultimediaParadise.overlay_this_image_onto_that_video
503
+ #
504
+ # This method can be used to overlay an image over an existing local
505
+ # video file.
506
+ #
507
+ # The options in use are as follows:
508
+ #
509
+ # overlay=25:25: The image will be positioned 25px to the right and
510
+ # 25px down, originating from the top left corner (0:0).
511
+ #
512
+ # enable='between(t,0,20)': The overlay image will be shown from
513
+ # 00:00:00 to 00:00:20
514
+ #
515
+ # ========================================================================= #
516
+ def self.overlay_this_image_onto_that_video(
517
+ this_image,
518
+ that_video,
519
+ duration_in_n_seconds = 3
520
+ )
521
+ _ = 'ffmpeg -y -i '+that_video+' '\
522
+ '-i '+this_image+' -filter_complex "[0:v][1:v] '\
523
+ 'overlay=80:80:enable=\'between(t,0,'+
524
+ duration_in_n_seconds.to_s+')\'" '\
525
+ '-pix_fmt yuv420p -c:a copy '\
526
+ 'output.mp4'
527
+ e
528
+ esystem _
529
+ e
530
+ end
531
+
532
+ # ========================================================================= #
533
+ # === MultimediaParadise.split_into_chunks_of_n_minutes
534
+ # ========================================================================= #
535
+ def self.split_into_chunks_of_n_minutes(
536
+ this_video = '*.mp4',
537
+ n_minutes = 5
538
+ )
539
+ this_video = this_video.first if this_video.is_a? Array
540
+ _ = 'ffmpeg -i '+this_video+' -c copy -map 0 -segment_time '\
541
+ '00:0'+n_minutes.to_s+':00 -f segment output%03d.mp4'
542
+ e
543
+ esystem _
544
+ e
545
+ end
546
+
547
+ # ========================================================================= #
548
+ # === MultimediaParadise.split_into_chunks_of_5_minutes
549
+ # ========================================================================= #
550
+ def self.split_into_chunks_of_5_minutes(
551
+ i = '*.mp4'
552
+ )
553
+ MultimediaParadise.split_into_chunks_of_n_minutes(i, 5)
554
+ end
555
+
556
+ # ========================================================================= #
557
+ # === MultimediaParadise.return_ss_mm_hh
558
+ #
559
+ # This may return a string such as "16:35:07".
560
+ # ========================================================================= #
561
+ def self.return_ss_mm_hh
562
+ ::Time.now.strftime('%H:%M:%S')
563
+ end
564
+
565
+ # ========================================================================= #
566
+ # === MultimediaParadise.to_ts
567
+ #
568
+ # This will batch-convert all .mp4 files into .ts files.
569
+ # ========================================================================= #
570
+ def self.to_ts
571
+ files = Dir['*.mp4']
572
+ files.each {|this_file|
573
+ cmd = 'ffmpeg -i '+this_file+' -c copy '\
574
+ '-bsf:v h264_mp4toannexb -f mpegts '+
575
+ this_file.sub(/#{File.extname(this_file)}$/,'')+
576
+ '.ts'
577
+
578
+ esystem cmd
579
+ }
580
+ end
581
+
582
+ # ========================================================================= #
583
+ # === MultimediaParadise.set_the_aspect_ratio_of_this_video
584
+ #
585
+ # This method will set the aspect-ratio of a given video file, via
586
+ # ffmpeg. The commandline-flag for this is called -aspect.
587
+ #
588
+ # Original example:
589
+ #
590
+ # ffmpeg -i foo.mp4 -aspect 16:9 bar.mp4
591
+ #
592
+ # Example for the MultimediaParadise namespace:
593
+ #
594
+ # MultimediaParadise.set_the_aspect_ratio_of_this_video('foo.mpg')
595
+ #
596
+ # ========================================================================= #
597
+ def self.set_the_aspect_ratio_of_this_video(
598
+ this_video, use_this_aspect_ratio = '16:9'
599
+ )
600
+ extension_to_use = File.extname(this_video)
601
+ cmd_to_use = 'ffmpeg -i '+this_video+' -aspect '+
602
+ use_this_aspect_ratio+' output_'+
603
+ this_video.sub(/#{extension_to_use}$/,'')+extension_to_use
604
+ e
605
+ e cmd_to_use
606
+ e
607
+ system cmd_to_use
608
+ end
609
+
610
+ # ========================================================================= #
611
+ # === MultimediaParadise.extract_one_image_per_second
612
+ #
613
+ # This method will extract one-image-per-second from a given
614
+ # input video file.
615
+ #
616
+ # The first argument to this method should be the video file you
617
+ # are working with, such as 'foobar.mp4'.
618
+ # ========================================================================= #
619
+ def self.extract_one_image_per_second(
620
+ from_this_video_file = 'my_video.mpeg',
621
+ frame_size_to_use = '75x75'
622
+ )
623
+ extension_to_use = File.extname(from_this_video_file)
624
+ _ = 'ffmpeg -i '+from_this_video_file+
625
+ ' -r 1 '+ # ← Specify the video-frame here, aka "1 image per second".
626
+ '-s '+frame_size_to_use+
627
+ ' OUTPUT_'+from_this_video_file.sub(/#{extension_to_use}$/,'')+
628
+ extension_to_use
629
+ e
630
+ esystem _
631
+ e
632
+ end
633
+
634
+ # ========================================================================= #
635
+ # === MultimediaParadise.convert_these_images_into_a_video
636
+ #
637
+ # This method can be used to "assemble" images into a video.
638
+ # ========================================================================= #
639
+ def self.convert_these_images_into_a_video(*images)
640
+ _ = 'ffmpeg -f image2 -i '+images.join(' ').strip+' video.mpg'
641
+ esystem _
642
+ end
643
+
644
+ # ========================================================================= #
645
+ # === MultimediaParadise.high_quality_transcoding_of_this_video_file
646
+ #
647
+ # This method can be used for high-quality transcoding of a given
648
+ # input video file.
649
+ #
650
+ # - C:V is the video codec of choice
651
+ # - preset is the compression preset (in this case slow for higher
652
+ # quality compression)
653
+ # - CRF is the Constant Rate Factor, which preserves an overall
654
+ # level of quality throughout the file by adjusting each frame's
655
+ # bitrate based on the given quality level. The higher the CRF,
656
+ # the lower the overall quality level.
657
+ # - The video filter flag (-vf) is used to call FFMPEG's pre-bundled
658
+ # video filters.
659
+ # - yadif (Yet Another Deinterlacing Filter) deinterlaces an interlaced
660
+ # input, as progressive video is not only easier to compress and most
661
+ # current computer monitors and televisions are progressive scan.
662
+ # - When encoding with H.264/MPEG-4 AVC, the audio format used is AAC
663
+ # (Advanced Audio Coding); in order to enable FFMPEG's experimental,
664
+ # native AAC encoder.
665
+ # - -strict -2 needs to be added to the command.
666
+ # - An external library such as libfaac can also be used, and -strict
667
+ # -2 can be omitted.
668
+ #
669
+ # ========================================================================= #
670
+ def self.high_quality_transcoding_of_this_video_file(this_video_file)
671
+ output_file = 'OUTPUT_'+this_video_file.
672
+ sub(/#{File.extname(this_video_file)}$/,'')+'.mp4'
673
+ _ = 'ffmpeg -i '+this_video_file+' -c:v libx264 -preset slow '\
674
+ '-crf 18 -vf yadif -strict -2 '+
675
+ output_file
676
+ e
677
+ esystem _
678
+ e
679
+ end; self.instance_eval { alias high_quality_transcoding high_quality_transcoding_of_this_video_file } # === MultimediaParadise.high_quality_transcoding
680
+
681
+ # ========================================================================= #
682
+ # === MultimediaParadise.identify_video
683
+ #
684
+ # Use this to identify a given video or audio file.
685
+ #
686
+ # Another way would be this:
687
+ #
688
+ # mplayer -vo null -ao null -frames 0 -identify POP_America_TheLastUnicorn.mp3
689
+ #
690
+ # You will have to parse this lateron.
691
+ # ========================================================================= #
692
+ def self.identify_video(this_file)
693
+ cmd = "ffmpeg -i #{this_file}"
694
+ e
695
+ e cmd
696
+ e
697
+ result = `{cmd}`
698
+ return result
699
+ end
700
+
701
+ # ========================================================================= #
702
+ # === MultimediaParadise.show_available_audio_formats
703
+ #
704
+ # Use this method if you want to show the available (registered)
705
+ # audio formats.
706
+ # ========================================================================= #
707
+ def self.show_available_audio_formats
708
+ e; AUDIO_FORMATS.each {|entry|
709
+ e " - #{entry}" # It is ok to prepend the '-' since this is for display purposes.
710
+ }; e
711
+ end
712
+
713
+ # ========================================================================= #
714
+ # === MultimediaParadise.show_artist
715
+ #
716
+ # Use this for .mp3 files, via ffmpeg. It will show the artist.
717
+ #
718
+ # Input should be a .mp3 file.
719
+ #
720
+ # Usage example from within ruby code:
721
+ #
722
+ # MultimediaParadise.show_artist('/Depot/Audio/YoutubeMix_VivaldisFourSeasons.mp3')
723
+ # MultimediaParadise.show_artist('/Depot/Audio/Vivaldi_Concerto8.mp3')
724
+ #
725
+ # ========================================================================= #
726
+ def self.show_artist(
727
+ i, report_classname = true
728
+ )
729
+ result = MultimediaParadise.return_artist(i)
730
+ if result.empty?
731
+ opnn if report_classname
732
+ e 'This file does not have any artist-tag.'
733
+ else
734
+ opnn if report_classname
735
+ e "The artist is: #{simp(result)}"
736
+ end
737
+ end
738
+
739
+ # ========================================================================= #
740
+ # === MultimediaParadise.return_artist
741
+ # ========================================================================= #
742
+ def self.return_artist(
743
+ i,
744
+ report_classname = true
745
+ )
746
+ i = i.to_s
747
+ cmd =
748
+ 'ffprobe -loglevel error -show_entries format_tags=artist '\
749
+ '-of default=noprint_wrappers=1:nokey=1 '+i
750
+ result = `#{cmd}`.chomp
751
+ return result
752
+ end
753
+
754
+ # ========================================================================= #
755
+ # === MultimediaParadise.load_yaml
756
+ # ========================================================================= #
757
+ def self.load_yaml(i)
758
+ YAML.load_file(i)
759
+ end
760
+
761
+ # ========================================================================= #
762
+ # === MultimediaParadise.open_yaml_file
763
+ #
764
+ # This will open my video collection.
765
+ # ========================================================================= #
766
+ def self.open_yaml_file(
767
+ i = FILE_VIDEO_COLLECTION
768
+ )
769
+ esystem "bluefish #{i}"
770
+ end
771
+
772
+ # ========================================================================= #
773
+ # === MultimediaParadise.flip_video_to_the_left
774
+ #
775
+ # This toplevel-method can be used to flip a video to the left,
776
+ # that is, to rotate it by -90 degrees.
777
+ #
778
+ # It will tap into ffmpeg for this task.
779
+ # ========================================================================= #
780
+ def self.flip_video_to_the_left(i)
781
+ ffmpeg_flip_video_to_the_left(i)
782
+ end
783
+
784
+ # ========================================================================= #
785
+ # === MultimediaParadise.flip_video_to_the_right
786
+ #
787
+ # This toplevel-method can be used to flip a video to the right,
788
+ # that is, to rotate it by +90 degrees.
789
+ # ========================================================================= #
790
+ def self.flip_video_to_the_right(i)
791
+ ffmpeg_flip_video_to_the_right(i)
792
+ end
793
+
794
+ # ========================================================================= #
795
+ # === glob
796
+ # ========================================================================= #
797
+ def glob(i)
798
+ Dir[i]
799
+ end
800
+
801
+ # ========================================================================= #
802
+ # === video_collection?
803
+ # ========================================================================= #
804
+ def video_collection?
805
+ ::MultimediaParadise.file_video_collection
806
+ end
807
+
808
+ # ========================================================================= #
809
+ # === MultimediaParadise::PLAY_ZOOMED
810
+ #
811
+ # If this constant is set to true, then we will play in a zoomed way.
812
+ # ========================================================================= #
813
+ PLAY_ZOOMED = YAML.load_file(
814
+ "#{PROJECT_BASE_DIRECTORY}configuration/play_zoomed.yml"
815
+ )
816
+
817
+ # ========================================================================= #
818
+ # === MultimediaParadise.verbose_analyse_this_mp3_file_for_id3_tags
819
+ # ========================================================================= #
820
+ def self.verbose_analyse_this_mp3_file_for_id3_tags(this_mp3_file)
821
+ require 'id3lib'
822
+ if this_mp3_file.is_a? Array
823
+ this_mp3_file.each {|entry|
824
+ verbose_analyse_this_mp3_file_for_id3_tags(entry)
825
+ }
826
+ else
827
+ dataset = ID3Lib::Tag.new(this_mp3_file)
828
+ e "#{::Colours.rev}"\
829
+ "The .mp3 file is called: #{sfancy(this_mp3_file)}"
830
+ if dataset.empty?
831
+ e 'Has no id3-tags!'
832
+ else
833
+ # e 'Has some id3-tags.' # <- Dont report this in this case, though.
834
+ # ===================================================================== #
835
+ # Iterate through these entries next.
836
+ # ===================================================================== #
837
+ dataset.each_entry {|inner_hash|
838
+ value = inner_hash[:text].to_s
839
+ case inner_hash[:id]
840
+ # =================================================================== #
841
+ # === :TIT2
842
+ # =================================================================== #
843
+ when :TIT2
844
+ e 'The title is: '+
845
+ Colours.steelblue(value) unless value.empty?
846
+ # =================================================================== #
847
+ # === :TCON
848
+ #
849
+ # The genre.
850
+ # =================================================================== #
851
+ when :TCON
852
+ e 'The genre is: '+
853
+ Colours.steelblue(value) unless value.empty?
854
+ # =================================================================== #
855
+ # === :TYER
856
+ #
857
+ # The year.
858
+ # =================================================================== #
859
+ when :TYER
860
+ e 'The year is: '+
861
+ Colours.steelblue(value) unless value.empty?
862
+ # =================================================================== #
863
+ # === :TPE1
864
+ #
865
+ # The artist.
866
+ # =================================================================== #
867
+ when :TPE1
868
+ e 'The artist is: '+
869
+ Colours.steelblue(value) unless value.empty?
870
+ end
871
+ }
872
+ # pp dataset # <- for debugging.
873
+ end
874
+ end
875
+ end
876
+
877
+ # ========================================================================= #
878
+ # === MultimediaParadise.analyze_this_directory_for_id3_tags
879
+ # ========================================================================= #
880
+ def self.analyze_this_directory_for_id3_tags(i = Dir.pwd)
881
+ require 'id3lib'
882
+ all_files = Dir["#{i}/*.mp3"]
883
+ all_files.each {|this_mp3_file|
884
+ verbose_analyse_this_mp3_file_for_id3_tags(this_mp3_file)
885
+ }
886
+ end
887
+
888
+ # ========================================================================= #
889
+ # === MultimediaParadise.compress_this_ogg_file
890
+ #
891
+ # This method will use a sampling rate of 22050 Hz. This should be
892
+ # perfectly adequate for speech-related audio, but I also found it
893
+ # to work well when compressing a tetris.ogg file (for the game
894
+ # tetris).
895
+ # ========================================================================= #
896
+ def self.compress_this_ogg_file(i = 'foobar.ogg')
897
+ _ = 'ffmpeg -i '+entry+' '\
898
+ '-c:a libvorbis -ab 32k '\
899
+ '-ar 22050'\
900
+ ' OUTPUT_'+i
901
+ e
902
+ esystem _
903
+ e
904
+ end
905
+
906
+ # ========================================================================= #
907
+ # === MultimediaParadise.try_to_rename_kde_konsole_tab
908
+ # ========================================================================= #
909
+ def self.try_to_rename_kde_konsole_tab(
910
+ new_title = '_',
911
+ try_to_rename_the_kde_konsole_tab = TRY_TO_RENAME_THE_KDE_KONSOLE_TAB
912
+ )
913
+ if try_to_rename_the_kde_konsole_tab
914
+ begin
915
+ require 'roebe/requires/require_kde_konsole.rb'
916
+ rescue LoadError
917
+ e 'roebe/requires/require_kde_konsole.rb is not available'
918
+ end
919
+ if Object.const_defined?(:Roebe) and
920
+ Roebe.respond_to?(:rename_konsole)
921
+ Roebe.rename_konsole(new_title)
922
+ end
923
+ end
924
+ end; self.instance_eval { alias rename_kde_konsole try_to_rename_kde_konsole_tab } # === MultimediaParadise.rename_kde_konsole
925
+ self.instance_eval { alias do_rename_konsole try_to_rename_kde_konsole_tab } # === MultimediaParadise.do_rename_konsole
926
+ self.instance_eval { alias rename_kde_konsole_tab try_to_rename_kde_konsole_tab } # === MultimediaParadise.rename_kde_konsole_tab
927
+
928
+ # ========================================================================= #
929
+ # === MultimediaParadise.crop_this_video
930
+ #
931
+ # This method can be used to crop a particular video file, via
932
+ # ffmpeg.
933
+ #
934
+ # The raw ffmpeg-command would go like something like this:
935
+ #
936
+ # ffmpeg -i input.mp4 -filter:v "crop=out_w:out_h:x:y" output.mp4
937
+ #
938
+ # These variables are:
939
+ #
940
+ # → out_w is the width of the output rectangle
941
+ # → out_h is the height of the output rectangle
942
+ # → x and y specify the top left corner of the output rectangle
943
+ # → output.mp4 is the output file
944
+ #
945
+ # ========================================================================= #
946
+ def self.crop_this_video(
947
+ i = 'input.mp4',
948
+ output_file = 'output.mp4'
949
+ )
950
+ [i].flatten.compact.each {|this_video_file|
951
+ esystem 'ffmpeg -i '+
952
+ this_video_file.to_s+
953
+ ' -filter:v "crop=w:h:x:y" '+
954
+ output_file.to_s
955
+ }
956
+ end
957
+
958
+ end
959
+
960
+ if __FILE__ == $PROGRAM_NAME
961
+ include MultimediaParadise
962
+ map_number_to_videofile
963
+ puts 'The version of the MultimediaParadise project is: '+version?
964
+ end # rb shared.rb