class PostMetadataFetcher def self.fetch raw_url uri, = Preview::UrlSafety.validate(raw_url) response = Preview::HttpFetcher.fetch(uri.to_s, max_bytes: Preview::ThumbnailFetcher::HTML_MAX_BYTES) metadata = Preview::HtmlMetadataExtractor.extract(response) document = Nokogiri::HTML.parse(response.body) 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') 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: 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.youtube_video_id(uri) return ['動画', 'ニコニコ'] if Preview::KnownSiteExtractor.niconico_video_id(uri) [] end 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