media.py 4.9 KB

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