media.py 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150
  1. __filename__ = "media.py"
  2. __author__ = "Bob Mottram"
  3. __license__ = "AGPL3+"
  4. __version__ = "1.0.0"
  5. __maintainer__ = "Bob Mottram"
  6. __email__ = "bob@freedombone.net"
  7. __status__ = "Production"
  8. from blurhash import blurhash_encode as blurencode
  9. from PIL import Image
  10. import numpy
  11. import os
  12. import sys
  13. import json
  14. import commentjson
  15. import datetime
  16. from auth import createPassword
  17. from shutil import copyfile
  18. from shutil import rmtree
  19. from shutil import move
  20. def removeMetaData(imageFilename: str,outputFilename: str):
  21. imageFile = open(imageFilename)
  22. image = Image.open(imageFilename)
  23. data = list(image.getdata())
  24. imageWithoutExif = Image.new(image.mode, image.size)
  25. imageWithoutExif.putdata(data)
  26. imageWithoutExif.save(outputFilename)
  27. def getImageHash(imageFilename: str) -> str:
  28. return blurencode(numpy.array(Image.open(imageFilename).convert("RGB")))
  29. def isMedia(imageFilename: str) -> bool:
  30. permittedMedia=['png','jpg','gif','mp4','ogv','mp3','ogg']
  31. for m in permittedMedia:
  32. if imageFilename.endswith('.'+m):
  33. return True
  34. print('WARN: '+imageFilename+' is not a permitted media type')
  35. return False
  36. def createMediaDirs(baseDir: str,mediaPath: str) -> None:
  37. if not os.path.isdir(baseDir+'/media'):
  38. os.mkdir(baseDir+'/media')
  39. if not os.path.isdir(baseDir+'/'+mediaPath):
  40. os.mkdir(baseDir+'/'+mediaPath)
  41. def getMediaPath() -> str:
  42. currTime=datetime.datetime.utcnow()
  43. weeksSinceEpoch=int((currTime - datetime.datetime(1970,1,1)).days/7)
  44. return 'media/'+str(weeksSinceEpoch)
  45. def getAttachmentMediaType(filename: str) -> str:
  46. """Returns the type of media for the given file
  47. image, video or audio
  48. """
  49. mediaType=None
  50. imageTypes=['png','jpg','jpeg','gif']
  51. for mType in imageTypes:
  52. if filename.endswith('.'+mType):
  53. return 'image'
  54. videoTypes=['mp4','webm','ogv']
  55. for mType in videoTypes:
  56. if filename.endswith('.'+mType):
  57. return 'video'
  58. audioTypes=['mp3','ogg']
  59. for mType in audioTypes:
  60. if filename.endswith('.'+mType):
  61. return 'audio'
  62. return mediaType
  63. def attachMedia(baseDir: str,httpPrefix: str,domain: str,port: int, \
  64. postJson: {},imageFilename: str, \
  65. mediaType: str,description: str, \
  66. useBlurhash: bool) -> {}:
  67. """Attaches media to a json object post
  68. The description can be None
  69. Blurhash is optional, since low power systems may take a long time to calculate it
  70. """
  71. if not isMedia(imageFilename):
  72. return postJson
  73. fileExtension=None
  74. acceptedTypes=['png','jpg','gif','mp4','webm','ogv','mp3','ogg']
  75. for mType in acceptedTypes:
  76. if imageFilename.endswith('.'+mType):
  77. if mType=='jpg':
  78. mType='jpeg'
  79. if mType=='mp3':
  80. mType='mpeg'
  81. fileExtension=mType
  82. if not fileExtension:
  83. return postJson
  84. mediaType=mediaType+'/'+fileExtension
  85. print('Attached media type: '+mediaType)
  86. if fileExtension=='jpeg':
  87. fileExtension='jpg'
  88. if mediaType=='audio/mpeg':
  89. fileExtension='mp3'
  90. if port:
  91. if port!=80 and port!=443:
  92. if ':' not in domain:
  93. domain=domain+':'+str(port)
  94. mPath=getMediaPath()
  95. mediaPath=mPath+'/'+createPassword(32)+'.'+fileExtension
  96. if baseDir:
  97. createMediaDirs(baseDir,mPath)
  98. mediaFilename=baseDir+'/'+mediaPath
  99. attachmentJson={
  100. 'mediaType': mediaType,
  101. 'name': description,
  102. 'type': 'Document',
  103. 'url': httpPrefix+'://'+domain+'/'+mediaPath
  104. }
  105. if useBlurhash and mediaType=='image':
  106. attachmentJson['blurhash']=getImageHash(imageFilename)
  107. postJson['attachment']=[attachmentJson]
  108. if baseDir:
  109. if mediaType=='image':
  110. removeMetaData(imageFilename,mediaFilename)
  111. else:
  112. copyfile(imageFilename,mediaFilename)
  113. return postJson
  114. def archiveMedia(baseDir: str,archiveDirectory: str,maxWeeks=4) -> None:
  115. """Any media older than the given number of weeks gets archived
  116. """
  117. currTime=datetime.datetime.utcnow()
  118. weeksSinceEpoch=int((currTime - datetime.datetime(1970,1,1)).days/7)
  119. minWeek=weeksSinceEpoch-maxWeeks
  120. if archiveDirectory:
  121. if not os.path.isdir(archiveDirectory):
  122. os.mkdir(archiveDirectory)
  123. if not os.path.isdir(archiveDirectory+'/media'):
  124. os.mkdir(archiveDirectory+'/media')
  125. for subdir, dirs, files in os.walk(baseDir+'/media'):
  126. for weekDir in dirs:
  127. if int(weekDir)<minWeek:
  128. if archiveDirectory:
  129. move(os.path.join(baseDir+'/media', weekDir),archiveDirectory+'/media')
  130. else:
  131. # archive to /dev/null
  132. rmtree(os.path.join(baseDir+'/media', weekDir))