Fix a bug where, if you were uploading an entire 4chan thread, then the source of each post would get set to the 4chan thread, rather than to the individual 4chan post.
141 lines
3.7 KiB
Ruby
141 lines
3.7 KiB
Ruby
# frozen_string_literal: true
|
|
|
|
class UploadMediaAsset < ApplicationRecord
|
|
extend Memoist
|
|
|
|
attr_accessor :file
|
|
|
|
belongs_to :upload
|
|
belongs_to :media_asset, optional: true
|
|
has_one :post, through: :media_asset
|
|
|
|
after_create :async_process_upload!
|
|
after_save :update_upload_status, if: :saved_change_to_status?
|
|
|
|
# XXX there are ~150 old assets with blank source urls because the source went bad id before the image url could be saved.
|
|
validates :source_url, format: { with: %r{\A(https?|file)://}i, message: "is not a valid URL" }
|
|
validates :page_url, format: { with: %r{\A(https?)://}i, message: "is not a valid URL" }, allow_nil: true
|
|
|
|
enum status: {
|
|
pending: 0,
|
|
processing: 100,
|
|
active: 200,
|
|
failed: 300,
|
|
}
|
|
|
|
scope :unfinished, -> { where(status: %w[pending processing]) }
|
|
scope :finished, -> { where(status: %w[active failed]) }
|
|
|
|
def self.visible(user)
|
|
if user.is_admin?
|
|
all
|
|
elsif user.is_anonymous?
|
|
none
|
|
else
|
|
where(upload: user.uploads)
|
|
end
|
|
end
|
|
|
|
def self.search(params, current_user)
|
|
q = search_attributes(params, [:id, :created_at, :updated_at, :status, :source_url, :page_url, :error, :upload, :media_asset, :post], current_user: current_user)
|
|
|
|
if params[:is_posted].to_s.truthy?
|
|
q = q.where.associated(:post)
|
|
elsif params[:is_posted].to_s.falsy?
|
|
q = q.where.missing(:post)
|
|
end
|
|
|
|
case params[:order]
|
|
when "id_desc"
|
|
q = q.order(id: :desc)
|
|
when "id_asc"
|
|
q = q.order(id: :asc)
|
|
else
|
|
q.apply_default_order(params)
|
|
end
|
|
end
|
|
|
|
def loading?
|
|
pending? || processing?
|
|
end
|
|
|
|
def finished?
|
|
active? || failed?
|
|
end
|
|
|
|
def file_upload?
|
|
source_url.starts_with?("file://")
|
|
end
|
|
|
|
# The source of the post after upload. This is either the image URL, if the image URL is convertible to a page URL
|
|
# (e.g. Pixiv), or the page URL if it's not (e.g. Twitter).
|
|
def canonical_url
|
|
if file_upload?
|
|
source_url
|
|
|
|
# If the source is an image URL that is convertible to a page URL, then use the image URL as the post source.
|
|
elsif Source::URL.page_url(source_url).present?
|
|
source_url
|
|
|
|
# If a better page URL can be found by the extractor (potentially with an API call), then use that as the source.
|
|
elsif source_extractor.page_url.present?
|
|
source_extractor.page_url
|
|
|
|
# If we can't find any better page URL, then just use the one we already have.
|
|
elsif page_url.present?
|
|
page_url
|
|
|
|
# Otherwise if we can't find a page URL at all, then just use the image URL.
|
|
else
|
|
source_url
|
|
end
|
|
end
|
|
|
|
def source_extractor
|
|
return nil if source_url.blank?
|
|
Source::Extractor.find(source_url, page_url)
|
|
end
|
|
|
|
# Calls `process_upload!`
|
|
def async_process_upload!
|
|
if file.present?
|
|
ProcessUploadMediaAssetJob.perform_now(self)
|
|
else
|
|
ProcessUploadMediaAssetJob.perform_later(self)
|
|
end
|
|
end
|
|
|
|
def process_upload!
|
|
update!(status: :processing)
|
|
|
|
if file.present?
|
|
media_file = MediaFile.open(file)
|
|
else
|
|
media_file = source_extractor.download_file!(source_url)
|
|
end
|
|
|
|
MediaAsset.validate_media_file!(media_file, upload.uploader)
|
|
MediaAsset.upload!(media_file) do |media_asset|
|
|
update!(media_asset: media_asset)
|
|
end
|
|
|
|
update!(status: :active)
|
|
rescue Exception => e
|
|
update!(status: :failed, error: e.message)
|
|
ensure
|
|
media_file&.close
|
|
end
|
|
|
|
def update_upload_status
|
|
upload.with_lock do
|
|
if upload.upload_media_assets.all?(&:failed?)
|
|
upload.update!(status: "error", error: upload.upload_media_assets.map(&:error).join("; "))
|
|
elsif upload.upload_media_assets.all?(&:finished?)
|
|
upload.update!(status: "completed")
|
|
end
|
|
end
|
|
end
|
|
|
|
memoize :source_extractor
|
|
end
|