StorageManager: remove Post-specific code.
Refactor StorageManager to remove all image URL generation code. Instead the image URL generation code lives in MediaAsset. Now StorageManager is only concerned with how to read and write files to remote storage backends like S3 or SFTP, not with how image URLs should be generated. This way the file storage code isn't tightly coupled to posts, so it can be used to store any kind of file, not just images belonging to posts.
This commit is contained in:
@@ -48,102 +48,8 @@ class StorageManager
|
||||
raise NotImplementedError, "open not implemented"
|
||||
end
|
||||
|
||||
# Store or replace the given file belonging to the given post.
|
||||
# @param io [IO] the file to store
|
||||
# @param post [Post] the post the image belongs to
|
||||
# @param type [Symbol] the image variant to store (:preview, :crop, :large, :original)
|
||||
def store_file(io, post, type)
|
||||
store(io, file_path(post.md5, post.file_ext, type))
|
||||
end
|
||||
|
||||
# Delete the file belonging to the given post.
|
||||
# @param post_id [Integer] the post's id
|
||||
# @param md5 [String] the post's md5
|
||||
# @param file_ext [String] the post's file extension
|
||||
# @param type [Symbol] the image variant to delete (:preview, :crop, :large, :original)
|
||||
def delete_file(post_id, md5, file_ext, type)
|
||||
delete(file_path(md5, file_ext, type))
|
||||
end
|
||||
|
||||
# Return a readonly copy of the image belonging to the given post.
|
||||
# @param post [Post] the post
|
||||
# @param type [Symbol] the image variant to open (:preview, :crop, :large, :original)
|
||||
# @return [MediaFile] the image file
|
||||
def open_file(post, type)
|
||||
self.open(file_path(post.md5, post.file_ext, type))
|
||||
end
|
||||
|
||||
# Generate the image URL for the given post.
|
||||
# @param post [Post] the post
|
||||
# @param type [Symbol] the post's image variant (:preview, :crop, :large, :original)
|
||||
# @param tagged_filename [Boolean] whether the URL should contain the post's tags
|
||||
# @return [String] the image URL
|
||||
def file_url(post, type, tagged_filenames: false)
|
||||
subdir = subdir_for(post.md5)
|
||||
file = file_name(post.md5, post.file_ext, type)
|
||||
seo_tags = seo_tags(post) if tagged_filenames
|
||||
|
||||
if type == :preview && !post.has_preview?
|
||||
"#{root_url}/images/download-preview.png"
|
||||
elsif type == :preview
|
||||
"#{base_url}/preview/#{subdir}#{file}"
|
||||
elsif type == :crop
|
||||
"#{base_url}/crop/#{subdir}#{file}"
|
||||
elsif type == :large && post.has_large?
|
||||
"#{base_url}/sample/#{subdir}#{seo_tags}#{file}"
|
||||
else
|
||||
"#{base_url}/original/#{subdir}#{seo_tags}#{post.md5}.#{post.file_ext}"
|
||||
end
|
||||
end
|
||||
|
||||
def root_url
|
||||
origin = Addressable::URI.parse(base_url).origin
|
||||
origin = "" if origin == "null" # base_url was relative
|
||||
origin
|
||||
end
|
||||
|
||||
def file_path(post_or_md5, file_ext, type)
|
||||
md5 = post_or_md5.is_a?(String) ? post_or_md5 : post_or_md5.md5
|
||||
subdir = subdir_for(md5)
|
||||
file = file_name(md5, file_ext, type)
|
||||
|
||||
case type
|
||||
when :preview
|
||||
"/preview/#{subdir}#{file}"
|
||||
when :crop
|
||||
"/crop/#{subdir}#{file}"
|
||||
when :large
|
||||
"/sample/#{subdir}#{file}"
|
||||
when :original
|
||||
"/original/#{subdir}#{file}"
|
||||
end
|
||||
end
|
||||
|
||||
def file_name(md5, file_ext, type)
|
||||
large_file_ext = (file_ext == "zip") ? "webm" : "jpg"
|
||||
|
||||
case type
|
||||
when :preview
|
||||
"#{md5}.jpg"
|
||||
when :crop
|
||||
"#{md5}.jpg"
|
||||
when :large
|
||||
"sample-#{md5}.#{large_file_ext}"
|
||||
when :original
|
||||
"#{md5}.#{file_ext}"
|
||||
end
|
||||
end
|
||||
|
||||
def subdir_for(md5)
|
||||
"#{md5[0..1]}/#{md5[2..3]}/"
|
||||
end
|
||||
|
||||
# Generate the tags in the image URL.
|
||||
def seo_tags(post)
|
||||
return "" if !tagged_filenames
|
||||
|
||||
tags = post.presenter.humanized_essential_tag_string.gsub(/[^a-z0-9]+/, "_").gsub(/(?:^_+)|(?:_+$)/, "").gsub(/_{2,}/, "_")
|
||||
"__#{tags}__"
|
||||
def file_url(path)
|
||||
File.join(base_url, path)
|
||||
end
|
||||
|
||||
def full_path(path)
|
||||
|
||||
@@ -38,7 +38,9 @@ class MediaAsset < ApplicationRecord
|
||||
end
|
||||
|
||||
def open_file
|
||||
storage_service.open(file_path)
|
||||
file = storage_service.open(file_path)
|
||||
frame_data = media_asset.pixiv_ugoira_frame_data&.data if media_asset.is_ugoira?
|
||||
MediaFile.open(file, frame_data: frame_data)
|
||||
end
|
||||
|
||||
def convert_file(media_file)
|
||||
|
||||
@@ -74,36 +74,47 @@ class Post < ApplicationRecord
|
||||
module FileMethods
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
def storage_manager
|
||||
Danbooru.config.storage_manager
|
||||
def seo_tags
|
||||
presenter.humanized_essential_tag_string.gsub(/[^a-z0-9]+/, "_").gsub(/(?:^_+)|(?:_+$)/, "").gsub(/_{2,}/, "_")
|
||||
end
|
||||
|
||||
def file(type = :original)
|
||||
storage_manager.open_file(self, type)
|
||||
media_asset.variant(type).open_file
|
||||
end
|
||||
|
||||
def tagged_file_url(tagged_filenames: !CurrentUser.user.disable_tagged_filenames?)
|
||||
storage_manager.file_url(self, :original, tagged_filenames: tagged_filenames)
|
||||
slug = seo_tags if tagged_filenames
|
||||
media_asset.variant(:original).file_url(slug)
|
||||
end
|
||||
|
||||
def tagged_large_file_url(tagged_filenames: !CurrentUser.user.disable_tagged_filenames?)
|
||||
storage_manager.file_url(self, :large, tagged_filenames: tagged_filenames)
|
||||
slug = seo_tags if tagged_filenames
|
||||
|
||||
if media_asset.has_variant?(:sample)
|
||||
media_asset.variant(:sample).file_url(slug)
|
||||
else
|
||||
media_asset.variant(:original).file_url(slug)
|
||||
end
|
||||
end
|
||||
|
||||
def file_url
|
||||
storage_manager.file_url(self, :original)
|
||||
media_asset.variant(:original).file_url
|
||||
end
|
||||
|
||||
def large_file_url
|
||||
storage_manager.file_url(self, :large)
|
||||
if media_asset.has_variant?(:sample)
|
||||
media_asset.variant(:sample).file_url
|
||||
else
|
||||
media_asset.variant(:original).file_url
|
||||
end
|
||||
end
|
||||
|
||||
def preview_file_url
|
||||
storage_manager.file_url(self, :preview)
|
||||
media_asset.variant(:preview).file_url
|
||||
end
|
||||
|
||||
def crop_file_url
|
||||
storage_manager.file_url(self, :crop)
|
||||
media_asset.variant(:crop).file_url
|
||||
end
|
||||
|
||||
def open_graph_image_url
|
||||
@@ -1162,7 +1173,7 @@ class Post < ApplicationRecord
|
||||
|
||||
ModAction.log("<@#{user.name}> regenerated IQDB for post ##{id}", :post_regenerate_iqdb, user)
|
||||
else
|
||||
media_file = MediaFile.open(file, frame_data: pixiv_ugoira_frame_data&.data.to_a)
|
||||
media_file = media_asset.variant(:original).open_file
|
||||
media_asset.distribute_files!(media_file)
|
||||
|
||||
update!(
|
||||
|
||||
Reference in New Issue
Block a user