このコミットが含まれているのは:
@@ -61,6 +61,13 @@ class PostImportsController < ApplicationController
|
||||
columns = Array(value['columns'])
|
||||
rows = Array(value['rows'])
|
||||
raise ArgumentError, '解析結果の形式が不正です.' unless columns.all?(Hash) && rows.all?(Hash)
|
||||
raise ArgumentError, '取込件数が多すぎます.' if rows.length > PostImportSourceParser::MAX_ROWS
|
||||
raise ArgumentError, '列数が多すぎます.' if columns.length > 50
|
||||
unless rows.all? { |row| Array(row['values']).length <= columns.length &&
|
||||
Array(row['values']).all? { _1.is_a?(String) && _1.bytesize <= PostImportSourceParser::MAX_CELL_BYTES } }
|
||||
raise ArgumentError, '解析結果のセルが不正です.'
|
||||
end
|
||||
raise ArgumentError, '解析結果が大きすぎます.' if rows.sum { Array(_1['values']).sum(&:bytesize) } > PostImportSourceParser::MAX_BYTES
|
||||
|
||||
{ columns: columns.map { |column| column.slice('key', 'label') },
|
||||
rows: rows.map { |row| { source_row: row['source_row'], values: Array(row['values']) } } }
|
||||
|
||||
@@ -26,6 +26,12 @@ class PostImportPreviewer
|
||||
should_fetch = fetch_metadata == true || fetch_metadata.to_i == row[:source_row].to_i
|
||||
metadata, fetch_warnings = metadata_for(url, should_fetch, metadata_cache, fetch_warnings)
|
||||
metadata.each do |field, value|
|
||||
if field == 'tags' && provenance[field] != 'manual'
|
||||
previous_origin = provenance[field]
|
||||
attributes[field] = [attributes[field], value].compact.join(' ').split.uniq.join(' ')
|
||||
provenance[field] = previous_origin == 'automatic' ? 'automatic' : previous_origin
|
||||
next
|
||||
end
|
||||
next unless provenance[field] == 'automatic' || attributes[field].blank?
|
||||
|
||||
attributes[field] = value
|
||||
|
||||
@@ -7,21 +7,39 @@ class PostMetadataFetcher
|
||||
content = -> name { document.at_css("meta[property='#{ name }'], meta[name='#{ name }']")&.[]('content')&.strip.presence }
|
||||
duration = content.call('og:video:duration') || content.call('video:duration')
|
||||
published = content.call('article:published_time') || content.call('date')
|
||||
published_at = Time.zone.parse(published.to_s) if published.present?
|
||||
created_range = original_created_range(published)
|
||||
platform_tags = platform_tags(uri)
|
||||
{ title: metadata[:title],
|
||||
thumbnail_base: Preview::KnownSiteExtractor.thumbnail_url(uri) || metadata[:image_url],
|
||||
original_created_from: published_at&.iso8601,
|
||||
original_created_before: published_at && (published_at + 1.minute).iso8601,
|
||||
original_created_from: created_range&.first&.iso8601,
|
||||
original_created_before: created_range&.last&.iso8601,
|
||||
duration: duration&.to_f&.then { _1.positive? ? (_1 * 1_000).round : nil },
|
||||
tags: platform_tags.join(' ') }
|
||||
end
|
||||
|
||||
def self.platform_tags uri
|
||||
return ['動画', 'YouTube'] if Preview::KnownSiteExtractor.thumbnail_url(uri)
|
||||
return ['動画', 'YouTube'] if Preview::KnownSiteExtractor.youtube_video_id(uri)
|
||||
return ['動画', 'ニコニコ'] if Preview::KnownSiteExtractor.niconico_video_id(uri)
|
||||
|
||||
[]
|
||||
end
|
||||
private_class_method :platform_tags
|
||||
|
||||
def self.original_created_range value
|
||||
return nil if value.blank?
|
||||
|
||||
raw = value.to_s.strip
|
||||
from = Time.zone.parse(raw)
|
||||
before =
|
||||
case raw
|
||||
when /\A\d{4}\z/ then from + 1.year
|
||||
when /\A\d{4}-\d{2}\z/ then from + 1.month
|
||||
when /\A\d{4}-\d{2}-\d{2}\z/ then from + 1.day
|
||||
when /:\d{2}(?:Z|[+-]\d{2}:?\d{2})?\z/ then from + 1.second
|
||||
else from + 1.minute
|
||||
end
|
||||
[from, before]
|
||||
rescue ArgumentError, TypeError
|
||||
nil
|
||||
end
|
||||
private_class_method :platform_tags, :original_created_range
|
||||
end
|
||||
|
||||
@@ -4,6 +4,15 @@ module Preview
|
||||
youtube_thumbnail(uri)
|
||||
end
|
||||
|
||||
def self.youtube_video_id(uri)
|
||||
case uri.host&.downcase
|
||||
when 'youtu.be'
|
||||
uri.path.split('/').reject(&:blank?).first
|
||||
when 'www.youtube.com', 'youtube.com', 'm.youtube.com'
|
||||
uri.path == '/watch' ? URI.decode_www_form(uri.query.to_s).to_h['v'] : nil
|
||||
end&.then { _1 if _1.match?(/\A[A-Za-z0-9_-]{6,20}\z/) }
|
||||
end
|
||||
|
||||
def self.niconico_video_id(uri)
|
||||
case uri.host&.downcase
|
||||
when 'www.nicovideo.jp', 'nicovideo.jp'
|
||||
@@ -14,14 +23,8 @@ module Preview
|
||||
end
|
||||
|
||||
def self.youtube_thumbnail(uri)
|
||||
id =
|
||||
case uri.host&.downcase
|
||||
when 'youtu.be'
|
||||
uri.path.split('/').reject(&:blank?).first
|
||||
when 'www.youtube.com', 'youtube.com', 'm.youtube.com'
|
||||
uri.path == '/watch' ? URI.decode_www_form(uri.query.to_s).to_h['v'] : nil
|
||||
end
|
||||
return unless id&.match?(/\A[A-Za-z0-9_-]{6,20}\z/)
|
||||
id = youtube_video_id(uri)
|
||||
return unless id
|
||||
|
||||
"https://i.ytimg.com/vi/#{ id }/hqdefault.jpg"
|
||||
end
|
||||
|
||||
新しい課題から参照
ユーザをブロックする