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.

utils.py 7.3KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259
  1. import datetime
  2. import hashlib
  3. import os
  4. import subprocess
  5. from os.path import splitext
  6. from flask import current_app
  7. from flask_security import current_user
  8. from models import db, Role, Logging, Config, UserLogging
  9. def gcfg():
  10. _config = Config.query.one()
  11. if not _config:
  12. return {"app_name": "ree2bits"}
  13. return {"app_name": _config.app_name}
  14. class InvalidUsage(Exception):
  15. status_code = 400
  16. def __init__(self, message, status_code=None, payload=None):
  17. Exception.__init__(self)
  18. self.message = message
  19. if status_code is not None:
  20. self.status_code = status_code
  21. self.payload = payload
  22. def to_dict(self):
  23. rv = dict(self.payload or ())
  24. rv["message"] = self.message
  25. rv["status"] = "error"
  26. rv["code"] = self.status_code
  27. return rv
  28. def is_admin():
  29. adm = Role.query.filter(Role.name == "admin").first()
  30. if not current_user or not current_user.is_authenticated or not adm:
  31. return False
  32. if adm in current_user.roles:
  33. return True
  34. return False
  35. def add_log(category, level, message):
  36. if not category or not level or not message:
  37. print("!! Fatal error in add_log() one of three variables not set")
  38. print("[LOG][{0}][{1}] {2}".format(level.upper(), category, message))
  39. a = Logging(category=category, level=level.upper(), message=message)
  40. db.session.add(a)
  41. db.session.commit()
  42. # categories used, they are used to map the item_id to the right model
  43. # - sounds
  44. # - albums
  45. # - user
  46. # - global
  47. def add_user_log(item, user, category, level, message):
  48. if not category or not level or not message or not item:
  49. print("!! Fatal error in add_user_log() one of three variables not set")
  50. print("[LOG][{0}][{1}][u:{2}i:{3}] {4}".format(level.upper(), category, user, item, message))
  51. a = UserLogging(category=category, level=level.upper(), message=message, item_id=item, user_id=user)
  52. db.session.add(a)
  53. db.session.commit()
  54. def duration_elapsed_human(seconds):
  55. print(seconds)
  56. seconds = round(seconds)
  57. minutes, seconds = divmod(seconds, 60)
  58. hours, minutes = divmod(minutes, 60)
  59. days, hours = divmod(hours, 24)
  60. years, days = divmod(days, 365.242199)
  61. minutes = int(minutes)
  62. hours = int(hours)
  63. days = int(days)
  64. years = int(years)
  65. if years > 0:
  66. return "%d y" % years
  67. elif days > 0:
  68. return "%d d" % days
  69. elif hours > 0:
  70. return "%d h" % hours + "s" * (hours != 1)
  71. elif minutes > 0:
  72. return "%d mn" % minutes + "s" * (minutes != 1)
  73. else:
  74. return "right now"
  75. def duration_song_human(seconds):
  76. if seconds is None:
  77. return "error"
  78. seconds = float(seconds)
  79. seconds = seconds
  80. minutes, seconds = divmod(seconds, 60)
  81. hours, minutes = divmod(minutes, 60)
  82. days, hours = divmod(hours, 24)
  83. years, days = divmod(days, 365.242199)
  84. minutes = int(minutes)
  85. hours = int(hours)
  86. days = int(days)
  87. years = int(years)
  88. if years > 0:
  89. return "%d year" % years + "s" * (years != 1)
  90. elif days > 0:
  91. return "%d day" % days + "s" * (days != 1)
  92. elif hours > 0:
  93. return "%d hour" % hours + "s" * (hours != 1)
  94. elif minutes > 0:
  95. return "%d mn" % minutes + "s" * (minutes != 1)
  96. else:
  97. return "%.2f sec" % seconds + "s" * (seconds != 1)
  98. def generate_audio_dat_file(filename):
  99. binary = current_app.config["AUDIOWAVEFORM_BIN"]
  100. if not os.path.exists(binary) or not os.path.exists(filename):
  101. add_log("AUDIOWAVEFORM", "ERROR", "Filename {0} or binary {1} invalid".format(filename, binary))
  102. return None
  103. fname, _ = splitext(filename)
  104. audio_dat = "{0}.dat".format(fname)
  105. cmd = [binary, "-i", filename, "-o", audio_dat, "-b", "8"]
  106. try:
  107. process = subprocess.run(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
  108. if not process:
  109. add_log("AUDIOWAVEFORM_DAT", "ERROR", "Subprocess returned None")
  110. return None
  111. except subprocess.CalledProcessError as e:
  112. add_log("AUDIOWAVEFORM_DAT", "ERROR", "Process error: {0}".format(e))
  113. return None
  114. print("- Command ran with: {0}".format(process.args))
  115. if process.stderr.startswith(b"Can't generate"):
  116. add_log("AUDIOWAVEFORM_DAT", "ERROR", "Process error: {0}".format(process.stderr))
  117. return None
  118. return audio_dat
  119. def get_waveform(filename):
  120. binary = current_app.config["AUDIOWAVEFORM_BIN"]
  121. if not os.path.exists(binary) or not os.path.exists(filename):
  122. add_log("AUDIOWAVEFORM", "ERROR", "Filename {0} or binary {1} invalid".format(filename, binary))
  123. return None
  124. fname, _ = splitext(filename)
  125. tmpjson = "{0}.json".format(fname)
  126. cmd = [binary, "-i", filename, "--pixels-per-second", "10", "-b", "8", "-o", tmpjson]
  127. """
  128. Failed: Can't generate "xxx" from "xxx"
  129. OK:
  130. Input file: piano2.wav
  131. Frames: 302712
  132. Sample rate: 48000 Hz
  133. Channels: 2
  134. Format: 0x10002
  135. Sections: 1
  136. Seekable: yes
  137. Generating waveform data...
  138. Samples per pixel: 4800
  139. Input channels: 2
  140. Done: 100%
  141. Read 302712 frames
  142. Generated 64 points
  143. Writing output file: some-file.json
  144. """
  145. try:
  146. process = subprocess.run(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
  147. if not process:
  148. add_log("AUDIOWAVEFORM", "ERROR", "Subprocess returned None")
  149. return None
  150. except subprocess.CalledProcessError as e:
  151. add_log("AUDIOWAVEFORM", "ERROR", "Process error: {0}".format(e))
  152. return None
  153. print("- Command ran with: {0}".format(process.args))
  154. if process.stderr.startswith(b"Can't generate"):
  155. add_log("AUDIOWAVEFORM", "ERROR", "Process error: {0}".format(process.stderr))
  156. return None
  157. with open(tmpjson, "r") as f:
  158. json = f.readlines()
  159. os.unlink(tmpjson)
  160. if isinstance(json, list):
  161. json = json[0].rstrip()
  162. return json
  163. def create_png_waveform(fn_audio, fn_png):
  164. binary = current_app.config["AUDIOWAVEFORM_BIN"]
  165. if not os.path.exists(binary) or not os.path.exists(fn_audio):
  166. add_log("AUDIOWAVEFORM_PNG", "ERROR", "Filename {0} or binary {1} invalid".format(fn_audio, binary))
  167. return None
  168. fname, _ = splitext(fn_png)
  169. pngwf = "{0}.png".format(fname)
  170. cmd = [
  171. binary,
  172. "-i",
  173. fn_audio,
  174. "--width",
  175. "384",
  176. "--height",
  177. "64",
  178. "--no-axis-labels",
  179. "--background-color",
  180. "FFFFFF00",
  181. "-o",
  182. pngwf,
  183. ]
  184. try:
  185. process = subprocess.run(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
  186. if not process:
  187. add_log("AUDIOWAVEFORM_PNG", "ERROR", "Subprocess returned None")
  188. return None
  189. except subprocess.CalledProcessError as e:
  190. add_log("AUDIOWAVEFORM_PNG", "ERROR", "Process error: {0}".format(e))
  191. return None
  192. print("- Command ran with: {0}".format(process.args))
  193. if process.stderr.startswith(b"Can't generate"):
  194. add_log("AUDIOWAVEFORM_PNG", "ERROR", "Process error: {0}".format(process.stderr))
  195. return None
  196. return True
  197. def get_hashed_filename(filename):
  198. f_n, f_e = splitext(filename)
  199. fs_fname = hashlib.sha256()
  200. hashed_format = "%s-%s" % (f_n, datetime.datetime.now())
  201. fs_fname.update(hashed_format.encode("utf-8"))
  202. fs_fname = fs_fname.hexdigest()
  203. return fs_fname + f_e