multimedia_paradise 1.1.97

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 (306) hide show
  1. checksums.yaml +7 -0
  2. data/README.md +1177 -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 +9 -0
  7. data/bin/extract_audio +7 -0
  8. data/bin/file_duration +7 -0
  9. data/bin/merge_mp3 +7 -0
  10. data/bin/missing_video_files +7 -0
  11. data/bin/movie_searcher +7 -0
  12. data/bin/mp3_to_opus +7 -0
  13. data/bin/mplayer_wrapper +7 -0
  14. data/bin/multimedia_information +11 -0
  15. data/bin/multimedia_paradise +9 -0
  16. data/bin/play_random_simpsons_video +7 -0
  17. data/bin/playlist +20 -0
  18. data/bin/random_video +7 -0
  19. data/bin/remove_audio +9 -0
  20. data/bin/remove_last_second +7 -0
  21. data/bin/remove_subtitles +7 -0
  22. data/bin/to_mp4 +7 -0
  23. data/bin/video_information +8 -0
  24. data/bin/video_player +11 -0
  25. data/bin/video_to_images +7 -0
  26. data/bin/waveform +73 -0
  27. data/doc/CHANGELOG.md +40 -0
  28. data/doc/LINKS.md +6 -0
  29. data/doc/MOTIVATION.md +15 -0
  30. data/doc/MULTIMEDIA_PARADISE.cgi +65 -0
  31. data/doc/MergingVideoLectures.md +12 -0
  32. data/doc/README.gen +1160 -0
  33. data/doc/Readme_for_the_cut_audio_component.md +168 -0
  34. data/doc/TODO.md +82 -0
  35. data/lib/multimedia_paradise.rb +5 -0
  36. data/lib/multimedia_paradise/audio/audio_player/audio_player.rb +685 -0
  37. data/lib/multimedia_paradise/audio/audio_player/constants.rb +121 -0
  38. data/lib/multimedia_paradise/audio/audio_player/menu.rb +138 -0
  39. data/lib/multimedia_paradise/audio/audio_player/reset.rb +59 -0
  40. data/lib/multimedia_paradise/audio/audio_player/tab.rb +33 -0
  41. data/lib/multimedia_paradise/audio/base.rb +66 -0
  42. data/lib/multimedia_paradise/audio/compress.rb +92 -0
  43. data/lib/multimedia_paradise/audio/create_m3u_playlist.rb +244 -0
  44. data/lib/multimedia_paradise/audio/cut_audio/10_minutes_chop.rb +27 -0
  45. data/lib/multimedia_paradise/audio/cut_audio/15_minutes_chop.rb +27 -0
  46. data/lib/multimedia_paradise/audio/cut_audio/30_minutes_chop.rb +34 -0
  47. data/lib/multimedia_paradise/audio/cut_audio/5_minutes_chop.rb +27 -0
  48. data/lib/multimedia_paradise/audio/cut_audio/chop.rb +100 -0
  49. data/lib/multimedia_paradise/audio/cut_audio/class.rb +70 -0
  50. data/lib/multimedia_paradise/audio/cut_audio/class_methods.rb +49 -0
  51. data/lib/multimedia_paradise/audio/cut_audio/constants.rb +87 -0
  52. data/lib/multimedia_paradise/audio/cut_audio/help.rb +46 -0
  53. data/lib/multimedia_paradise/audio/cut_audio/initialize.rb +49 -0
  54. data/lib/multimedia_paradise/audio/cut_audio/intersect.rb +86 -0
  55. data/lib/multimedia_paradise/audio/cut_audio/menu.rb +396 -0
  56. data/lib/multimedia_paradise/audio/cut_audio/misc.rb +1071 -0
  57. data/lib/multimedia_paradise/audio/cut_audio/report_and_feedback.rb +233 -0
  58. data/lib/multimedia_paradise/audio/cut_audio/reset.rb +72 -0
  59. data/lib/multimedia_paradise/audio/cut_audio/run.rb +25 -0
  60. data/lib/multimedia_paradise/audio/cut_audio/start_position.rb +72 -0
  61. data/lib/multimedia_paradise/audio/extract_audio/constants.rb +37 -0
  62. data/lib/multimedia_paradise/audio/extract_audio/extract_audio.rb +379 -0
  63. data/lib/multimedia_paradise/audio/file_duration/constants.rb +53 -0
  64. data/lib/multimedia_paradise/audio/file_duration/file_duration.rb +553 -0
  65. data/lib/multimedia_paradise/audio/genres/boogie.rb +35 -0
  66. data/lib/multimedia_paradise/audio/genres/concerts.rb +35 -0
  67. data/lib/multimedia_paradise/audio/genres/constants.rb +53 -0
  68. data/lib/multimedia_paradise/audio/genres/eurodance.rb +35 -0
  69. data/lib/multimedia_paradise/audio/genres/genre.rb +696 -0
  70. data/lib/multimedia_paradise/audio/genres/hip_hop.rb +35 -0
  71. data/lib/multimedia_paradise/audio/genres/italian_songs.rb +35 -0
  72. data/lib/multimedia_paradise/audio/genres/the_1980s.rb +35 -0
  73. data/lib/multimedia_paradise/audio/genres/trance.rb +35 -0
  74. data/lib/multimedia_paradise/audio/lyrics_fetcher.rb +242 -0
  75. data/lib/multimedia_paradise/audio/merge_audio_files.rb +136 -0
  76. data/lib/multimedia_paradise/audio/modify_year_of_audio_file.rb +151 -0
  77. data/lib/multimedia_paradise/audio/n_audio_songs.rb +216 -0
  78. data/lib/multimedia_paradise/audio/play_all_audio_files.rb +122 -0
  79. data/lib/multimedia_paradise/audio/playlist/add.rb +72 -0
  80. data/lib/multimedia_paradise/audio/playlist/constants.rb +75 -0
  81. data/lib/multimedia_paradise/audio/playlist/help.rb +84 -0
  82. data/lib/multimedia_paradise/audio/playlist/initialize.rb +41 -0
  83. data/lib/multimedia_paradise/audio/playlist/menu.rb +295 -0
  84. data/lib/multimedia_paradise/audio/playlist/playlist.rb +837 -0
  85. data/lib/multimedia_paradise/audio/playlist/reset.rb +36 -0
  86. data/lib/multimedia_paradise/audio/playlist/show.rb +47 -0
  87. data/lib/multimedia_paradise/audio/remove_audio.rb +79 -0
  88. data/lib/multimedia_paradise/audio/remove_last_second.rb +83 -0
  89. data/lib/multimedia_paradise/audio/streamripper/constants.rb +51 -0
  90. data/lib/multimedia_paradise/audio/streamripper/streamripper_wrapper.rb +279 -0
  91. data/lib/multimedia_paradise/audio/to_mp3.rb +140 -0
  92. data/lib/multimedia_paradise/audio/to_ogg.rb +104 -0
  93. data/lib/multimedia_paradise/audio/waveform/class.rb +341 -0
  94. data/lib/multimedia_paradise/audio/waveform/constants.rb +38 -0
  95. data/lib/multimedia_paradise/audio/waveform/log.rb +101 -0
  96. data/lib/multimedia_paradise/autoinclude.rb +3 -0
  97. data/lib/multimedia_paradise/autoinclude_remove_audio.rb +6 -0
  98. data/lib/multimedia_paradise/base/base.rb +34 -0
  99. data/lib/multimedia_paradise/base/colours.rb +291 -0
  100. data/lib/multimedia_paradise/base/constants.rb +19 -0
  101. data/lib/multimedia_paradise/base/encoding.rb +31 -0
  102. data/lib/multimedia_paradise/base/misc.rb +492 -0
  103. data/lib/multimedia_paradise/base/namespace.rb +16 -0
  104. data/lib/multimedia_paradise/colours/colours.rb +82 -0
  105. data/lib/multimedia_paradise/configuration/play_zoomed.yml +1 -0
  106. data/lib/multimedia_paradise/constants/constants.rb +23 -0
  107. data/lib/multimedia_paradise/constants/conversions.rb +62 -0
  108. data/lib/multimedia_paradise/constants/directory_constants.rb +120 -0
  109. data/lib/multimedia_paradise/constants/encodings.rb +26 -0
  110. data/lib/multimedia_paradise/constants/file_constants.rb +144 -0
  111. data/lib/multimedia_paradise/constants/misc.rb +80 -0
  112. data/lib/multimedia_paradise/constants/my_video_directory.rb +30 -0
  113. data/lib/multimedia_paradise/constants/namespace.rb +14 -0
  114. data/lib/multimedia_paradise/constants/newline.rb +14 -0
  115. data/lib/multimedia_paradise/constants/video_filetypes.rb +27 -0
  116. data/lib/multimedia_paradise/constants/web_constants.rb +56 -0
  117. data/lib/multimedia_paradise/data/asoundrc +12 -0
  118. data/lib/multimedia_paradise/ffmpeg/README.md +2 -0
  119. data/lib/multimedia_paradise/ffmpeg/ffmpeg.rb +566 -0
  120. data/lib/multimedia_paradise/gui/fox/play_from_radio_station.rb +75 -0
  121. data/lib/multimedia_paradise/gui/gtk/multimedia_converter.rb +390 -0
  122. data/lib/multimedia_paradise/gui/gtk/notebook.rb +128 -0
  123. data/lib/multimedia_paradise/gui/gtk/play_video_from_my_collection.rb +302 -0
  124. data/lib/multimedia_paradise/gui/gtk/radio/buttons.rb +177 -0
  125. data/lib/multimedia_paradise/gui/gtk/radio/constants.rb +57 -0
  126. data/lib/multimedia_paradise/gui/gtk/radio/initialize.rb +28 -0
  127. data/lib/multimedia_paradise/gui/gtk/radio/misc.rb +406 -0
  128. data/lib/multimedia_paradise/gui/gtk/radio/play_from_radio_station.rb +63 -0
  129. data/lib/multimedia_paradise/gui/gtk/radio/reset.rb +62 -0
  130. data/lib/multimedia_paradise/gui/gtk/radio/skeleton.rb +96 -0
  131. data/lib/multimedia_paradise/gui/gtk/simple_play_widget/README.md +12 -0
  132. data/lib/multimedia_paradise/gui/gtk/simple_play_widget/simple_play_widget.rb +245 -0
  133. data/lib/multimedia_paradise/gui/gtk/video_collection.rb +214 -0
  134. data/lib/multimedia_paradise/gui/gtk/widget_increase_or_decrease_audio.rb +143 -0
  135. data/lib/multimedia_paradise/gui/gtk/youtube_downloader.rb +265 -0
  136. data/lib/multimedia_paradise/gui/gui_base.rb +46 -0
  137. data/lib/multimedia_paradise/gui/tk/tk_multimedia_wrapper.rb +60 -0
  138. data/lib/multimedia_paradise/help/help.rb +73 -0
  139. data/lib/multimedia_paradise/images/MULTIMEDIA_PARADISE_LOGO.png +0 -0
  140. data/lib/multimedia_paradise/images/UK_flag.png +0 -0
  141. data/lib/multimedia_paradise/images/US_flag.png +0 -0
  142. data/lib/multimedia_paradise/images/austrian_flag.png +0 -0
  143. data/lib/multimedia_paradise/images/french_flag.png +0 -0
  144. data/lib/multimedia_paradise/images/german_flag.png +0 -0
  145. data/lib/multimedia_paradise/images/radio_image.png +0 -0
  146. data/lib/multimedia_paradise/images/trance.png +0 -0
  147. data/lib/multimedia_paradise/menu/menu.rb +365 -0
  148. data/lib/multimedia_paradise/misc/long_format_to_milliseconds_converter.rb +182 -0
  149. data/lib/multimedia_paradise/misc/milliseconds_to_long_format_converter.rb +186 -0
  150. data/lib/multimedia_paradise/multimedia/analyse_multimedia_file.rb +176 -0
  151. data/lib/multimedia_paradise/multimedia/chord.rb +174 -0
  152. data/lib/multimedia_paradise/multimedia/convert_audio_to_video_with_image.rb +171 -0
  153. data/lib/multimedia_paradise/multimedia/interactive_shell.rb +84 -0
  154. data/lib/multimedia_paradise/multimedia/merge_multimedia.rb +119 -0
  155. data/lib/multimedia_paradise/multimedia/note.rb +500 -0
  156. data/lib/multimedia_paradise/multimedia/play_from_this_list.rb +163 -0
  157. data/lib/multimedia_paradise/multimedia/read_meta_tags.rb +173 -0
  158. data/lib/multimedia_paradise/multimedia/start_length_duration.rb +205 -0
  159. data/lib/multimedia_paradise/project/project.rb +47 -0
  160. data/lib/multimedia_paradise/requires/require_audio_files.rb +74 -0
  161. data/lib/multimedia_paradise/requires/require_cut_audio.rb +7 -0
  162. data/lib/multimedia_paradise/requires/require_extract_audio.rb +7 -0
  163. data/lib/multimedia_paradise/requires/require_file_duration.rb +7 -0
  164. data/lib/multimedia_paradise/requires/require_streamripper.rb +7 -0
  165. data/lib/multimedia_paradise/requires/require_the_audio_player.rb +7 -0
  166. data/lib/multimedia_paradise/requires/require_the_multimedia_paradise_project.rb +30 -0
  167. data/lib/multimedia_paradise/requires/require_toplevel_methods_files.rb +25 -0
  168. data/lib/multimedia_paradise/requires/require_video_files.rb +25 -0
  169. data/lib/multimedia_paradise/requires/require_video_player.rb +7 -0
  170. data/lib/multimedia_paradise/sinatra/app.rb +257 -0
  171. data/lib/multimedia_paradise/sound_effects/README.md +8 -0
  172. data/lib/multimedia_paradise/sound_effects/channel_opened.mp3 +0 -0
  173. data/lib/multimedia_paradise/sound_effects/phone_ring.mp3 +0 -0
  174. data/lib/multimedia_paradise/toplevel_cut_audio.rb +16 -0
  175. data/lib/multimedia_paradise/toplevel_methods/analyze_audio_stream.rb +31 -0
  176. data/lib/multimedia_paradise/toplevel_methods/chop_into_segments_of_n_seconds_size.rb +32 -0
  177. data/lib/multimedia_paradise/toplevel_methods/chop_off_first_five_minutes.rb +22 -0
  178. data/lib/multimedia_paradise/toplevel_methods/chop_off_first_n_seconds.rb +92 -0
  179. data/lib/multimedia_paradise/toplevel_methods/chop_off_first_ten_minutes.rb +22 -0
  180. data/lib/multimedia_paradise/toplevel_methods/chop_off_first_two_minutes.rb +24 -0
  181. data/lib/multimedia_paradise/toplevel_methods/conversions.rb +1040 -0
  182. data/lib/multimedia_paradise/toplevel_methods/copy_and_merge_this_video_n_times.rb +51 -0
  183. data/lib/multimedia_paradise/toplevel_methods/copy_file.rb +18 -0
  184. data/lib/multimedia_paradise/toplevel_methods/create_video_from_this_audio.rb +65 -0
  185. data/lib/multimedia_paradise/toplevel_methods/cut_from_to.rb +151 -0
  186. data/lib/multimedia_paradise/toplevel_methods/delay_audio.rb +31 -0
  187. data/lib/multimedia_paradise/toplevel_methods/denoise.rb +90 -0
  188. data/lib/multimedia_paradise/toplevel_methods/deshake.rb +43 -0
  189. data/lib/multimedia_paradise/toplevel_methods/e.rb +16 -0
  190. data/lib/multimedia_paradise/toplevel_methods/encode_this_video.rb +49 -0
  191. data/lib/multimedia_paradise/toplevel_methods/ensure_that_the_output_directory_exists.rb +27 -0
  192. data/lib/multimedia_paradise/toplevel_methods/esystem.rb +43 -0
  193. data/lib/multimedia_paradise/toplevel_methods/files_and_directories.rb +86 -0
  194. data/lib/multimedia_paradise/toplevel_methods/flip_and_rotate.rb +58 -0
  195. data/lib/multimedia_paradise/toplevel_methods/increase_volume_of_this_audio_file.rb +61 -0
  196. data/lib/multimedia_paradise/toplevel_methods/is_a_multimedia_file.rb +27 -0
  197. data/lib/multimedia_paradise/toplevel_methods/is_audio_file.rb +27 -0
  198. data/lib/multimedia_paradise/toplevel_methods/is_image_file.rb +31 -0
  199. data/lib/multimedia_paradise/toplevel_methods/is_on_roebe.rb +17 -0
  200. data/lib/multimedia_paradise/toplevel_methods/is_video_file.rb +61 -0
  201. data/lib/multimedia_paradise/toplevel_methods/merge_multimedia_file.rb +105 -0
  202. data/lib/multimedia_paradise/toplevel_methods/merge_these_videos.rb +96 -0
  203. data/lib/multimedia_paradise/toplevel_methods/misc.rb +316 -0
  204. data/lib/multimedia_paradise/toplevel_methods/n_local_videos.rb +56 -0
  205. data/lib/multimedia_paradise/toplevel_methods/opn.rb +24 -0
  206. data/lib/multimedia_paradise/toplevel_methods/output_directory.rb +59 -0
  207. data/lib/multimedia_paradise/toplevel_methods/player_in_use.rb +80 -0
  208. data/lib/multimedia_paradise/toplevel_methods/query_the_audio_codec_of_this_file.rb +24 -0
  209. data/lib/multimedia_paradise/toplevel_methods/radio.rb +350 -0
  210. data/lib/multimedia_paradise/toplevel_methods/rds.rb +24 -0
  211. data/lib/multimedia_paradise/toplevel_methods/return_all_video_files.rb +63 -0
  212. data/lib/multimedia_paradise/toplevel_methods/return_data_from_video_collection_file_for_this_entry.rb +38 -0
  213. data/lib/multimedia_paradise/toplevel_methods/return_duration_of_this_multimedia_file.rb +27 -0
  214. data/lib/multimedia_paradise/toplevel_methods/return_full_name_for_video_at_this_position.rb +54 -0
  215. data/lib/multimedia_paradise/toplevel_methods/return_path_to_random_simpsons_video_file.rb +43 -0
  216. data/lib/multimedia_paradise/toplevel_methods/return_random_video_file_from_the_video_collection.rb +62 -0
  217. data/lib/multimedia_paradise/toplevel_methods/return_screen_resolution.rb +24 -0
  218. data/lib/multimedia_paradise/toplevel_methods/scale_video.rb +27 -0
  219. data/lib/multimedia_paradise/toplevel_methods/set_title_of.rb +55 -0
  220. data/lib/multimedia_paradise/toplevel_methods/slow_down_this_video_file.rb +33 -0
  221. data/lib/multimedia_paradise/toplevel_methods/start_screencast.rb +61 -0
  222. data/lib/multimedia_paradise/toplevel_methods/subtitles.rb +59 -0
  223. data/lib/multimedia_paradise/toplevel_methods/to_mp4.rb +22 -0
  224. data/lib/multimedia_paradise/toplevel_methods/total_duration.rb +35 -0
  225. data/lib/multimedia_paradise/toplevel_methods/use_lame_codec.rb +32 -0
  226. data/lib/multimedia_paradise/toplevel_methods/video_dataset.rb +76 -0
  227. data/lib/multimedia_paradise/version/version.rb +28 -0
  228. data/lib/multimedia_paradise/video/all_videos.rb +101 -0
  229. data/lib/multimedia_paradise/video/capture_screen.rb +285 -0
  230. data/lib/multimedia_paradise/video/check_numbers.rb +215 -0
  231. data/lib/multimedia_paradise/video/copy_missing_video_files.rb +278 -0
  232. data/lib/multimedia_paradise/video/correct_video_numbers.rb +273 -0
  233. data/lib/multimedia_paradise/video/create_dvd.rb +50 -0
  234. data/lib/multimedia_paradise/video/encode_video.rb +79 -0
  235. data/lib/multimedia_paradise/video/ffmpeg_options.rb +156 -0
  236. data/lib/multimedia_paradise/video/find_video.rb +431 -0
  237. data/lib/multimedia_paradise/video/fix_married_with_children_videos.rb +70 -0
  238. data/lib/multimedia_paradise/video/google_video_downloader.rb +80 -0
  239. data/lib/multimedia_paradise/video/guess_video_name.rb +189 -0
  240. data/lib/multimedia_paradise/video/missing_video_files/missing_video_files.rb +286 -0
  241. data/lib/multimedia_paradise/video/movie_searcher.rb +279 -0
  242. data/lib/multimedia_paradise/video/mplayer_wrapper.rb +483 -0
  243. data/lib/multimedia_paradise/video/play_random_file.rb +85 -0
  244. data/lib/multimedia_paradise/video/play_random_realvideo.rb +87 -0
  245. data/lib/multimedia_paradise/video/prepare_video_lecture.rb +272 -0
  246. data/lib/multimedia_paradise/video/random_video.rb +310 -0
  247. data/lib/multimedia_paradise/video/registered_video_file.rb +131 -0
  248. data/lib/multimedia_paradise/video/remove_metadata.rb +52 -0
  249. data/lib/multimedia_paradise/video/rename_video_file.rb +147 -0
  250. data/lib/multimedia_paradise/video/report_local_videos.rb +106 -0
  251. data/lib/multimedia_paradise/video/report_missing_videos_in_the_yaml_file.rb +107 -0
  252. data/lib/multimedia_paradise/video/resolution.rb +152 -0
  253. data/lib/multimedia_paradise/video/simpsons.rb +127 -0
  254. data/lib/multimedia_paradise/video/speed_up_video.rb +135 -0
  255. data/lib/multimedia_paradise/video/srt_regex.rb +211 -0
  256. data/lib/multimedia_paradise/video/store_available_video_files.rb +135 -0
  257. data/lib/multimedia_paradise/video/the_simpsons/README.md +9 -0
  258. data/lib/multimedia_paradise/video/the_simpsons/good_the_simpsons_episodes.rb +107 -0
  259. data/lib/multimedia_paradise/video/the_simpsons/the_simpsons.rb +82 -0
  260. data/lib/multimedia_paradise/video/video.rb +14 -0
  261. data/lib/multimedia_paradise/video/video_encoding_settings.rb +57 -0
  262. data/lib/multimedia_paradise/video/video_genres.rb +336 -0
  263. data/lib/multimedia_paradise/video/video_information.rb +443 -0
  264. data/lib/multimedia_paradise/video/video_metadata.rb +132 -0
  265. data/lib/multimedia_paradise/video/video_player.rb +572 -0
  266. data/lib/multimedia_paradise/video/video_renamer.rb +166 -0
  267. data/lib/multimedia_paradise/video/watermark.rb +290 -0
  268. data/lib/multimedia_paradise/video/youtube_embedder.rb +235 -0
  269. data/lib/multimedia_paradise/www/alsa.cgi +274 -0
  270. data/lib/multimedia_paradise/www/audacity.cgi +23 -0
  271. data/lib/multimedia_paradise/www/audio.cgi +2589 -0
  272. data/lib/multimedia_paradise/www/best_voices.cgi +57 -0
  273. data/lib/multimedia_paradise/www/componists/vivaldi.cgi +212 -0
  274. data/lib/multimedia_paradise/www/decibel.cgi +79 -0
  275. data/lib/multimedia_paradise/www/lame.cgi +100 -0
  276. data/lib/multimedia_paradise/www/lilypond.cgi +96 -0
  277. data/lib/multimedia_paradise/www/lyrics.cgi +48 -0
  278. data/lib/multimedia_paradise/www/midi/al_adagi.mid +0 -0
  279. data/lib/multimedia_paradise/www/play_songs.cgi +75 -0
  280. data/lib/multimedia_paradise/www/pulseaudio.cgi +169 -0
  281. data/lib/multimedia_paradise/www/rhythmbox.cgi +115 -0
  282. data/lib/multimedia_paradise/www/sound_theory.cgi +162 -0
  283. data/lib/multimedia_paradise/yaml/audio_formats.yml +14 -0
  284. data/lib/multimedia_paradise/yaml/genres/1980s.yml +198 -0
  285. data/lib/multimedia_paradise/yaml/genres/README.md +5 -0
  286. data/lib/multimedia_paradise/yaml/genres/boogie.yml +68 -0
  287. data/lib/multimedia_paradise/yaml/genres/concerts.yml +29 -0
  288. data/lib/multimedia_paradise/yaml/genres/eurodance.yml +456 -0
  289. data/lib/multimedia_paradise/yaml/genres/hip_hop.yml +49 -0
  290. data/lib/multimedia_paradise/yaml/genres/italian_songs.yml +53 -0
  291. data/lib/multimedia_paradise/yaml/genres/trance.yml +157 -0
  292. data/lib/multimedia_paradise/yaml/image_formats.yml +8 -0
  293. data/lib/multimedia_paradise/yaml/lyrics.yml +5543 -0
  294. data/lib/multimedia_paradise/yaml/playlist.yml +115 -0
  295. data/lib/multimedia_paradise/yaml/radio/README.md +5 -0
  296. data/lib/multimedia_paradise/yaml/radio/radio_stations.yml +289 -0
  297. data/lib/multimedia_paradise/yaml/song_tags.yml +815 -0
  298. data/lib/multimedia_paradise/yaml/use_this_video_player.yml +1 -0
  299. data/lib/multimedia_paradise/yaml/video_collection.yml +1818 -0
  300. data/multimedia_paradise.gemspec +71 -0
  301. data/test/testing_audio_player.rb +15 -0
  302. data/test/testing_ffmpeg_options.rb +14 -0
  303. data/test/testing_file_duration.rb +17 -0
  304. data/test/testing_modify_year_of_audio_file.rb +14 -0
  305. data/test/testing_multimedia_paradise_project.rb +151 -0
  306. metadata +476 -0
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 5f79ba1e9612bb765e5d787ed1265564a230141d4cddf6721ff3dcfa5f4ea631
4
+ data.tar.gz: 8ebdd2e27b93c2abae1d6774bad96589b7035d11784843df27ca88e3bd909a2b
5
+ SHA512:
6
+ metadata.gz: 231be9d038ce39099c5c4ac3dd791b411e9422426e54289c35b294150eee1cb565006cb74b2f13c10ff05dd99b4bf936d76a60852a549f5800d52f4c37657cde
7
+ data.tar.gz: a9ffc45cf5c81178e38e7aa10403bea94a1f0a5d1916749b0673fea15e66c6449e36fe0f6f34b5e9a5a541941f0dd5fa4475273506b636dbbf101dc8cb78aaa8
@@ -0,0 +1,1177 @@
1
+ [![forthebadge](http://forthebadge.com/images/badges/built-with-love.svg)](https://www.gobolinux.org/)
2
+ [![forthebadge](http://forthebadge.com/images/badges/made-with-ruby.svg)](https://www.ruby-lang.org/en/)
3
+ [![Gem Version](https://badge.fury.io/rb/multimedia_paradise.svg)](https://badge.fury.io/rb/multimedia_paradise)
4
+
5
+ # MultimediaParadise - Everything about audio and video
6
+
7
+ ![Logo][logo]
8
+ [logo]: http://shevy.bplaced.net/MULTIMEDIA_PARADISE_LOGO.png
9
+
10
+ The **multimedia paradise** project bundles together code that can be
11
+ used for "multimedia data" - in particular for **audio** and **video** files.
12
+
13
+ Most of the functionality found within the **multimedia paradise**
14
+ projects depends on <b>ffmpeg</b>, but in principle the code in the
15
+ main module called **MultimediaParadise** should work with other
16
+ toolkits as well, if a toolkit supports certain actions (such as
17
+ <b>sox</b>). As is often the case, support for other toolkits depends
18
+ on time investment - and time availability - of the main author of
19
+ this project.
20
+
21
+ For all purposes, though, **ffmpeg** is a really excellent project.
22
+ Thus, the MultimediaParadise gem will focus on **ffmpeg** by
23
+ default.
24
+
25
+ You can obtain a copy of ffmpeg from the following URL:
26
+
27
+ https://www.ffmpeg.org/
28
+
29
+ ## Installation of the MultimediaParadise project
30
+
31
+ There are several ways how to install this project, including oldschol
32
+ **setup.rb** - but I recommend the following way:
33
+
34
+ gem install multimedia_paradise --user-install
35
+
36
+ The reason as to why I recommend the **--user-install** option is because
37
+ the various files under the **bin/** subdirectory will be available
38
+ in your home directory (under e. g. ~/.gem/ruby/2.5.0/bin or whatever
39
+ your local ruby version is). That way you can easily add that directory
40
+ to $PATH or not, and make use of these files.
41
+
42
+ ## Removing audio from a video file
43
+
44
+ If you wish to **remove audio from a video file**, use the following
45
+ **API**:
46
+
47
+ MultimediaParadise.remove_audio(path_to_the_file_goes_in_here)
48
+
49
+ Specific example:
50
+
51
+ MultimediaParadise.remove_audio('/foo.avi')
52
+
53
+ This functionality depends on an installed **ffmpeg**. If anyone
54
+ knows of a pure ruby variant only, let me know.
55
+
56
+ ## Radio stations
57
+
58
+ Since as of **October 2018**, the **MultimediaParadise** project comes
59
+ with a small **yaml file** called **radio_stations.yml**.
60
+
61
+ x = YAML.load_file('radio_stations.yml')
62
+
63
+ The idea here is to have a few additional audio-streams (from **radio
64
+ stations**) that could be loaded up into, for example, **rhythmbox**.
65
+
66
+ I also wanted to have a default "template" for testing some ruby code
67
+ there, such as autogenerating a playlist from this file, or listening
68
+ to radio stations via mplayer (or mpv) and similar activities.
69
+
70
+ The file **radio_stations.yml** is evidently catered to my own use
71
+ case. If you wish to use your own .yml file then you can do so by
72
+ setting the environment variable called **MULTIMEDIA_PARADISE_RADIO_STATIONS**
73
+ to the path of a local yaml file. For the necessary format, see the
74
+ file **radio_stations.yml** that comes distributed with this **.gem**.
75
+
76
+ I may listen to local internet radio stations but also to external
77
+ ones, such as **BBC**. The following example shows how I tap into
78
+ this functionality, first by showing BBC 1:
79
+
80
+ multimedia_paradise --bbc1
81
+ multimedia_paradise --bbc2
82
+ multimedia_paradise --bbc3
83
+ multimedia_paradise --bbc4
84
+ multimedia_paradise --fm4
85
+
86
+ The above list may be extended in the future, but for now (December
87
+ 2018) it shall suffice.
88
+
89
+ Do note that this functionality depends on a multimedia player,
90
+ such as **mpv** or **mplayer**. See elsewhere in this document
91
+ how to set to use such a multimedia player.
92
+
93
+ ## Streamripper support
94
+
95
+ There is code support for streamripper, just a tiny wrapper.
96
+
97
+ This can be invoked like so:
98
+
99
+ MultimediaParadise.streamripper
100
+
101
+ This depends on the file <b>streamripper_wrapper.rb</b> which
102
+ is just a tiny, pure-ruby "wrapper" over streamripper. (It
103
+ really only directly calls the streampripper binary, so
104
+ nothing fancy.)
105
+
106
+ ## Modifying the timestamps of .srt files
107
+
108
+ The file <b>srt_regex.rb</b> can be used if you need to batch-modify
109
+ .srt files, when they have the wrong timestamp, for instance. This
110
+ was exactly the reason why I wrote that class - some .srt files
111
+ may have a wrong offset, and so we need to correct them.
112
+
113
+ Note that this class is quite old and the code quality is not as
114
+ high as other classes since I wrote it a long time ago. I may
115
+ improve on it eventually, but for the time being, assume that
116
+ it isn't one of the best classes in this project.
117
+
118
+ ## Watermarking videos
119
+
120
+ A <b>watermark</b> is a specific tag to a video. This can be a
121
+ <b>logo</b> but it can also be used as some kind of (annoying)
122
+ filter.
123
+
124
+ Whatever your use case may be, ffmpeg supports watermarking
125
+ videos - and multimedia_paradise taps right into that
126
+ functionality.
127
+
128
+ Adding a watermark to a video is possible and quite simple.
129
+ The class that does so, in regards to the MultimediaParadise
130
+ project, is aptly called <b>Watermark</b> and it allows you
131
+ to use FFMPEG to embed a watermark video, using the
132
+ simple <b>MultimediaParadise.watermark()</b> method.
133
+
134
+ I rarely need to use this method so it may not be as
135
+ polished as other parts of the project, though.
136
+
137
+ The default use is to simply call that .rb file and pass a
138
+ video file to it:
139
+
140
+ vwatermark /Depot/Temp/MultimediaProject/foobar.mp4
141
+
142
+ (vwatermark is an alias on my system.)
143
+
144
+ If you want to use your own image, then you have to pass an
145
+ additional argument to the method, which should be the path
146
+ to the image at hand.
147
+
148
+ vwatermark /Depot/Temp/MultimediaProject/foobar.mp4 /opt/my_awesome_logo.png
149
+
150
+ ## Embedding Youtube Videos
151
+
152
+ "Embedding" Youtube Videos is also possible. Note the quotes.
153
+
154
+ The code is in the file **multimedia_paradise/video/youtube_embedder.rb**.
155
+
156
+ ## Increasing the volume of an audio file
157
+
158
+ You can use the module-level method:
159
+
160
+ MultimediaParadise.increase_volume_of_this_audio_file()
161
+
162
+ The **first argument** to this method should be the name of the file
163
+ that you wish to modify or the name of the files. This is usually
164
+ a file such as foobar.mp3 or similar.
165
+
166
+ The **second argument** is the modified percentage value that is
167
+ given to -v (and to **sox**). For example, if you pass in 2.0,
168
+ then the volume of the audio file at hand will be **increased
169
+ twofold**. If it is 3.0, then it will be increased threefold,
170
+ and so on.
171
+
172
+ Since the name of the method is "increase_volume", that particular
173
+ method can not be used to decrease the volume (via negative
174
+ floats such as -2.0).
175
+
176
+ ## Download videos from Google
177
+
178
+ The file google_video_downloader.rb can be used to download
179
+ videos from Google - but we may have to use youtube-dl for
180
+ this, which is python. This is not ideal since we use ruby :)
181
+ but I am too lazy to clone the functionality of <b>youtube-dl</b>
182
+ for now, so this just has to be glue code really. (Glue code
183
+ is for lazy people and I am lazy.)
184
+
185
+ ## Extracting audio from any given video file
186
+
187
+ You can extract audio from any given video file, by making
188
+ use of <b>class MultimediaParadise::ExtractAudio</b>. This
189
+ presently depends on <b>ffmpeg</b>, so you must have
190
+ ffmpeg available.
191
+
192
+ Usage example follows:
193
+
194
+ MultimediaParadise::ExtractAudio.new('foobar.avi')
195
+
196
+ This assumes that a video file called **foobar.avi** exists.
197
+
198
+ A **toplevel method** exists for this functionality as well:
199
+
200
+ MultimediaParadise.extract_audio(target_file_here)
201
+ MultimediaParadise.extract_audio('/tmp/foobar.avi')
202
+ MultimediaParadise.extract_audio('/home/lala.mp4')
203
+
204
+ Perhaps you may find the latter variant to be easier to read and
205
+ use than the variant that uses explicit **::** scoping for the
206
+ instantiation of **class ExtractAudio**. Under the hood, both
207
+ variants do the same of course.
208
+
209
+ ## Screen capture
210
+
211
+ If you want to capture the screen, that is, to record what
212
+ is happening, have a look at the class called
213
+ <b>MultimediaParadise::CaptureScreen</b>, in the file
214
+ **multimedia_paradise/video/capture_screen.rb**.
215
+
216
+ ## Autoinclude the main namespace
217
+
218
+ Since April 2014 you can autoinclude this project's main
219
+ namespace (toplevel **MultimediaParadise constant**)
220
+ by using the following ruby code:
221
+
222
+ require 'multimedia_paradise/autoinclude'
223
+
224
+ ## Using the executable bin/mpa
225
+
226
+ **mpa** is a small wrapper over mpv (or mplayer).
227
+
228
+ It is tailored to my own local videoset, which I store in
229
+ a yaml file. I am not sure how to best have other people
230
+ use mpa without the .yml file, but at the worst, it
231
+ is possible to just use bin/multimedia_paradise to play
232
+ an existing local video or audio file.
233
+
234
+ ## Guessing video names
235
+
236
+ I use a **.yml** file to keep track of registered video files.
237
+
238
+ I also needed a class that tells me the most likely name of a
239
+ video file, e. g. if the input is "Ninja", then this class
240
+ should report all Ninja video files, properly sorted, according
241
+ to the information contained in that .yml file. (This of course
242
+ requires that this genre is registered in that .yml file.)
243
+
244
+ **class MultimediaParadise::GuessVideoName** does precisely
245
+ that. Input the given search term at hand, such as **horror**
246
+ for horror movies, and it should hopefully report some information
247
+ that may be useful in order to find/name the video file at hand.
248
+
249
+ Note that this depends on a properly formatted .yml file; and
250
+ ideally you would create your own .yml file, with your own
251
+ tags, videos and so forth.
252
+
253
+ The **format** of the .yml file should be like this:
254
+
255
+ a) The number of the video file at hand, as an **Integer** value,
256
+ such as 1, 2, 3 and so forth.
257
+ b) A **hash** that describes at the least the 'title', but
258
+ may also contain entries such as <b>imdb:</b> and so forth.
259
+
260
+ ## Finding local videos
261
+
262
+ The file <b>find_video.rb</b> can be of help here as it will
263
+ try to locate local videos.
264
+
265
+ This is optimized towards my own dataset compiled about
266
+ videos; in the future, I will most likely provide a way
267
+ so that other people can also use their own dataset.
268
+ (The dataset I use is a simple yaml file storing all
269
+ information about the local videos.)
270
+
271
+ ## Playing a random (video or audio) file
272
+
273
+ <b>class MultimediaParadise::PlayRandomFile</b> can play a
274
+ random multimedia file. Since this will select a file
275
+ randomly, you can only pass in a directory for now - although
276
+ passing in an Array may also make sense, so perhaps this
277
+ class will be extended at a later time.
278
+
279
+ ## AudioPlayer
280
+
281
+ This class is just a thin "wrapper" over **mplayer** or
282
+ **mpv** really. It has been created in **early June 2014**.
283
+
284
+ The file can be found at
285
+ **multimedia_paradise/audio/audio_player/audio_player.rb**.
286
+
287
+ It was originally created because I needed to play, via
288
+ the commandline, audio songs in a <b>loop</b> - like a
289
+ **juke box**. I wanted it to be very simple too, so no
290
+ ncurses interface to it.
291
+
292
+ I also use it to perform wake-up calls in the morning, like
293
+ an alarm clock.
294
+
295
+ There is an **executable** for this, at **bin/audio_player**,
296
+ which acts as entry point to the code behind it, for
297
+ <b>class MultimediaParadise::AudioPlayer</b>:
298
+
299
+ If you want to play in a loop, you can pass the argument
300
+ "loop" or just "l".
301
+
302
+ Since as of the 24th February 2018, it can also act as a
303
+ "timer", together with class <b>Roebe::At</b>. For example,
304
+ if you want to play random songs at the time 21:35:00,
305
+ you can do:
306
+
307
+ rsong 21:35:00
308
+
309
+ Note that <b>rsong</b> is simply an alias that I use towards
310
+ <b>bin/audio_player</b>. Without an alias, the above becomes:
311
+
312
+ audio_player 21:35:00
313
+
314
+ Usually I tend to use <b>mpv</b>, but sometimes I do use
315
+ mplayer, e. g. when mpv has some problem due to recent
316
+ API changes. In this case, one can specify to use mplayer
317
+ on the commandline, via:
318
+
319
+ rsong 10:00:00 --use-mplayer
320
+
321
+ ## Delaying the audio of a video-file
322
+
323
+ FFmpeg allows you to easily delay the audio of a video file.
324
+
325
+ MultimediaParadise has this included as well, via:
326
+
327
+ MultimediaParadise.delay_audio()
328
+
329
+ The first argument to this should be the name of the file
330
+ that you wish to manipulate, such as <b>foobar.mp4</b>.
331
+
332
+ The second argument is the amount of seconds for the delay,
333
+ such as 5.53 seconds.
334
+
335
+ A new video-file will be generated as a consequence, if all
336
+ goes well.
337
+
338
+ ## Denoising audio/video
339
+
340
+ This subsection is about <b>removing noise from a multimedia file</b>.
341
+
342
+ **Noise** in this context refers to **unwanted audio**, such as
343
+ scratching on a blackboard during a university lecture, and similar
344
+ unwanted noises.
345
+
346
+ First, this functionality was needed because I inherited **audio recordings**
347
+ that were made via a cheap mp3-recorder from like **+10 years ago** or so,
348
+ say, the year 2009 - something like that.
349
+
350
+ The human voice has a **frequency range** between **300Hz** - **3000Hz**.
351
+
352
+ The **noise** in these files was extremey disturbing and distracting, and
353
+ I wanted to get rid of it, in order to more easily hear the voice of the
354
+ speaker. This also included increasing the volume as well, but that is
355
+ for another subsection.
356
+
357
+ The subsection here will additionally report some of my findings from back
358
+ then - as a **memo**.
359
+
360
+ A simple **filter-strategy** is to **first apply highpass**, and then
361
+ **lowpass**, via **ffmpeg**, such as in this way:
362
+
363
+ ffmpeg -i foobar.mp3 -af "lowpass=f=3000, highpass=f=200" output.mp3
364
+
365
+ Your local file comes first, such as the file **foobar.mp3*. This should
366
+ remove some of the noise that you may find in a recording, but you may
367
+ have to tweak the values a little in order to get the most out of it.
368
+
369
+ Note that you can use ffplay to see the effect of this:
370
+
371
+ ffplay INPUT_FILE -af lowpass=3000,highpass=200
372
+ ffplay foobar.mp3 -af lowpass=4000,highpass=200
373
+ ffplay foobar.mp3 -af lowpass=2000,highpass=200
374
+
375
+ I integrated this functionality into **MultimediaParadise**, via the
376
+ following simple API:
377
+
378
+ MultimediaParadise.denoise('foobar.mp3')
379
+
380
+ This is the default use case, by just supplying the name/path to the
381
+ audio file in question.
382
+
383
+ The second argument to this method is the **lowpass value**; the
384
+ third argument is for the **highpass value**:
385
+
386
+ MultimediaParadise.denoise('foobar.mp3', '250', '2000')
387
+
388
+ This, surprisingly enough, worked. But I do not think it is
389
+ the ideal value.
390
+
391
+ For more information, see the following blog entry from 2017:
392
+
393
+ https://manerosss.wordpress.com/2017/07/24/ffmpeg-%C2%B7-apply-a-filter-to-enhance-voice-by-removing-low-and-high-frequency-noises/
394
+
395
+ If you need to find out which values are best, you can use <b>ffplay</b>
396
+ such as in this way:
397
+
398
+ ffplay INPUT -af lowpass=3000,highpass=200
399
+
400
+ ## Creating a screencast with multimedia_paradise and FFMPEG
401
+
402
+ Code in the file **multimedia_paradise/toplevel_methods/screencast.rb** can
403
+ be used to record a screencast (on Linux).
404
+
405
+ The API is as follows:
406
+
407
+ MultimediaParadise.start_screencast
408
+
409
+ The method accepts several parameters - if you need fine tuning then
410
+ have a look at that file.
411
+
412
+ Presently only video without audio can be recorded, but there are
413
+ tutorials out there that enable recording of audio as well. I will
414
+ have a look into this at a later time (<- written in September 2018).
415
+
416
+ ## Changing the audio code of a video file via FFMpeg
417
+
418
+ If you want to change the audio codec in a given video file, say,
419
+ **foobar.avi**, then you can use this API:
420
+
421
+ MultimediaParadise.use_lame_codec('foobar.avi')
422
+
423
+ This essentially just combines **-vcodec copy -acodec libmp3lame**
424
+ but I wanted to have a simpler top-level API in ruby for this too,
425
+ so this method was added.
426
+
427
+ ## Query the audio codec of a video file
428
+
429
+ You can use this top-level API to determine the audio codec of a
430
+ video file:
431
+
432
+ MultimediaParadise.query_the_audio_codec_of_this_file()
433
+ MultimediaParadise.query_the_audio_codec()
434
+ MultimediaParadise.audio_codec?()
435
+
436
+ All variants listed above work; the last option is the shortest
437
+ one, apparently.
438
+
439
+ The argument should be the path to a locally existing videofile.
440
+
441
+ Say that your file is at **/Depot/foobar.avi** then the ruby code
442
+ may look like this:
443
+
444
+ require 'multimedia_paradise'
445
+ uses_this_codec = MultimediaParadise.audio_codec?('/Depot/foobar.avi')
446
+
447
+ This functionality **depends on ffmpeg**.
448
+
449
+ ## Converting into .mp3 format
450
+
451
+ You can use class **MultimediaParadise::Audio::ToMp3** to convert
452
+ e. g. a **.wav** file into a **.mp3** file:
453
+
454
+ MultimediaParadise::Audio::ToMp3.new('path_to_wav.waf')
455
+
456
+ As this may be a bit cumbersome to type, there exists a simpler
457
+ **top-level method** to convert an audio-file into the **.mp3
458
+ format**:
459
+
460
+ MultimediaParadise.to_mp3(*input_files_here)
461
+ MultimediaParadise.to_mp3( %( foo.wav bar.wav ) )
462
+
463
+ ## ffmpeg options
464
+
465
+ This subsection just shows a few options for ffmpeg; I added this mostly
466
+ because I tend to be quite forgetful. That way I can have a quick
467
+ overview on the homepage of this gem here.
468
+
469
+ |Commandline flag | Example | Implementation Status
470
+ |-----------------|------------------------|----------------------------------------------------------------------------------------|
471
+ | **-s** | **-s 500×500** | convert the video into a **width x height** ratio, of 500 x 500 pixel |
472
+ | **-vcodec** | **-vcodec mpeg4** | specify which video-codec is to be used, e. g. for the conversion of a video file |
473
+
474
+ ## Playing several multimedia-files from a list/file
475
+
476
+ You can pass a list of files that the MultimediaParadise project
477
+ should play.
478
+
479
+ The toplevel method is **MultimediaParadise.play_this_list()**,
480
+ so for example:
481
+
482
+ MultimediaParadise.play_this_list '
483
+
484
+ /Users/x/VIDEO/Cartoons/Simpsons-09/Treehouse_Of_Horror_VIII.m4v
485
+ /Users/x/VIDEO/Cartoons/Simpsons-09/The_Joy_Of_Sect.m4v
486
+ /Users/x/VIDEO/Cartoons/Simpsons-08/The_Springfield_Files.m4v
487
+
488
+ '
489
+
490
+ Empty lines will be ignored, so the method will only play these
491
+ entries if they are not empty.
492
+
493
+ The alias **MultimediaParadise.play_from_this_list()** would also
494
+ work, by the way.
495
+
496
+ I needed this functionality because sometimes other classes written
497
+ in ruby may show, on the commandline, such a flat list, via a long
498
+ String broken by newlines.
499
+
500
+ ## Environment variables for the MultimediaParadise project
501
+
502
+ The MultimediaParadise project is tailored to my own needs primarily,
503
+ which means that other people may not necessarily benefit from the
504
+ project as much. Additionally, as of December 2018, there are some
505
+ hardcoded paths, which makes this even worse. I have decided in
506
+ December 2018 that this approach will change in the future.
507
+
508
+ For the time being, you can use certain ENV (environment) flags to
509
+ specify where your audio/video files are kept. This assumes that
510
+ you have **one central directory** for these files; respectively
511
+ up to two, if you keep your audio and video files **separate**.
512
+
513
+ For specifying where your **local video files** reside, you can use the
514
+ constant called **MULTIMEDIA_PARADISE_DEPOT_VIDEO**. Simply
515
+ set this, in your shell, to be the path to the directory where
516
+ your video files may be, such as in:
517
+
518
+ export MULTIMEDIA_PARADISE_DEPOT_VIDEO=/opt/videos
519
+
520
+ A similar constant exists for audio files; simply set
521
+ **MULTIMEDIA_PARADISE_DEPOT_AUDIO**.
522
+
523
+ export MULTIMEDIA_PARADISE_DEPOT_AUDIO=/opt/my_songs
524
+
525
+ ## Genre support of video files
526
+
527
+ If you have a .yml file that keeps your video files
528
+ sorted, then you can also use a <b>genre:</b> tag
529
+ identifier to classify the video at hand.
530
+
531
+ For example, the movie <b>The Blade Runner</b> may have an associated
532
+ genre called <b>Science Fiction</b>. The movie <b>Poltergeist</b> may
533
+ have a genre tag called <b>Horror</b> and so on.
534
+
535
+ Once the genre-tagging has been done, we can search
536
+ for these genres on the commandline, via class
537
+ <b>VideoGenres</b>.
538
+
539
+ See its --help option for commands.
540
+
541
+ video_genres --help
542
+
543
+ If you wish to find out which science fiction movies
544
+ are registered, do:
545
+
546
+ video_genres --genre="Science Fiction"
547
+
548
+ You can also use a shorter variant, via a Pseudo-Regex:
549
+
550
+ video_genres "/Science Fiction/"
551
+
552
+ Some shortcuts exist if the above is too cumbersome. For example,
553
+ all science fiction movies could also be shown via this way:
554
+
555
+ video_genres --science-fiction
556
+
557
+ To see the available video genres, do this:
558
+
559
+ video_genres --available-video-genres
560
+
561
+ It you want to play a **random** horror movie, provided that you
562
+ have these registered tags, you can do the following:
563
+
564
+ video_genres --play-random-video-from-this-genre=horror
565
+
566
+ ## Copying and merging the same video
567
+
568
+ If you sort of wish to "duplicate" a video, but append this
569
+ onto an existing one, then you can use this method:
570
+
571
+ MultimediaParadise.copy_and_merge_this_video_n_times
572
+
573
+ The first argument should be the existing video file; the
574
+ second argument should be how many times it should be
575
+ "repeated", which should be a number. For example, the
576
+ number 5 means that the video will be merged onto itself
577
+ 4 times, thus creating a video that is 5x the length (all
578
+ with the same content).
579
+
580
+ There are alternatives to this, such as looping the same
581
+ video; but I wanted to really be able to have the same
582
+ video be played over and over again, even though this
583
+ made the size larger.
584
+
585
+ ## MultimediaParadise::AnalyseMultimediaFile
586
+
587
+ class **MultimediaParadise::AnalyseMultimediaFile** can be used
588
+ to analyse multimedia files (e. g. audio and video files),
589
+ on the commandline.
590
+
591
+ I needed this because **ffmpeg -i** alone was tiresome to
592
+ read.
593
+
594
+
595
+
596
+ ## Flipping and rotating video files
597
+
598
+ FFMpeg can easily flip video files. MultimediaParadise supports this
599
+ functionality too, through the file
600
+ <b>multimedia_paradise/toplevel_methods/flip_and_rotate.rb</b>.
601
+
602
+ Horizontal and vertical flipping is supported through these
603
+ two **toplevel APIs**:
604
+
605
+ MultimediaParadise.horizontal_flip()
606
+ MultimediaParadise.vertical_flip()
607
+
608
+ The latter variant also has a simpler, more intuitive API:
609
+
610
+ MultimediaParadise.flip_upside_down()
611
+
612
+ So essentially, you picture a video, and then simply flip
613
+ the top to the bottom, and the bottom to the top. Easy-peasy.
614
+
615
+ The **first argument** to this method should be the name/path
616
+ to an existing video file.
617
+
618
+ You can also rotate a video file by 90° via this API:
619
+
620
+ MultimediaParadise.rotate_this_video_file_by_90_degrees('foo.mpg')
621
+
622
+ Since as of March 2019, two more methods were added to flip a video
623
+ (rotate a video) clockwise and counter-clockwise, by 90° each:
624
+
625
+ MultimediaParadise.flip_video_to_the_right
626
+ MultimediaParadise.flip_video_to_the_left
627
+
628
+ So the older method **MultimediaParadise.rotate_this_video_file_by_90_degrees()**
629
+ is essentially the same as the newer method **MultimediaParadise.flip_video_to_the_right**.
630
+
631
+ ## Merging audio files together
632
+
633
+ **class MultimediaParadise::MergeAudioFiles** can be used to merge different
634
+ audio files together. If no specific input argument is provided then this
635
+ class will scan for all audio files in the current working directory and all
636
+ subdirectories, then merge these together into a new file called **output.mp3**.
637
+
638
+ I needed this functionality so that I could put lectures together into a single
639
+ file - made it easier to listen to a single file, rather than find them all
640
+ spread out.
641
+
642
+ ## Toplevel cutting multimedia files
643
+
644
+ This subsection deals with cutting multimedia files, that is,
645
+ to chop a longer file into one (or several) smaller files.
646
+
647
+ The primary method for this is called **MultimediaParadise.cut_from_to()**,
648
+ but you can also use a few aliases to this method, such as
649
+ **MultimediaParadise.cut()**.
650
+
651
+ The API is flexible.
652
+
653
+ Let's first show a few examples:
654
+
655
+ MultimediaParadise.cut_from_to('00:00:01-00:25:10', this_file: 'Tales_from_the_crypt_S05E10_Came_the_Dawn_1993.mp4')
656
+ MultimediaParadise.cut_from_to('00:02:23 / 00:28:04', this_file: 'Tales_from_the_crypt_S05E10_Came_the_Dawn_1993.mp4')
657
+ MultimediaParadise.cut(to: '00:22:50', this_file: 'TALES_FROM_THE_CRYPT/Tales_from_the_crypt_S06E11_Surprise_Party.mkv')
658
+
659
+ These are somewhat equivalent.
660
+
661
+ The simplest way may be to pass, as **first argument**, a String to
662
+ the method, denoting the start position and the end position, in
663
+ HH:MM:SS format. But you can also decide to use a Hash instead,
664
+ such as the third example shows.
665
+
666
+ Do note that if you decide to use a String, you can either use
667
+ the '-' variant or a ' / ' variant. The latter is the default
668
+ display format for the mpv video/audio player, so I added support
669
+ for it since copy/pasting may be a bit simpler that way.
670
+
671
+ The special key called **:this_file** should be the file that you
672
+ wish to cut. The absolute path should be given here; for my home
673
+ system I also use some fake-macros, such as TALES_FROM_THE_CRYPT/
674
+ to denote where tales from the crypt may reside (and other files).
675
+ This allows me to more easily make use of my local file system.
676
+
677
+ The key **:to** refers to the end position, that is, when to make
678
+ the cut.
679
+
680
+ The ideal scenario for this method is to simply cut from a start
681
+ position to an end position - in other words, to make an existing
682
+ video file shorter.
683
+
684
+ Do note that another class, called CutAudio, also exists as part of
685
+ the multimedia_paradise project. This is partially due to legacy
686
+ reasons; and partially due to CutAudio being primarily used for
687
+ .mp3 files, and for interactive use. One day the functionality
688
+ may be re-used, but for the time being I will keep it separate (less
689
+ work for now).
690
+
691
+ If you rather want a simple API, where you input only two Strings
692
+ usually (as parameters), then you could use:
693
+
694
+ MultimediaParadise.video_duration(of_this_file, '00:30:00-00:35:00')
695
+
696
+ The first argument would be the file that you wish to cut; and
697
+ the second is the duration, so two Strings in total. Interally this
698
+ will be passed to the method **MultimediaParadise.cut_from_to()**
699
+ anyway, so you could even use a Hash instead - but the primary use
700
+ case for that method is to allow for a simpler API. Use whatever
701
+ you prefer.
702
+
703
+ ## Setting the title metadata of a .mp3 file
704
+
705
+ Thanks to ffmpeg we can easily modify the metadata entry of a .mp3
706
+ file. MultimediaParadise supports this too, via:
707
+
708
+ MultimediaParadise.set_title_of(this_audio_file, this_title)
709
+
710
+ So the first argument should be the local path to a .mp3 file; and
711
+ the second argument should be the title that this .mp3 file should
712
+ have. I use this for batch-setting the title - and a file called
713
+ **bin/auto_title** exists that does this from the commandline as well.
714
+
715
+ ## CutAudio
716
+
717
+ You can cut audio files via the class **CutAudio**. The code to this
718
+ class resides under the subdirectory **multimedia_paradise/audio/cut_audio/**.
719
+
720
+ Invoke **cut_audio** (residing under **bin/cut_audio**) with the path
721
+ to an .mp3 file or another audio file. You will then enter the
722
+ **interactive menu** of class CutAudio, which allows you to do some
723
+ specific tasks related to cutting and merging audio files (see the
724
+ "help" section there, in interactive mode).
725
+
726
+ You may want to designate **start** and **stop** positions when in
727
+ interactive mode. You can do so via prefixing "s" and suffixing "e",
728
+ such as in the following way:
729
+
730
+ s10
731
+ e20
732
+
733
+ This would mean to "start at 10 seconds" and "end at 20 seconds". So
734
+ we will cut out the intermediate 10 seconds between these two points.
735
+
736
+ Via "play" you can play the audio file; I recommend having installed
737
+ **mplayer** or **mpv** for this task.
738
+
739
+ That way you can find out where you may wish to cut in the first place.
740
+
741
+ Once you have your start and end positions, you can run this command:
742
+
743
+ cut
744
+
745
+ This will cut out the selected subsection; in this case the part from
746
+ 10 seconds to 20 seconds.
747
+
748
+ The number specifies how many seconds are to be used. This
749
+ can sometimes be a bit difficult to calculate in your head
750
+ e. g. how many seconds do 83 minutes entail to.
751
+
752
+ A pseudo-calculator can be queried within class CutAudio.
753
+
754
+ For example:
755
+
756
+ 6*60
757
+
758
+ This would quickly show you that the result of this is 360
759
+ seconds (the input meant 6 minutes, if you think about it).
760
+
761
+ There are many more options available, so have a look at the
762
+ "help" section there. Keep in mind that CutAudio is a bit
763
+ complicated to use sometimes, and also has a very few bugs
764
+ as well (I did not get around to re-writing it, so for now
765
+ this has to suffice).
766
+
767
+ ## Resizing a video
768
+
769
+ **ffmpeg** makes it easy to resize a video.
770
+
771
+ For example, say that you wish to re-scale an existing video
772
+ to the same ratio, but with fewer pixels, like 640. You could
773
+ use the following commandline invocation, with the **-vf**
774
+ flag, for this task:
775
+
776
+ ffmpeg -i input.mp4 -vf scale=640:-1 output.mp4
777
+
778
+ In this case, output.mp4 will have 640 pixels in width.
779
+
780
+ The strange -1 is simply a way to tell ffmpeg that the
781
+ same aspect ratio should be kept. That way ffmpeg will
782
+ calculate which ratio value should be used, in order
783
+ to retain the original width:height relation. You can
784
+ sometimes see that people use the wrong aspect ratio,
785
+ and then their video may look distorted.
786
+
787
+ MultimediaParadise also supports this via:
788
+
789
+ MultimediaParadise.scale_this_video()
790
+ MultimediaParadise.resize_this_vide()
791
+
792
+ The first argument is the path to the local input-file,
793
+ such as **input.mp4*.
794
+
795
+ After that a Hash can be used, where **height** and **width**
796
+ can be given.
797
+
798
+ MultimediaParadise.scale_this_video('input.mp4', height: 320, width: 220)
799
+
800
+ The argument for :width can be omitted, in which case -1 will be used
801
+ as default:
802
+
803
+ MultimediaParadise.scale_this_video('input.mp4', height: 320)
804
+
805
+ Would be the same as:
806
+
807
+ MultimediaParadise.scale_this_video('input.mp4', height: 320, height: -1)
808
+
809
+ The value for height: can be ignored too, in which case it will default
810
+ to 640 - but this default value may change one day in the future, so it
811
+ may be better to specify at the least one value here. But, ultimately,
812
+ if you don't care, this could also work:
813
+
814
+ MultimediaParadise.scale_this_video('input.mp4')
815
+
816
+ We may even omit the first argument in the future, one day, if we
817
+ assign a default file on the toplevel - but for the time being
818
+ (**September 2019**), the API is how it is and requires **at the
819
+ least one argument**.
820
+
821
+ ## Creating a video out of an audio file, such as a .mp3 file
822
+
823
+ Via the API **MultimediaParadise.create_video_from_this_audio()**
824
+ you can "create" a video, from an audio file, such as a .mp3 file.
825
+
826
+ This requires a static image, which is the **second argument** to
827
+ that method.
828
+
829
+ Why did I add this method? I needed a way to upload .mp3 files
830
+ to a remote website but they had a **filter** removing .mp3 files;
831
+ they allowed for .mp4 files, so I converted it into a .mp4
832
+ file and that works. That is strange, since you can always
833
+ use **ffmpeg** to extract the .mp3 audio again - so I dont
834
+ understand the filter that prevents .mp3 upload but allows
835
+ .mp4 upload ...
836
+
837
+ Quite odd if you ask me.
838
+
839
+ **:\\**
840
+
841
+ **:/**
842
+
843
+ Anyway - here an example for the official API for this,
844
+ from within ruby:
845
+
846
+ this_audio_file = 'foobar.mp3'
847
+ this_image_file = '/FORENSIC_CAT.jpg'
848
+ MultimediaParadise.create_video_from_this_audio(this_audio_file, this_image_file)
849
+
850
+ ## MovieSearcher
851
+
852
+ class MovieSearcher can be used to look up information about a
853
+ movie from http://www.omdbapi.com, if you have an API key.
854
+
855
+ The code written for this class is not great, but if all you
856
+ need is some quick commandline information then this class
857
+ could be used. It can be found at
858
+ **multimedia_paradise/video/movie_searcher.rb**.
859
+
860
+ Since as of 02.01.2020, an executable is now distributed
861
+ as well, called **movie_searcher** (under the **bin** subdirectory
862
+ of this gem).
863
+
864
+ I have aliased this executable to **videorating**, and then simply
865
+ do this on the commandline:
866
+
867
+ videorating tremors
868
+
869
+ You may need an API key called **OMDBAPI_API_KEY**. I recommend
870
+ you to set this; class MovieSearch will then try to pick it up
871
+ when it was set (see the ruby code for this).
872
+
873
+ ## Deshaking videos
874
+
875
+ Ffmpeg has support for deshaking videos through a filter:
876
+
877
+ https://ffmpeg.org/ffmpeg-filters.html#deshake
878
+
879
+ The deshake-filter from ffmpeg helps remove camera shake from
880
+ hand-holding a camera.
881
+
882
+ The API for multimedia_paradise is the following:
883
+
884
+ MultimediaParadise.deshake(input_files_go_here)
885
+ MultimediaParadise.deshake('foobar.mp4')
886
+
887
+ ## Missing video files
888
+
889
+ Via:
890
+
891
+ mpa --missing-videos?
892
+
893
+ I can determine which video files are missing locally.
894
+
895
+ This is evidently catered to my own use case, and a big .yml
896
+ file that I maintain. You may have to create your own .yml
897
+ file here if you wish to make use of this functionality.
898
+
899
+ ## class ConvertAudioToVideoWithImage
900
+
901
+ **class ConvertAudioToVideoWithImage** allows you to "attach"
902
+ a static image file to an audio file, such as a <b>.mp3</b>
903
+ file.
904
+
905
+ This functionality depends on **ffmpeg**, so you need to
906
+ have ffmpeg available in order to make use of this class.
907
+
908
+ Two arguments are necessary to class ConvertAudioToVideoWithImage:
909
+
910
+ (1) first, the audio-file
911
+ (2) second, the image file that you wish to use
912
+
913
+ You can also use the following toplevel-method:
914
+
915
+ MultimediaParadise.to_avi_with_this_image()
916
+
917
+ with the same parameter pattern.
918
+
919
+ To give you a specific example - say that you have your .mp3
920
+ file at:
921
+
922
+ /Depot/j/foobar.mp3
923
+
924
+ And your image at:
925
+
926
+ /Depot/Images/foobar.png
927
+
928
+ Then the proper way to use the **toplevel-method** would be:
929
+
930
+ MultimediaParadise.to_avi_with_this_image('/Depot/j/foobar.mp3','/Depot/Images/foobar.png')
931
+
932
+ It does not have to be an **.avi** file though. You can also
933
+ use a .mp4 file via:
934
+
935
+ MultimediaParadise.to_mp4_with_this_image('foo.mp3','bar.png')
936
+
937
+ The latter method can also be used from the commandline via:
938
+
939
+ convert_audio_to_mp4video_with_image a.mp3 b.png
940
+
941
+ Remember that the audio file comes first, and the image file
942
+ comes last.
943
+
944
+ ## Removing the last second of an audio file
945
+
946
+ If you just need to quickly chop off the last 1 second from
947
+ an audio file then you can use this API:
948
+
949
+ MultimediaParadise::RemoveLastSecond.new(ARGV)
950
+ MultimediaParadise::RemoveLastSecond.new('foobar.mp3')
951
+
952
+ ## Encoding a video via MultimediaParadise
953
+
954
+ You can use the toplevel method called **MultimediaParadise.encode_this_video()**
955
+ to encode a video.
956
+
957
+ By default CRF will be used, which is the **Constant Rate Factor**.
958
+
959
+ Support for two-pass encoding has not been added to MultimediParadise,
960
+ but you can read up on ffmpeg how to do this:
961
+
962
+ https://trac.ffmpeg.org/wiki/Encode/H.264
963
+
964
+ Example:
965
+
966
+ require 'multimedia_paradise/toplevel_methods/encode_this_video.rb'
967
+ MultimediaParadise.encode_this_video('foobar.avi')
968
+
969
+ The default output for this will be .mkv, which is the matroska container.
970
+ (Currently that method in MultimediaParadise does not allow for
971
+ another output format, in **June 2020**; but this may be changed in the
972
+ future in another release of this project.)
973
+
974
+ ## MultimediaParadise.set_player_in_use()
975
+
976
+ The toplevel method **MultimediaParadise.set_player_in_use()** can
977
+ be used to set the main multimedia player (audio + video) in use
978
+ for the MultimediaProject. Normally I set this to **mplayer** or
979
+ **mpv**, but **vlc** or any other player could also be used here.
980
+
981
+ You can also quickly set to use **mpv** since as of the 30th
982
+ June 2020.
983
+
984
+ Usage example for permanently setting this:
985
+
986
+ multimedia_paradise --use-mpv
987
+
988
+ This will modify the content of a .yml file.
989
+
990
+ ## Playlists
991
+
992
+ The **MultimediaParadise** project can generate **.m3u** files, as
993
+ long as they are simple, e. g. one entry per line. For the purpose
994
+ of the document here, we will call such **.m3u** files
995
+ **playlists**.
996
+
997
+ The class responsible for the creation of **.m3u** files is
998
+ class <b>MultimediaParadise::CreateM3uPlaylist</b>, residing
999
+ at the location <b>multimedia_paradise/audio/create_m3u_playlist.rb</b>
1000
+ within the **MultimediaParadise** project.
1001
+
1002
+ The primary objective of this class is to generate that
1003
+ **.m3u** text file. Of course you can do so easily without the
1004
+ project - just do a "ls" and pipe it into a file - but I wanted
1005
+ this functionality specifically within the project, so that I
1006
+ can automate the creation of playlists, including batch-uploading
1007
+ to other sites at a later time, such as for youtube and other
1008
+ sites.
1009
+
1010
+ I myself use this class to generate playlists for various different
1011
+ **song types** - be these **eurodance songs**, **trance songs**,
1012
+ **pop songs** and so forth. Once such a .m3u file has been
1013
+ (auto)generated, it could then be used for upload to an external
1014
+ site, as mentioned, such as to **youtube** or other websites that
1015
+ support such playlists. Of course in order for this to work you may
1016
+ need to provide valid URLs to these individual entries somehow. The
1017
+ primary use case for class <b>MultimediaParadise::CreateM3uPlaylist</b>
1018
+ is for **local audio files**, though.
1019
+
1020
+ The input to class <b>MultimediaParadise::CreateM3uPlaylist</b>
1021
+ should ideally be a **yaml file** describing your songs (at the
1022
+ least the path to these songs), but you could also use the **API**
1023
+ from within Ruby, naturally (and thus use a **ruby array** directly
1024
+ that is to be passed to the class; just pass this Array to **.new()**).
1025
+
1026
+ You can also use this simpler **toplevel method**, in ruby
1027
+ instead:
1028
+
1029
+ MultimediaParadise.create_m3u_playlist()
1030
+
1031
+ The **first argument** to this method should contain the **dataset**
1032
+ that you will use for the .m3u file that is to be autogenerated.
1033
+ This should be a simple Array.
1034
+
1035
+ You can, naturally, rename the .m3u file after it has been created,
1036
+ since a default name will be used - the generic name used for
1037
+ generation of the file will be **playlist.m3u**.
1038
+
1039
+ For my own custom dataset, e. g. to generate a playlist
1040
+ with good **tales-from-the-crypt** videos, I can just do:
1041
+
1042
+ playlist --tales-from-the-crypt
1043
+
1044
+ The MultimediaParadise project also comes with another class,
1045
+ called **class Playlist**, which has a different task. That
1046
+ **class Playlist** will handle audio-playlists, primarily. For
1047
+ example, it can play audio files at certain positions in
1048
+ the playlist.
1049
+
1050
+ Usage example from the commandline for this:
1051
+
1052
+ playlist 33,44,55
1053
+
1054
+ Would play the songs at position 33, then 44 and then 55. It
1055
+ is thus a very primitive sort of **jukebox**. See
1056
+ **playlist --help** for help options.
1057
+
1058
+ You can change positions in that playlist. To exchange position
1059
+ 95 with position 94, you could use input like this:
1060
+
1061
+ playlist "95 -> 94"
1062
+
1063
+ This would mean to take the song at position 95 and move it
1064
+ to position 94. Conversely the song at position 94 will be
1065
+ moved to 95; this is thus ***an exchange operation***.
1066
+
1067
+ To show the entries of a playlist do:
1068
+
1069
+ playlist --show
1070
+
1071
+ ## The file video_collection.yml
1072
+
1073
+ The file video_collection.yml, which is distributed by this
1074
+ project, can be used to denote different videos files.
1075
+
1076
+ This is catered to my own use case, but you can adapt this
1077
+ file to your own use case.
1078
+
1079
+ I use the file to automatically handle local videos, such
1080
+ as batch-renaming or ensuring that everything is correct,
1081
+ and so on.
1082
+
1083
+ To determine the default (assumed) location, try this
1084
+ method:
1085
+
1086
+ MultimediaParadise.file_video_collection
1087
+
1088
+ ## Converting a video file to the corresponding images
1089
+
1090
+ Via:
1091
+
1092
+ MultimediaParadise.video_to_images
1093
+
1094
+ you can convert a video to its corresponding images.
1095
+
1096
+ See the file **multimedia_paradise/toplevel_methods/conversion.rb**
1097
+ for more information about that functionality - it is made possible
1098
+ thanks to ffmpeg.
1099
+
1100
+ ## Working with subtitles
1101
+
1102
+ You can embed subtitles into a video directly. This subsection
1103
+ explains how this can be done.
1104
+
1105
+ Embedding subtitles (text files such as .srt files) into a video
1106
+ file is trivial with ffmpeg. The multimedia_paradise project
1107
+ supports this as well, via the following toplevel API:
1108
+
1109
+ require 'multimedia_paradise/toplevel_methods/subtitles.rb'
1110
+ MultimediaParadise.embed_this_subtitle_onto_that_video('foo.srt','bar.avi')
1111
+
1112
+ If you wish to remove a subtitle from a video file, try this:
1113
+
1114
+ MultimediaParadise.remove_subtitles_from_this_video_file('foobar.mp4')
1115
+
1116
+ Since as of October 2020, a file called **bin/remove_subtitles**
1117
+ is made available as well, for commandline usage.
1118
+
1119
+ ## Graphical User Interface (GUI)
1120
+
1121
+ There is some ruby-gtk code for the MultimediaParadise available and
1122
+ distributed within this gem, mostly for **gtk2** right now. It is
1123
+ planned to transition into ruby-gtk3 at a later point, but this depends
1124
+ on many factors, including how well-polished the **gtk_paradise**
1125
+ gem is, since I use that gem a lot.
1126
+
1127
+ Note that in general a lot of the GUI parts of MultimediaParadise
1128
+ is in a **very experimental** state, subject to change, and possibly
1129
+ filled with bugs - but you can have a look at e. g. the **gtk-radio**
1130
+ part.
1131
+
1132
+ That one even has a stop/play/resume button, and an increase/decrease
1133
+ in audio volume, if ALSA is available. It lists some radio stations,
1134
+ based on a .yml file - you could use the same format and supply
1135
+ your own .yml file there, but support for this has not yet been
1136
+ added (need to re-think that part).
1137
+
1138
+ Evidently LOTS of features are missing there that might make sense
1139
+ for a GUI about radio-streams, and some bugs may exist as well, so
1140
+ don't use any of these widgets in "production" or for anything
1141
+ serious. I will, however had, try to make the GUI components,
1142
+ including the www-interfaces, more useful over the coming months
1143
+ and years, as time (and motivation) permits.
1144
+
1145
+ Note that for the first 10 buttons, you can access them via the
1146
+ keyboard too - by pressing ALT+number, such as **ALT+1** for
1147
+ the first button.
1148
+
1149
+ ## Additional documentation and information
1150
+
1151
+ In October 2020 I decided to publish all my collected local video
1152
+ and audio related content, which is made available through
1153
+ oldschool .cgi files. To make this even more complicated, most
1154
+ of these files are written in german so these have only a limited
1155
+ use for most people. Still, I think some of the information
1156
+ contained therein may be useful for other people, which is why
1157
+ I will publish this slowly over the coming months. Furthermore,
1158
+ some yaml-files are part of this, and publishing yaml files is
1159
+ useful, as it is decoupled from the programming language
1160
+ (in this case **ruby**).
1161
+
1162
+
1163
+ ## Contact information
1164
+
1165
+ If your creative mind has ideas and specific suggestions to make this
1166
+ gem more useful in general, feel free to drop me an email at any
1167
+ time, via:
1168
+
1169
+ shevegen@gmail.com
1170
+
1171
+ (Do keep in mind that responding to emails may take some time, depending
1172
+ on the amount of work I may have at that moment, due to reallife. I will,
1173
+ however had, read feedback. Patches and code changes are welcome too
1174
+ of course, as long as they are in the spirit of the project at
1175
+ hand, e. g. fitting to the general theme.)
1176
+
1177
+ Thank you.