- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我试图让上传的视频在后台转换,运行窗口。我正在使用的一些东西:
gem 'paperclip'
gem 'delayed_job_active_record'
gem 'ffmpeg'
[2012-12-09 22:47:03] ERROR invalid body size.
[2012-12-09 22:47:03] ERROR Errno::ECONNABORTED: An established connection was a
borted by the software in your host machine.
C:/RailsInstaller/Ruby1.9.3/lib/ruby/1.9.1/webrick/httpresponse.rb:396:i
n `write'
C:/RailsInstaller/Ruby1.9.3/lib/ruby/1.9.1/webrick/httpresponse.rb:396:i
n `<<'
C:/RailsInstaller/Ruby1.9.3/lib/ruby/1.9.1/webrick/httpresponse.rb:396:i
n `_write_data'
C:/RailsInstaller/Ruby1.9.3/lib/ruby/1.9.1/webrick/httpresponse.rb:368:i
n `send_body_string'
C:/RailsInstaller/Ruby1.9.3/lib/ruby/1.9.1/webrick/httpresponse.rb:249:i
n `send_body'
C:/RailsInstaller/Ruby1.9.3/lib/ruby/1.9.1/webrick/httpresponse.rb:152:i
n `send_response'
C:/RailsInstaller/Ruby1.9.3/lib/ruby/1.9.1/webrick/httpserver.rb:110:in
`run'
C:/RailsInstaller/Ruby1.9.3/lib/ruby/1.9.1/webrick/server.rb:191:in `blo
ck in start_thread'
class Video < ActiveRecord::Base
belongs_to :user
has_many :comments, dependent: :destroy
attr_accessible :video, :user_id, :video_file_name, :title, :public, :description, :views
has_attached_file :video, url: "/users/:user_id/videos/:id/:basename_:style.:extension"
#process_in_background :video #causes death
validates :video, presence: true
validates :description, presence: true, length: { minimum: 5, maximum: 100}
validates :title, presence: true, length: { minimum: 1, maximum: 15 }
validates_attachment_size :video, less_than: 1.gigabytes
validates_attachment :video, presence: true
default_scope order: 'created_at DESC'
Paperclip.interpolates :user_id do |attachment, style|attachment.instance.user_id
end
#before_post_process do |video|
# false if video.status == "converting"
#end
def perform
command = <<-end_command
start ffmpeg -i #{ '/public/users/:user_id/videos/:id/:basename_:style.:extension' } -ar 22050 -ab 32 -s 1280x720 -vcodec webm -r 25 -qscale 8 -f webm -y #{ '/public/users/:user_id/videos/:id/:basename_.webm' }
end_command
success = system(command)
logger.debug 'Converting File: ' + success.to_s
if success && $?.exitstatus.to_i == 0
#self.converted!
self.status = "converted"
else
#self.failure!
self.status = "failed"
end
end
handle_asynchronously :perform
def self.search(search)
if search
find(:all, conditions: ["public = 't' AND title LIKE ?", "%#{search}%"], order: "created_at DESC")
else
find(:all, conditions: ["public = 't'"], order: "created_at DESC")
end
end
def self.admin_search(search)
if search
find(:all, conditions: ['title LIKE ?', "%#{search}%"], order: "created_at DESC")
else
find(:all, order: "created_at DESC")
end
end
private
# This updates the stored filename with the new flash video file
def set_new_filename
#update_attribute(:filename, "#{filename}.#{id}.webm")
update_attribute(:content_type, "video/x-webm")
end
end
class VideosController < ApplicationController
before_filter :signed_in_user, only: [:upload, :update, :destroy]
before_filter :admin_user, only: :admin_index
def upload
@video = Video.new
# generate a unique id for the upload
@uuid = (0..29).to_a.map {|x| rand(10)}
end
def create
@video = Video.new(params[:video])
@video.user_id = current_user.id
if @video.save
@video.delay.perform
flash[:success] = "Uploaded Succefully!"
redirect_to @video.user
Delayed::Worker.new.start
else
render 'upload'
end
end
def show
@video = Video.find(params[:id])
@comments = @video.comments.paginate(page: params[:page], per_page: 6)
if !@video.public
if !signed_in? || current_user.id != @video.user_id && !current_user.admin && !current_user.approved?(@video.user)
flash[:notice] = "Video is private"
redirect_to root_path
end
end
end
def update
@video = Video.find(params[:id])
if @video.update_attributes(params[:video])
flash[:success] = "Video preferences saved"
else
flash[:fail] = "Failed to update video preferences"
end
redirect_to :back
end
def destroy
@video = Video.find(params[:id])
@video.destroy
flash[:deleted] = "Deleted Succefully!"
redirect_to :back
end
def index
@videos = Video.paginate(page: params[:page], per_page: 6).search(params[:search])
end
def admin_index
@videos = Video.paginate(page: params[:page], per_page: 6).admin_search(params[:search])
end
def ajax_video_comments
@video = Video.find(params[:id])
@comments = @video.comments.paginate(page: params[:page], per_page: 6)
respond_to do |format|
format.js { render partial: 'shared/comments', content_type: 'text/html' }
end
end
def ajax_video_watched
@video = Video.find(params[:id])
@video.views += 1
@video.save
end
private
def signed_in_user
redirect_to root_path, notice: "Please Login." unless signed_in?
end
def admin_user
redirect_to(root_path) unless current_user.admin?
end
end
最佳答案
您的表应该有这些列:
class Video < ActiveRecord::Base
belongs_to :user
has_many :comments, dependent: :destroy
attr_accessible :video, :user_id, :video_file_name,
:title, :public, :description, :views
has_attached_file :video,
url: "/users/:user_id/videos/:id/:basename_:style.:extension"
styles: {
:original => { :geometry => "1280x720", :format => 'mp4', :streaming => true, :convert_options => { :input => {}, :output => {'c:v' => 'libx264', vprofile: 'high', preset: 'medium', 'b:v' => '1250k', maxrate: '1250k', bufsize: '2500k', pix_fmt: 'yuv420p', flags: '+mv4+aic', threads: 'auto', 'b:a' => '128k', strict: '-2'}} },
:medium => { :geometry => "854x480", :format => 'mp4', :streaming => true, :convert_options => { :input => {}, :output => {'c:v' => 'libx264', vprofile: 'high', preset: 'medium', 'b:v' => '750k', maxrate: '750k', bufsize: '1500k', pix_fmt: 'yuv420p', flags: '+mv4+aic', threads: 'auto', 'b:a' => '128k', strict: '-2'}} },
:small => { :geometry => '640x360', :format => 'mp4', :streaming => true, :convert_options => { :input => {}, :output => {'c:v' => 'libx264', vprofile: 'high', preset: 'medium', 'b:v' => '250k', maxrate: '250k', bufsize: '500k', pix_fmt: 'yuv420p', flags: '+mv4+aic', threads: 'auto', 'b:a' => '128k', strict: '-2'}} },
:thumb => { :geometry => "160x90", :format => 'jpg', :time => 10 }
},
processors: [:ffmpeg, :qtfaststart]
validates :video, presence: true
validates :description, presence: true, length: { minimum: 5, maximum: 100}
validates :title, presence: true, length: { minimum: 1, maximum: 15 }
validates_attachment_size :video, less_than: 1.gigabytes
validates_attachment :video, presence: true
default_scope order: 'created_at DESC'
# cancel post-processing now, and set flag...
before_post_process do |video|
if video.status == nil
video.status = "queuing"
false # halts processing
end
end
# ...and perform after save in background
after_commit do |video|
if video.status == "queuing"
Delayed::Job.enqueue VideoJob.new(video.id), :queue => 'video'
video.status == "queued"
video.save(validations: false)
end
end
# generate styles (downloads original first)
def regenerate_styles!
self.video.reprocess!
end
# detect if our source file has changed
def video_changed?
self.video_file_size_changed? ||
self.video_file_name_changed? ||
self.video_content_type_changed? ||
self.video_updated_at_changed?
end
# Class to perform with delayed jobs
class VideoJob < Struct.new(:video_id)
def perform
video = Video.find(self.video_id)
video.status = "processing"
video.save(validations: false)
video.regenerate_styles!
end
def success(job)
video = Video.find(self.video_id)
video.status = "complete"
video.save(:validate => false)
end
def error(job, exception)
video = Video.find(self.video_id)
video.status = "error"
video.save(:validate => false)
end
end
end
module Paperclip
class Ffmpeg < Processor
attr_accessor :geometry, :format, :whiny, :convert_options
# Creates a Video object set to work on the +file+ given. It
# will attempt to transcode the video into one defined by +target_geometry+
# which is a "WxH"-style string. +format+ should be specified.
# Video transcoding will raise no errors unless
# +whiny+ is true (which it is, by default. If +convert_options+ is
# set, the options will be appended to the convert command upon video transcoding.
def initialize file, options = {}, attachment = nil
@convert_options = {
:input => {},
:output => { :y => nil }
}
unless options[:convert_options].nil? || options[:convert_options].class != Hash
unless options[:convert_options][:input].nil? || options[:convert_options][:input].class != Hash
@convert_options[:input].reverse_merge! options[:convert_options][:input]
end
unless options[:convert_options][:output].nil? || options[:convert_options][:output].class != Hash
@convert_options[:output].reverse_merge! options[:convert_options][:output]
end
end
@geometry = options[:geometry]
@file = file
@keep_aspect = !@geometry.nil? && @geometry[-1,1] != '!'
@pad_only = @keep_aspect && @geometry[-1,1] == '#'
@enlarge_only = @keep_aspect && @geometry[-1,1] == '<'
@shrink_only = @keep_aspect && @geometry[-1,1] == '>'
@whiny = options[:whiny].nil? ? true : options[:whiny]
@format = options[:format]
@time = options[:time].nil? ? 3 : options[:time]
@current_format = File.extname(@file.path)
@basename = File.basename(@file.path, @current_format)
@meta = identify
@pad_color = options[:pad_color].nil? ? "black" : options[:pad_color]
attachment.instance_write(:meta, @meta)
end
# Performs the transcoding of the +file+ into a thumbnail/video. Returns the Tempfile
# that contains the new image/video.
def make
src = @file
dst = Tempfile.new([@basename, @format ? ".#{@format}" : ''])
dst.binmode
parameters = []
# Add geometry
if @geometry
# Extract target dimensions
if @geometry =~ /(\d*)x(\d*)/
target_width = $1
target_height = $2
end
# Only calculate target dimensions if we have current dimensions
unless @meta[:size].nil?
current_geometry = @meta[:size].split('x')
# Current width and height
current_width = current_geometry[0]
current_height = current_geometry[1]
if @keep_aspect
if @enlarge_only
if current_width.to_i < target_width.to_i
# Keep aspect ratio
width = target_width.to_i
height = (width.to_f / (@meta[:aspect].to_f)).to_i
@convert_options[:output][:s] = "#{width.to_i/2*2}x#{height.to_i/2*2}"
else
return nil
end
elsif @shrink_only
if current_width.to_i > target_width.to_i
# Keep aspect ratio
width = target_width.to_i
height = (width.to_f / (@meta[:aspect].to_f)).to_i
@convert_options[:output][:s] = "#{width.to_i/2*2}x#{height.to_i/2*2}"
else
return nil
end
elsif @pad_only
# Keep aspect ratio
width = target_width.to_i
height = (width.to_f / (@meta[:aspect].to_f)).to_i
# We should add half the delta as a padding offset Y
pad_y = (target_height.to_f - height.to_f) / 2
if pad_y > 0
@convert_options[:output][:vf] = "scale=#{width}:-1,pad=#{width.to_i}:#{target_height.to_i}:0:#{pad_y}:#@pad_color"
else
@convert_options[:output][:vf] = "scale=#{width}:-1,crop=#{width.to_i}:#{height.to_i}"
end
else
# Keep aspect ratio
width = target_width.to_i
height = (width.to_f / (@meta[:aspect].to_f)).to_i
@convert_options[:output][:s] = "#{width.to_i/2*2}x#{height.to_i/2*2}"
end
else
# Do not keep aspect ratio
@convert_options[:output][:s] = "#{target_width.to_i/2*2}x#{target_height.to_i/2*2}"
end
end
end
# Add format
case @format
when 'jpg', 'jpeg', 'png', 'gif' # Images
@convert_options[:input][:ss] = @time
@convert_options[:output][:vframes] = 1
@convert_options[:output][:f] = 'image2'
end
# Add source
parameters << @convert_options[:input].map { |k,v| "-#{k.to_s} #{v} "}
parameters << "-i ':source'"
parameters << @convert_options[:output].map { |k,v| "-#{k.to_s} #{v} "}
parameters << "':dest'"
parameters = parameters.flatten.compact.join(" ").strip.squeeze(" ")
begin
success = Paperclip.run("ffmpeg", parameters, :source => "#{File.expand_path(src.path)}", :dest => File.expand_path(dst.path))
rescue Cocaine::ExitStatusError => e
raise Paperclip::Error, "error while processing video for #{@basename}: #{e}" if @whiny
end
dst
end
def identify
meta = {}
command = "ffmpeg -i \"#{File.expand_path(@file.path)}\" 2>&1"
ffmpeg = IO.popen(command)
ffmpeg.each("\r") do |line|
# Matching lines like:
# Video: h264, yuvj420p, 640x480 [PAR 72:72 DAR 4:3], 10301 kb/s, 30 fps, 30 tbr, 600 tbn, 600 tbc
if line.include?(' Video: ')
start = line.index('Video:')
items = line[start, 150].split(',')
size = items[2].strip!.split(' ').first
meta[:size] = size.to_s
meta[:aspect] = size.split('x').first.to_f / size.split('x').last.to_f
end
# Matching Duration: 00:01:31.66, start: 0.000000, bitrate: 10404 kb/s
if line =~ /Duration:(\s.?(\d*):(\d*):(\d*\.\d*))/
meta[:length] = $2.to_s + ":" + $3.to_s + ":" + $4.to_s
end
end
meta
end
end
class Attachment
def meta
instance_read(:meta)
end
end
end
module Paperclip
class Qtfaststart < Processor
attr_accessor :streaming, :format, :whiny
# Creates a Video object set to work on the +file+ given. It
# will attempt to reposition the moov atom in the video given
# if +streaming+ is set.
def initialize file, options = {}, attachment = nil
@streaming = options[:streaming]
@file = file
@whiny = options[:whiny].nil? ? true : options[:whiny]
@format = options[:format]
@current_format = File.extname(@file.path)
@basename = File.basename(@file.path, @current_format)
@meta = attachment.meta
attachment.instance_write(:meta, @meta)
end
# Performs the atom repositioning on +file+.
# Returns the Tempfile that contains the new video or the original
# file if +streaming+ wasn't set.
def make
return @file unless @streaming
src = @file
dst = Tempfile.new([@basename, @format ? ".#{@format}" : ''])
dst.binmode
parameters = []
# Add source
parameters << ":source"
# Add destination
parameters << ":dest"
parameters = parameters.flatten.compact.join(" ").strip.squeeze(" ")
Paperclip.log("[qtfaststart] #{parameters}")
begin
success = Paperclip.run("qt-faststart", parameters, :source => "#{File.expand_path(src.path)}", :dest => File.expand_path(dst.path))
rescue Cocaine::ExitStatusError => e
raise PaperclipError, "error while processing video for #{@basename}: #{e}" if @whiny
end
dst
end
end
class Attachment
def meta
instance_read(:meta)
end
end
end
class VideosController < ApplicationController
before_filter :signed_in_user, only: [:upload, :update, :destroy]
before_filter :admin_user, only: :admin_index
def upload
@video = Video.new
# generate a unique id for the upload
@uuid = (0..29).to_a.map {|x| rand(10)}
end
def create
@video = Video.new(params[:video])
@video.user_id = current_user.id
if @video.save
flash[:success] = "Uploaded Succefully!"
redirect_to @video.user
else
render 'upload'
end
end
def show
@video = Video.find(params[:id])
@comments = @video.comments.paginate(page: params[:page], per_page: 6)
if !@video.public
if !signed_in? || current_user.id != @video.user_id && !current_user.admin && !current_user.approved?(@video.user)
flash[:notice] = "Video is private"
redirect_to root_path
end
end
end
def update
@video = Video.find(params[:id])
if @video.update_attributes(params[:video])
flash[:success] = "Video preferences saved"
else
flash[:fail] = "Failed to update video preferences"
end
redirect_to :back
end
def destroy
@video = Video.find(params[:id])
@video.destroy
flash[:deleted] = "Deleted Succefully!"
redirect_to :back
end
def index
@videos = Video.paginate(page: params[:page], per_page: 6).search(params[:search])
end
def admin_index
@videos = Video.paginate(page: params[:page], per_page: 6).admin_search(params[:search])
end
def ajax_video_comments
@video = Video.find(params[:id])
@comments = @video.comments.paginate(page: params[:page], per_page: 6)
respond_to do |format|
format.js { render partial: 'shared/comments', content_type: 'text/html' }
end
end
def ajax_video_watched
@video = Video.find(params[:id])
@video.views += 1
@video.save
end
private
def signed_in_user
redirect_to root_path, notice: "Please Login." unless signed_in?
end
def admin_user
redirect_to(root_path) unless current_user.admin?
end
end
关于ruby-on-rails-3 - 使用 Rails 进行后台视频处理,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13466420/
sanitize 是什么意思在 Rails 中是什么意思? 我正在阅读 CanCanCan 的文档.它说: When using strong_parameters or Rails 4+, you
在过去的几个月里,我感觉自己对 Ruby on Rails (RoR) 开发的了解达到了极限。我为大/小客户和 friend /爱好项目开发了大大小小的应用程序。我知道如何开发这些应用程序,但开始感觉
我昨天参加了一个关于扩展 Rails 的聚会,其中一个主题是 Hexagonal Rails。然而,我只做了一年的 Rails,对 MVC 结构非常满意(也许太舒服了),所以我不太了解适配器和消息队列
我使用多个 Rails 应用程序,一些在 Rails 3.2/Ruby 2.0 上,一些在 Rails 2.3/Ruby 1.8.7 上。 他们的共同点是,随着他们的成长和添加更多的依赖项/ gem
这个问题在这里已经有了答案: Using Rails-UJS in JS modules (Rails 6 with webpacker) (5 个答案) 关闭 3 年前。 我正在尝试使用 UJS
我正在开发一个当前使用 Rails 1.2 的 Rails 应用程序,所以我现在离最新的稳定版本(Rails 2.3)还有很长的路要走。 我应该如何进行迁移到更新版本的 Rails 的过程? 我应该一
尝试按照 Ryan Bates Backbone.js 教程构建抽奖应用程序,但我已经遇到了第一段代码的问题。在 application.js 的 init 函数中,他初始化了 Raffler 路由的
我正在使用 Rails 3.2 并且我有一个数据库表,我想在其中找到符合以下条件的所有行: a = true and b = true and ( 0 true, :b =>
我有一个用户类和一个联系人,其中联系人是用户的子类。这两个类都存储在用户表中。 我的联系人可能有也可能没有电子邮件地址,而我的用户需要一个电子邮件地址(我的用户模型定义中有 validates_pre
我正在编写一个教程,我在其中演示了一些 rails 命令。在我的机器上 rails和 script/rails两者都同样有效。有“首选”形式吗?两者中哪一个更普遍? 最佳答案 当您运行 rails 时
我正在寻找有关通过我的应用程序前进的最佳方式的建议,这是我首次开始集成Elasticsearch。我是一名初学者,但是热衷于深入研究,以便原谅任何明显的错误! 我遵循了http://www.sitep
我刚刚用 Rails new 启动了一个新的 Rails 应用程序,将默认数据库设置更改为 PostgresSQL。我用 bin/rails s 启动服务器,结果很奇怪 2016-04-21 05:0
我收到一个参数并希望它是这样的字符串: "abc,efg" 或者像这样的数组 ["abc","efg"] 在第一种情况下,我想将它转换成一个数组,什么是好的方法? 这是我的想法 if params[:
我刚刚用 Rails new 启动了一个新的 Rails 应用程序,将默认数据库设置更改为 PostgresSQL。我用 bin/rails s 启动服务器,结果很奇怪 2016-04-21 05:0
我收到一个参数并希望它是这样的字符串: "abc,efg" 或者像这样的数组 ["abc","efg"] 在第一种情况下,我想将它转换成一个数组,什么是好的方法? 这是我的想法 if params[:
我有 Rails 4,这是我的默认版本(我仍然希望它是)。但我不想在我的电脑上添加 rails 3.2。在以下命令中:gem install rails -v 3.2.16 我有这个警告: railt
您好,我想使用 Sheevaplug 构建一个“Rails Brick”来自 Marvell(操作系统是开箱即用的 Ubuntu,但您可以在其上安装其他发行版)。它将成为家庭服务器和静音、低成本(99
我需要能够从 Rails 控制台发送我的 Rails 应用程序的 Postgres 数据库中所有未接受的邀请。 (我有一个名为 Invitations 的表,其中包含一个名为 accepted 的 b
validate :cannot_modify_if_locked, on: :update def cannot_modify_if_locked if self.locked erro
我正在学习教程(学习 Rails 播客),需要更改以下路由语法,以便它与 Rails 3.0 兼容。谁能帮忙? map.view_page ':name', :controller => 'viewe
我是一名优秀的程序员,十分优秀!