require 'uri' require 'fileutils' class VideoImage include Mongoid::Document include Mongoid::Timestamps include OrbitModel::Status include OrbitModel::Impression include OrbitTag::Taggable include OrbitCategory::Categorizable include Slug mount_uploader :file, VideoDataImageUploader mount_uploader :video_snapshot, VideoDataImageUploader mount_uploader :video_file, VideoDataUploader mount_uploader :video_file_webm, VideoDataUploader field :default_video_snapshot, type: Boolean, default: false field :auto_convert_video, type: Boolean, default: false field :title, as: :slug_title, type: String, localize: true field :keyword, type: String, localize: true field :desc, type: String, localize: true # field :weight, type: Integer, default: 1 # field :out_link, type: String # field :link_open, type: String field :postdate , type: Date, default: Date.today field :deadline , type: Date field :is_youtube, type: Boolean, default: false field :youtube , type: String field :youtube_id, type: String field :sort_number, type: Integer field :language_enabled, type: Array, default: ["en","zh_tw"] field :exchange_item, default: "1" # 1=>youtube, 2=>video file, 3=>image field :use_override_post_agency, type: Boolean, default: false field :override_post_agency, type: Integer, default: 0 field :create_user_id field :update_user_id field :view_count, type: Integer, default: 0 field :scale, type: Float # LINK_OPEN_TYPES = ["local", "new_window"] # before_save :add_http # validates :file, presence: true # validates :out_link, format: {:with=> /\A(http:\/\/|https:\/\/|\/)/i}, allow_blank: true # validates :title, presence: true scope :open_in_future, ->{where(:is_hidden.ne=>true,:is_preview.ne => true,:postdate.gt=>Time.now).order(postdate: :asc)} scope :can_display, ->{where(:is_hidden.ne=>true).valid_time_range} scope :can_display_and_sorted, ->{can_display.sorted} scope :valid_time_range, ->{any_of({:postdate.lte=>Time.now, :deadline.gte=>Time.now},{:postdate.lte=>Time.now, :deadline=>nil},{:postdate=>nil,:deadline.gte=>Time.now},{:postdate=>nil,:deadline=>nil})} scope :sorted, ->{order({is_top: :desc,postdate: :desc,id: :desc})} scope :is_expired, ->{self.and(VideoImage.unscoped.or({:deadline.lte=>Time.now}).selector)} scope :not_expired, ->{self.and(VideoImage.unscoped.or({:deadline.gte=>Time.now},{:deadline=>nil}).selector)} before_save do unless @skip_callback uri = URI.parse(self.youtube) rescue nil self.is_youtube = (uri && uri.host == "www.youtube.com") if self.is_youtube if uri.path.start_with?('/embed/') self.youtube_id = uri.path.split('/embed/').last.split(/[\/#?]/).first if self.youtube_id.blank? self.is_youtube = false self.youtube_id = nil end else params = CGI.parse(uri.query.to_s) v = params.blank? ? nil : params['v'].first if v.blank? self.is_youtube = false self.youtube_id = nil else self.youtube_id = v end end if self.is_youtube begin youtube_img_url = "https:"+self.youtube_thumb uri = URI.parse(youtube_img_url) req = Net::HTTP::Get.new(uri.path) res = Net::HTTP.start( uri.host, uri.port, :use_ssl => (uri.scheme == 'https'), :verify_mode => OpenSSL::SSL::VERIFY_NONE) do |https| https.request(req) end snapshot_content = res.body rescue nil #Net::HTTP.get_response(URI.parse(youtube_img_url)).body rescue nil if snapshot_content self[:video_snapshot] = '0.jpg' snapshot_file_path = self.video_snapshot.file.path FileUtils.mkdir_p(File.dirname(snapshot_file_path)) File.open(snapshot_file_path, 'wb'){|f| f.write(snapshot_content)} image = MiniMagick::Image.open(snapshot_file_path) self.scale = (1.0 * image[:height] / image[:width] * 100).round(2) else puts "cannot read #{youtube_img_url}" end rescue => e puts e.to_s self.scale = nil end else self.scale = nil end else self.youtube_id = nil image = MiniMagick::Image.open(self.video_snapshot.file.path) rescue nil if image self.scale = (1.0 * image[:height] / image[:width] * 100).round(2) end end if self.video_snapshot_changed? self.default_video_snapshot = false end VideoProSetting.first.update_user_id(self) end end after_destroy do VideoProSetting.first.remove_user_id(self) end after_save do unless @skip_callback if (self.video_file_changed? || self.auto_convert_video_changed?) && self.auto_convert_video Thread.new do self.generate_webm end end if self.video_file? && self.video_file_changed? && (!(self.video_snapshot?) || self.default_video_snapshot) Thread.new do self.generate_video_snapshot end end end end def inc_count self.class.where(:id=>self.id).update_all({"$inc"=>{"view_count"=>1}}) end def category_title self.category.title rescue "" end def post_agencies_translations if defined?(OrbitHelper::SharedHash) && OrbitHelper::SharedHash OrbitHelper::SharedHash['video_pro'][:post_agencies_translations] rescue VideoProSetting.first.post_agencies_translations else VideoProSetting.first.post_agencies_translations rescue {} end end def get_override_post_agency self.post_agencies_translations[I18n.locale.to_s][self.override_post_agency] rescue "" end def post_agency(video_pro_setting=nil) if self.use_override_post_agency self.get_override_post_agency else if video_pro_setting.nil? video_pro_setting = VideoProSetting.first end if video_pro_setting && video_pro_setting.enable_name_mapping tmp = video_pro_setting.user_mapping[self.update_user_id] rescue nil if tmp.blank? user_name = User.where(:id=>self.update_user_id).pluck(:member_name).first[I18n.locale.to_s] rescue nil else user_name = tmp end else user_name = User.where(:id=>self.update_user_id).pluck(:member_name).first[I18n.locale.to_s] rescue nil end user_name end end def generate_video_snapshot if self.video_file? self.default_video_snapshot = true self[:video_snapshot] = File.basename(self.video_file.file.path).split(/\.[^.]+$/)[0] + ".jpg" FileUtils.mkdir_p(File.dirname(self.video_snapshot.file.path)) system("tmp/ffmpeg/ffmpeg -i #{self.video_file.file.path} -vframes 1 #{self.video_snapshot.file.path}") @skip_callback = true self.save @skip_callback = false true end end def generate_webm video_path = self.video_file.path rescue nil if !video_path.blank? video_webm = video_path.split('.')[0...-1].join('.')+".webm" core_num = [`cat /proc/cpuinfo | grep processor | wc -l`.to_i/2,1].max flag = system("tmp/ffmpeg/ffmpeg -i #{video_path} -c:v libvpx-vp9 -crf 35 -b:v 0 -b:a 96k -c:a libopus -filter:v fps=20 #{video_webm} -cpu-used #{core_num}") if flag self.video_file_webm = File.open(video_webm) @skip_callback = true self.save @skip_callback = false true else puts "generate webm failed" end end end def expired? self.deadline top_text, "classname" => "top"} if is_top? statuses << {"name" => hot_text, "classname" => "hot"} if is_hot? statuses << {"name" => hidden_text, "classname" => "hidden"} if is_hidden? statuses end def status_for_table status = "" status << "#{top_text} " if self.is_top status << "#{hot_text} " if self.is_hot status << "#{hidden_text}"if self.is_hidden status.html_safe end def top_text I18n.t("announcement.status.top") end def hot_text I18n.t("announcement.status.hot") end def hidden_text I18n.t("announcement.status.hidden") end def get_snapshot_url self.video_snapshot.url rescue "" # (self.is_youtube ? self.youtube_thumb : (self.video_snapshot.url)) end protected def add_http # unless self.out_link.blank? || self.out_link[/^http:\/\//] || self.out_link[/^https:\/\//] || self.out_link[/^\//] # self.out_link = 'https://' + self.out_link # end end end