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 6.1KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211
  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 get_waveform(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. tmpjson = "{0}.json".format(filename)
  104. cmd = [binary, "-i", filename, "--pixels-per-second", "10", "-b", "8", "-o", tmpjson]
  105. """
  106. Failed: Can't generate "xxx" from "xxx"
  107. OK:
  108. Input file: piano2.wav
  109. Frames: 302712
  110. Sample rate: 48000 Hz
  111. Channels: 2
  112. Format: 0x10002
  113. Sections: 1
  114. Seekable: yes
  115. Generating waveform data...
  116. Samples per pixel: 4800
  117. Input channels: 2
  118. Done: 100%
  119. Read 302712 frames
  120. Generated 64 points
  121. Writing output file: some-file.json
  122. """
  123. try:
  124. process = subprocess.run(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
  125. if not process:
  126. add_log("AUDIOWAVEFORM", "ERROR", "Subprocess returned None")
  127. return None
  128. except subprocess.CalledProcessError as e:
  129. add_log("AUDIOWAVEFORM", "ERROR", "Process error: {0}".format(e))
  130. return None
  131. print("- Command ran with: {0}".format(process.args))
  132. if process.stderr.startswith(b"Can't generate"):
  133. add_log("AUDIOWAVEFORM", "ERROR", "Process error: {0}".format(process.stderr))
  134. return None
  135. with open(tmpjson, "r") as f:
  136. json = f.readlines()
  137. os.unlink(tmpjson)
  138. if isinstance(json, list):
  139. json = json[0].rstrip()
  140. return json
  141. def create_png_waveform(fn_audio, fn_png):
  142. binary = current_app.config["AUDIOWAVEFORM_BIN"]
  143. if not os.path.exists(binary) or not os.path.exists(fn_audio):
  144. add_log("AUDIOWAVEFORM_PNG", "ERROR", "Filename {0} or binary {1} invalid".format(fn_audio, binary))
  145. return None
  146. pngwf = "{0}.png".format(fn_png)
  147. cmd = [binary, "-i", fn_audio, "--width", "384", "--height", "64", "--no-axis-labels", "-o", pngwf]
  148. try:
  149. process = subprocess.run(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
  150. if not process:
  151. add_log("AUDIOWAVEFORM_PNG", "ERROR", "Subprocess returned None")
  152. return None
  153. except subprocess.CalledProcessError as e:
  154. add_log("AUDIOWAVEFORM_PNG", "ERROR", "Process error: {0}".format(e))
  155. return None
  156. print("- Command ran with: {0}".format(process.args))
  157. if process.stderr.startswith(b"Can't generate"):
  158. add_log("AUDIOWAVEFORM_PNG", "ERROR", "Process error: {0}".format(process.stderr))
  159. return None
  160. return True
  161. def get_hashed_filename(filename):
  162. f_n, f_e = splitext(filename)
  163. fs_fname = hashlib.sha256()
  164. hashed_format = "%s-%s" % (f_n, datetime.datetime.now())
  165. fs_fname.update(hashed_format.encode("utf-8"))
  166. fs_fname = fs_fname.hexdigest()
  167. return fs_fname + f_e