- Added support for attachments referencing
- Added stderr capturing for better error reports - Added multiple commands support - Added video macro filter based on flowplayer and ffmpeg
This commit is contained in:
parent
5ea4c736ed
commit
8cfa874772
|
@ -6,12 +6,14 @@ class WikiExternalFilterController < ApplicationController
|
||||||
def filter
|
def filter
|
||||||
name = params[:name]
|
name = params[:name]
|
||||||
macro = params[:macro]
|
macro = params[:macro]
|
||||||
|
index = params[:index].to_i
|
||||||
|
filename = params[:filename] ? params[:filename] : name
|
||||||
config = load_config
|
config = load_config
|
||||||
cache_key = self.construct_cache_key(macro, name)
|
cache_key = self.construct_cache_key(macro, name)
|
||||||
content = read_fragment cache_key
|
content = read_fragment cache_key
|
||||||
|
|
||||||
if (content)
|
if (content)
|
||||||
send_data content, :type => config[macro]['content_type'], :disposition => 'inline'
|
send_data content[index], :type => config[macro]['content_type'], :disposition => 'inline', :filename => filename
|
||||||
else
|
else
|
||||||
render_404
|
render_404
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
require 'digest/sha2'
|
require 'digest/sha2'
|
||||||
|
require 'open4'
|
||||||
|
|
||||||
module WikiExternalFilterHelper
|
module WikiExternalFilterHelper
|
||||||
|
|
||||||
|
@ -24,7 +25,7 @@ module WikiExternalFilterHelper
|
||||||
['wiki_external_filter', macro, name].join("/")
|
['wiki_external_filter', macro, name].join("/")
|
||||||
end
|
end
|
||||||
|
|
||||||
def build(text, macro, info)
|
def build(text, attachments, macro, info)
|
||||||
|
|
||||||
name = Digest::SHA256.hexdigest(text)
|
name = Digest::SHA256.hexdigest(text)
|
||||||
result = {}
|
result = {}
|
||||||
|
@ -49,14 +50,14 @@ module WikiExternalFilterHelper
|
||||||
result[:content_type] = info['content_type']
|
result[:content_type] = info['content_type']
|
||||||
RAILS_DEFAULT_LOGGER.debug "from cache: #{name}"
|
RAILS_DEFAULT_LOGGER.debug "from cache: #{name}"
|
||||||
else
|
else
|
||||||
result = self.build_forced(text, info)
|
result = self.build_forced(text, attachments, info)
|
||||||
if result[:status]
|
if result[:status]
|
||||||
if expires > 0
|
if expires > 0
|
||||||
write_fragment cache_key, result[:content], :expires_in => expires.seconds
|
write_fragment cache_key, result[:content], :expires_in => expires.seconds
|
||||||
RAILS_DEFAULT_LOGGER.debug "cache saved: #{name}"
|
RAILS_DEFAULT_LOGGER.debug "cache saved: #{name}"
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
raise "Error applying external filter: #{result[:content]}"
|
raise "Error applying external filter: stdout is #{result[:content]}, stderr is #{result[:errors]}"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -66,23 +67,42 @@ module WikiExternalFilterHelper
|
||||||
return result
|
return result
|
||||||
end
|
end
|
||||||
|
|
||||||
def build_forced(text, info)
|
def build_forced(text, attachments, info)
|
||||||
|
|
||||||
|
if info['replace_attachments'] and attachments
|
||||||
|
attachments.each do |att|
|
||||||
|
text.gsub!(/#{att.filename.downcase}/i, att.diskfile)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
result = {}
|
result = {}
|
||||||
|
content = []
|
||||||
|
errors = ""
|
||||||
|
|
||||||
RAILS_DEFAULT_LOGGER.debug "executing command: #{info['command']}"
|
commands = info['commands']? info['commands'] : [info['command']]
|
||||||
|
|
||||||
content = IO.popen(info['command'], 'r+b') { |f|
|
commands.each do |command|
|
||||||
f.write info[:prolog] if info.key?(:prolog)
|
RAILS_DEFAULT_LOGGER.info "executing command: #{command}"
|
||||||
f.write CGI.unescapeHTML(text)
|
|
||||||
f.write info[:epilog] if info.key?(:epilog)
|
|
||||||
f.close_write
|
|
||||||
f.read
|
|
||||||
}
|
|
||||||
|
|
||||||
RAILS_DEFAULT_LOGGER.info("child status: sig=#{$?.termsig}, exit=#{$?.exitstatus}")
|
c = nil
|
||||||
|
e = nil
|
||||||
|
|
||||||
|
Open4::popen4(command) { |pid, fin, fout, ferr|
|
||||||
|
fin.write info[:prolog] if info.key?(:prolog)
|
||||||
|
fin.write CGI.unescapeHTML(text)
|
||||||
|
fin.write info[:epilog] if info.key?(:epilog)
|
||||||
|
fin.close
|
||||||
|
c, e = [fout.read, ferr.read]
|
||||||
|
}
|
||||||
|
|
||||||
|
RAILS_DEFAULT_LOGGER.debug("child status: sig=#{$?.termsig}, exit=#{$?.exitstatus}")
|
||||||
|
|
||||||
|
content << c
|
||||||
|
errors += e if e
|
||||||
|
end
|
||||||
|
|
||||||
result[:content] = content
|
result[:content] = content
|
||||||
|
result[:errors] = errors
|
||||||
result[:content_type] = info['content_type']
|
result[:content_type] = info['content_type']
|
||||||
result[:source] = text
|
result[:source] = text
|
||||||
result[:status] = $?.exitstatus == 0
|
result[:status] = $?.exitstatus == 0
|
||||||
|
@ -101,12 +121,12 @@ module WikiExternalFilterHelper
|
||||||
end
|
end
|
||||||
|
|
||||||
class Macro
|
class Macro
|
||||||
def initialize(view, source, macro, info)
|
def initialize(view, source, attachments, macro, info)
|
||||||
@view = view
|
@view = view
|
||||||
@view.controller.extend(WikiExternalFilterHelper)
|
@view.controller.extend(WikiExternalFilterHelper)
|
||||||
source.gsub!(/<br \/>/, "")
|
source.gsub!(/<br \/>/, "")
|
||||||
source.gsub!(/<\/?p>/, "")
|
source.gsub!(/<\/?p>/, "")
|
||||||
@result = @view.controller.build(source, macro, info)
|
@result = @view.controller.build(source, attachments, macro, info)
|
||||||
end
|
end
|
||||||
|
|
||||||
def render()
|
def render()
|
||||||
|
|
|
@ -12,6 +12,15 @@
|
||||||
when /\/.*(x|ht)ml/ then
|
when /\/.*(x|ht)ml/ then
|
||||||
%>
|
%>
|
||||||
<div><%= content %></div>
|
<div><%= content %></div>
|
||||||
|
<%
|
||||||
|
when /video\/x\-flv/ then
|
||||||
|
require 'RMagick'
|
||||||
|
image = Magick::Image::from_blob(content[0]).first
|
||||||
|
%>
|
||||||
|
<a class='flowplayer-video' href='<%= ActionController::Base.relative_url_root + "/wiki_external_filter/video.flv?name=#{name}" %>' alt='<%= h source %>' style='display:block;width:<%= image.columns %>px;height:<%= image.rows + 24 %>px;background-image:url(<%= url_for(:controller => 'wiki_external_filter', :action => 'filter', :macro => macro, :name => name, :index => 0) %>);background-repeat:no-repeat'><%= image_tag 'play_large.png', :plugin => 'wiki_external_filter', :style => "display:block;position:relative;left:#{image.columns / 2 - 83 / 2}px;top:#{image.rows / 2 - 83 / 2}px" %></a>
|
||||||
|
<%
|
||||||
|
@flowplayer_used = true
|
||||||
|
%>
|
||||||
<%
|
<%
|
||||||
else
|
else
|
||||||
%>
|
%>
|
||||||
|
@ -24,6 +33,32 @@
|
||||||
<br/>
|
<br/>
|
||||||
<span class='wiki_page'>Goto source: [[<%= wiki_name %>]]</span>
|
<span class='wiki_page'>Goto source: [[<%= wiki_name %>]]</span>
|
||||||
</div>
|
</div>
|
||||||
<% content_for :header_tags do %>
|
<%
|
||||||
<%= stylesheet_link_tag "wiki_external_filter.css", :plugin => "wiki_external_filter", :media => :all %>
|
content_for :header_tags do
|
||||||
<% end %>
|
%>
|
||||||
|
<%
|
||||||
|
if not @stylesheets_included
|
||||||
|
@stylesheets_included = true
|
||||||
|
%>
|
||||||
|
<%= stylesheet_link_tag "wiki_external_filter.css", :plugin => "wiki_external_filter", :media => :all %>
|
||||||
|
<%
|
||||||
|
end
|
||||||
|
%>
|
||||||
|
<%
|
||||||
|
if @flowplayer_used
|
||||||
|
if not @flowplayer_scripts_included
|
||||||
|
@flowplayer_scripts_included = true
|
||||||
|
%>
|
||||||
|
<%= javascript_include_tag 'flowplayer.min.js', :plugin => 'wiki_external_filter' %>
|
||||||
|
<script language="JavaScript">
|
||||||
|
//<![CDATA[
|
||||||
|
window.onload = function () {
|
||||||
|
flowplayer("a.flowplayer-video", "<%= ActionController::Base.relative_url_root + Engines::RailsExtensions::AssetHelpers.plugin_asset_path('wiki_external_filter', 'javascripts', 'flowplayer.swf') %>", { clip: { bufferLength: 1 } });
|
||||||
|
};
|
||||||
|
//]]>
|
||||||
|
</script>
|
||||||
|
<%
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
%>
|
||||||
|
|
|
@ -2,24 +2,60 @@
|
||||||
case content_type
|
case content_type
|
||||||
when /image\// then
|
when /image\// then
|
||||||
%>
|
%>
|
||||||
<img class='externalfilterinline' src='<%= url_for(:controller => 'wiki_external_filter', :action => 'filter', :macro => macro, :name => name) %>' alt="<%= h source %>" />
|
<img class='externalfilterinline' src='<%= url_for(:controller => 'wiki_external_filter', :action => 'filter', :macro => macro, :name => name, :index => 0) %>' alt="<%= h source %>" />
|
||||||
<%
|
<%
|
||||||
when /text\/plain/ then
|
when /text\/plain/ then
|
||||||
%>
|
%>
|
||||||
<pre class='externalfilterinline'><%= h content %></pre>
|
<pre class='externalfilterinline'><%= h content[0] %></pre>
|
||||||
<%
|
<%
|
||||||
when /\/.*(x|ht)ml/ then
|
when /\/.*(x|ht)ml/ then
|
||||||
%>
|
%>
|
||||||
<div class='externalfilterinline'><%= content %></div>
|
<div class='externalfilterinline'><%= content[0] %></div>
|
||||||
|
<%
|
||||||
|
when /video\/x\-flv/ then
|
||||||
|
require 'RMagick'
|
||||||
|
image = Magick::Image::from_blob(content[0]).first
|
||||||
|
%>
|
||||||
|
<a class='flowplayer-video externalfilterinline' href='<%= ActionController::Base.relative_url_root + "/wiki_external_filter/video.flv?name=#{name}" %>' alt='<%= h source %>' style='display:block;width:<%= image.columns %>px;height:<%= image.rows + 24 %>px;background-image:url(<%= url_for(:controller => 'wiki_external_filter', :action => 'filter', :macro => macro, :name => name, :index => 0) %>);background-repeat:no-repeat'><%= image_tag 'play_large.png', :plugin => 'wiki_external_filter', :style => "display:block;position:relative;left:#{image.columns / 2 - 83 / 2}px;top:#{image.rows / 2 - 83 / 2}px" %></a>
|
||||||
|
|
||||||
|
<%
|
||||||
|
@flowplayer_used = true
|
||||||
|
%>
|
||||||
<%
|
<%
|
||||||
else
|
else
|
||||||
%>
|
%>
|
||||||
<object class='externalfilterinline' name='<%= name %>' data='<%= url_for(:controller => 'wiki_external_filter', :action => 'filter', :macro => macro, :name => name) %>' type='<%= content_type %>' title="<%= h source %>">
|
<object class='externalfilterinline' name='<%= name %>' data='<%= url_for(:controller => 'wiki_external_filter', :action => 'filter', :macro => macro, :name => name, :index => 0) %>' type='<%= content_type %>' title="<%= h source %>">
|
||||||
<embed name='<%= name %>-2' src='<%= url_for(:controller => 'wiki_external_filter', :action => 'filter', :macro => macro, :name => name) %>' type='<%= content_type %>' title="<%= h source %>" />
|
<embed name='<%= name %>-2' src='<%= url_for(:controller => 'wiki_external_filter', :action => 'filter', :macro => macro, :name => name, :index => 0) %>' type='<%= content_type %>' title="<%= h source %>" />
|
||||||
</object>
|
</object>
|
||||||
<%
|
<%
|
||||||
end
|
end
|
||||||
%>
|
%>
|
||||||
<% content_for :header_tags do %>
|
<%
|
||||||
<%= stylesheet_link_tag "wiki_external_filter.css", :plugin => "wiki_external_filter", :media => :all %>
|
content_for :header_tags do
|
||||||
<% end %>
|
%>
|
||||||
|
<%
|
||||||
|
if not @stylesheets_included
|
||||||
|
@stylesheets_included = true
|
||||||
|
%>
|
||||||
|
<%= stylesheet_link_tag "wiki_external_filter.css", :plugin => "wiki_external_filter", :media => :all %>
|
||||||
|
<%
|
||||||
|
end
|
||||||
|
%>
|
||||||
|
<%
|
||||||
|
if @flowplayer_used
|
||||||
|
if not @flowplayer_scripts_included
|
||||||
|
@flowplayer_scripts_included = true
|
||||||
|
%>
|
||||||
|
<%= javascript_include_tag 'flowplayer.min.js', :plugin => 'wiki_external_filter' %>
|
||||||
|
<script language="JavaScript">
|
||||||
|
//<![CDATA[
|
||||||
|
window.onload = function () {
|
||||||
|
flowplayer("a.flowplayer-video", "<%= ActionController::Base.relative_url_root + Engines::RailsExtensions::AssetHelpers.plugin_asset_path('wiki_external_filter', 'javascripts', 'flowplayer.swf') %>", { clip: { bufferLength: 1 } });
|
||||||
|
};
|
||||||
|
//]]>
|
||||||
|
</script>
|
||||||
|
<%
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
%>
|
||||||
|
|
Binary file not shown.
After Width: | Height: | Size: 5.1 KiB |
Binary file not shown.
Binary file not shown.
Binary file not shown.
File diff suppressed because one or more lines are too long
Binary file not shown.
Binary file not shown.
|
@ -0,0 +1,3 @@
|
||||||
|
ActionController::Routing::Routes.draw do |map|
|
||||||
|
map.connect 'wiki_external_filter/:filename', :controller => 'wiki_external_filter', :action => 'filter', :macro => 'flowplayer', :index => '1', :requirements => { :filename => /\S+\.flv/ }
|
||||||
|
end
|
6
init.rb
6
init.rb
|
@ -18,8 +18,8 @@ Redmine::Plugin.register :wiki_external_filter do
|
||||||
Redmine::WikiFormatting::Macros.register do
|
Redmine::WikiFormatting::Macros.register do
|
||||||
info = config[name]
|
info = config[name]
|
||||||
desc info['description']
|
desc info['description']
|
||||||
macro name do |wiki_content_obj, args|
|
macro name do |obj, args|
|
||||||
m = WikiExternalFilterHelper::Macro.new(self, args.to_s, name, info)
|
m = WikiExternalFilterHelper::Macro.new(self, args.to_s, obj.page.attachments, name, info)
|
||||||
m.render
|
m.render
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -33,7 +33,7 @@ Redmine::Plugin.register :wiki_external_filter do
|
||||||
@included_wiki_pages ||= []
|
@included_wiki_pages ||= []
|
||||||
raise 'Circular inclusion detected' if @included_wiki_pages.include?(page.title)
|
raise 'Circular inclusion detected' if @included_wiki_pages.include?(page.title)
|
||||||
@included_wiki_pages << page.title
|
@included_wiki_pages << page.title
|
||||||
m = WikiExternalFilterHelper::Macro.new(self, page.content.text, name, info)
|
m = WikiExternalFilterHelper::Macro.new(self, page.content.text, page.attachments, name, info)
|
||||||
@included_wiki_pages.pop
|
@included_wiki_pages.pop
|
||||||
m.render_block(args.to_s)
|
m.render_block(args.to_s)
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,2 +1 @@
|
||||||
|
connect 'wiki_external_filter/:filename', :controller => 'wiki_external_filter', :action => 'filter', :macro => 'flowplayer', :index => '1', :requirements => { :filename => /\S+\.flv/ }
|
||||||
connect 'wiki_external_filter/:macro/:name', :controller => 'wiki_external_filter', :action => 'filter', :macro => /\S+/
|
|
||||||
|
|
Reference in New Issue