Something something like soundcloud but not like soundcloud.
Log in, upload records, done.
Simple, easy, KISS.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

transcoding_utils.py 7.6KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238
  1. from __future__ import print_function
  2. import contextlib
  3. import os
  4. import wave
  5. import time
  6. import magic
  7. import mutagen
  8. from models import db, SoundInfo, Sound
  9. from utils import get_waveform, create_png_waveform, duration_song_human, add_user_log
  10. from pydub import AudioSegment
  11. from os.path import splitext
  12. from flask import current_app
  13. def get_basic_infos(fname):
  14. mt = magic.from_file(fname, mime=True)
  15. print("- File is type {0}".format(mt))
  16. # We are going to get: duration (in seconds), format (bits), rate (Hz),
  17. # channels (count), codec (or not)
  18. infos = {
  19. "duration": None,
  20. "format": None,
  21. "rate": None,
  22. "channels": None,
  23. "codec": None,
  24. "bitrate": None,
  25. "bitrate_mode": None,
  26. "type": None,
  27. "type_human": None,
  28. }
  29. # WAV
  30. if mt == "audio/x-wav":
  31. with contextlib.closing(wave.open(fname, "r")) as f:
  32. frames = f.getnframes()
  33. rate = f.getframerate()
  34. duration = frames / float(rate)
  35. infos["duration"] = round(duration, 1)
  36. infos["channels"] = f.getnchannels()
  37. infos["rate"] = f.getframerate()
  38. infos["codec"] = "PCM"
  39. infos["format"] = f.getsampwidth() * 8
  40. infos["type"] = "WAV"
  41. infos["type_human"] = "WAV"
  42. # MP3
  43. elif mt == "audio/mpeg":
  44. muta = mutagen.File(fname)
  45. if muta is None:
  46. print("! ERROR mutagen is null")
  47. return infos
  48. infos["duration"] = muta.info.length
  49. infos["channels"] = muta.info.channels
  50. infos["rate"] = muta.info.sample_rate
  51. infos["codec"] = muta.info.encoder_info
  52. infos["bitrate"] = muta.info.bitrate
  53. if muta.info.bitrate_mode == mutagen.mp3.BitrateMode.CBR:
  54. infos["bitrate_mode"] = "CBR"
  55. elif muta.info.bitrate_mode == mutagen.mp3.BitrateMode.VBR:
  56. infos["bitrate_mode"] = "VBR"
  57. else:
  58. infos["bitrate_mode"] = "ABR"
  59. infos["type"] = "MP3"
  60. infos["type_human"] = "Mpeg 3"
  61. # OGG
  62. elif mt == "audio/ogg":
  63. muta = mutagen.File(fname)
  64. if muta is None:
  65. print("! ERROR mutagen is null")
  66. return infos
  67. infos["duration"] = muta.info.length
  68. infos["channels"] = muta.info.channels
  69. infos["rate"] = muta.info.sample_rate
  70. infos["bitrate"] = muta.info.bitrate
  71. infos["type"] = "OGG"
  72. infos["type_human"] = "Ogg Vorbis"
  73. # FLAC
  74. elif mt == "audio/x-flac" or mt == "audio/flac":
  75. muta = mutagen.File(fname)
  76. if muta is None:
  77. print("! ERROR mutagen is null")
  78. return infos
  79. infos["duration"] = muta.info.length
  80. infos["channels"] = muta.info.channels
  81. infos["rate"] = muta.info.sample_rate
  82. infos["bitrate"] = muta.info.bitrate
  83. if "encoder" in muta.vc:
  84. infos["codec"] = " ".join(muta.vc["encoder"])
  85. infos["type"] = "FLAC"
  86. infos["type_human"] = "FLAC"
  87. else:
  88. print("! ERROR not supported")
  89. return infos
  90. def get_waveform_infos(fname):
  91. return get_waveform(fname)
  92. def work_transcode(sound_id):
  93. sound = Sound.query.get(sound_id)
  94. if not sound:
  95. print("- Cant find sound ID {id} in database".format(id=sound_id))
  96. return
  97. if not sound.transcode_needed:
  98. print("- Sound ID {id} doesn't need transcoding".format(id=sound_id))
  99. sound.transcode_state = Sound.TRANSCODE_DONE
  100. db.session.commit()
  101. add_user_log(
  102. sound.id,
  103. sound.user.id,
  104. "sounds",
  105. "info",
  106. "Transcoding not needed for: {0} -- {1}".format(sound.id, sound.title),
  107. )
  108. return
  109. if not sound.transcode_state == Sound.TRANSCODE_WAITING:
  110. print("- Sound ID {id} transcoding != TRANSCODE_WAITING".format(id=sound_id))
  111. return
  112. print("File: {0}: {1}".format(sound.id, sound.title))
  113. add_user_log(
  114. sound.id, sound.user.id, "sounds", "info", "Transcoding started for: {0} -- {1}".format(sound.id, sound.title)
  115. )
  116. fname = os.path.join(current_app.config["UPLOADED_SOUNDS_DEST"], sound.user.slug, sound.filename)
  117. _file, _ext = splitext(fname)
  118. _start = time.time()
  119. a = AudioSegment.from_file(fname)
  120. a.export("{0}.mp3".format(_file), format="mp3", bitrate="196k")
  121. print("From: {0}".format(fname))
  122. print("Transcoded: {0}.mp3".format(_file))
  123. elapsed = time.time() - _start
  124. print("Transcoding done: ({0}) {1}".format(elapsed, duration_song_human(elapsed)))
  125. sound.transcode_state = Sound.TRANSCODE_DONE
  126. info = sound.sound_infos.first()
  127. info.done_waveform = False
  128. _a, _b = splitext(sound.filename)
  129. sound.filename_transcoded = "{0}.mp3".format(_a)
  130. db.session.commit()
  131. add_user_log(
  132. sound.id, sound.user.id, "sounds", "info", "Transcoding finished for: {0} -- {1}".format(sound.id, sound.title)
  133. )
  134. def work_metadatas(sound_id, force=False):
  135. sound = Sound.query.get(sound_id)
  136. if not sound:
  137. print("- Cant find sound ID %(id)s in database".format(id=sound_id))
  138. return
  139. add_user_log(
  140. sound.id,
  141. sound.user.id,
  142. "sounds",
  143. "info",
  144. "Metadatas gathering started for: {0} -- {1}".format(sound.id, sound.title),
  145. )
  146. _infos = sound.sound_infos.first()
  147. if not _infos:
  148. _infos = SoundInfo()
  149. _infos.sound_id = sound.id
  150. # Generate Basic infos
  151. fname = os.path.join(current_app.config["UPLOADED_SOUNDS_DEST"], sound.user.slug, sound.filename)
  152. if not _infos.done_basic or force:
  153. print("- WORKING BASIC on {0}, {1}".format(sound.id, sound.filename))
  154. basic_infos = get_basic_infos(fname)
  155. print("- Our file got basic infos: {0}".format(basic_infos))
  156. _infos.duration = basic_infos["duration"]
  157. _infos.channels = basic_infos["channels"]
  158. _infos.rate = basic_infos["rate"]
  159. _infos.codec = basic_infos["codec"]
  160. _infos.format = basic_infos["format"]
  161. _infos.bitrate = basic_infos["bitrate"]
  162. _infos.bitrate_mode = basic_infos["bitrate_mode"]
  163. _infos.done_basic = True
  164. _infos.type = basic_infos["type"]
  165. _infos.type_human = basic_infos["type_human"]
  166. if not _infos.done_waveform or force:
  167. if sound.transcode_state == Sound.TRANSCODE_DONE:
  168. _f, _e = splitext(fname)
  169. fname_t = "{0}.mp3".format(_f)
  170. print("- WORKING ON TRANSCODED FOR WAVEFORM")
  171. else:
  172. fname_t = fname
  173. print("- WORKING WAVEFORM on {0}, {1}".format(sound.id, sound.filename))
  174. waveform_infos = get_waveform_infos(fname_t)
  175. print("- Our file got waveform infos: {0}".format(waveform_infos))
  176. _infos.waveform = waveform_infos
  177. if not waveform_infos:
  178. _infos.waveform_error = True
  179. add_user_log(
  180. sound.id,
  181. sound.user.id,
  182. "sounds",
  183. "info",
  184. "Got an error when generating waveform" " for: {0} -- {1}".format(sound.id, sound.title),
  185. )
  186. else:
  187. fdir_wf = os.path.join(current_app.config["UPLOADS_DEFAULT_DEST"], "waveforms", sound.user.slug)
  188. fname_wf = os.path.join(fdir_wf, sound.filename)
  189. if not os.path.isdir(fdir_wf):
  190. os.makedirs(fdir_wf)
  191. create_png_waveform(fname_t, fname_wf)
  192. _infos.done_waveform = True
  193. db.session.add(_infos)
  194. db.session.commit()
  195. add_user_log(
  196. sound.id,
  197. sound.user.id,
  198. "sounds",
  199. "info",
  200. "Metadatas gathering finished for: {0} -- {1}".format(sound.id, sound.title),
  201. )