require 'uri' require 'fileutils' class VideoImage include Mongoid::Document include Mongoid::Timestamps include OrbitModel::Status include OrbitModel::Impression include OrbitTag::Taggable include OrbitHashtag::Hashtaggable 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 field :details, type: String, localize: true field :other_member_profiles, type: Array, default: [] has_and_belongs_to_many :video_tags, inverse_of: :video_images # 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 before_validation :parse_youtube_url 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 Thread.current[:skip_video_callbacks] if self.is_youtube == false 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 Thread.current[:skip_video_callbacks] 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}") Thread.current[:skip_video_callbacks] = true self.save Thread.current[:skip_video_callbacks] = 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) Thread.current[:skip_video_callbacks] = true self.save Thread.current[:skip_video_callbacks] = 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.file.url : (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 private def parse_youtube_url return if youtube.blank? return if self.youtube_changed? == false uri = URI.parse(youtube) rescue nil if uri.host == "www.youtube.com" self.is_youtube = true if uri.path.start_with?('/embed/') self.youtube_id = uri.path.split('/embed/').last.split(/[\/#?]/).first else params = CGI.parse(uri.query.to_s) self.youtube_id = params['v'].first end self.is_youtube = false if youtube_id.blank? else self.is_youtube = false self.youtube_id = nil end if self.is_youtube youtube_img_url = "https:"+self.youtube_thumb self.remote_file_url = youtube_img_url end rescue URI::InvalidURIError => e self.is_youtube = false self.youtube_id = nil end end