public
Description: User scripts for Greasemonkey/Safari/Fluid; home of Endless Tweets
Homepage: http://mislav.uniqpath.com/user-scripts/
Clone URL: git://github.com/mislav/user-scripts.git
user-scripts / Thorfile
100644 167 lines (142 sloc) 4.323 kb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
#!/usr/bin/env ruby
require 'net/http'
require 'curl'
require 'cgi'
require 'haml'
require 'sass'
require 'stringio'
 
class Gm < Thor
  desc 'build', %(Builds the *.user.js files from *.js sources)
  def build
    for name in self.class.scripts.keys
      source = File.open("#{name}/#{name}.js", 'r')
      target = File.open("#{name}/#{name}.user.js", 'w')
      
      begin
        render_template(source, target)
      ensure
        source.close
        target.close
      end
      
      puts target.path
    end
  end
  
  desc 'check', %(Checks scriptSize property on both local and remote file)
  def check
    Net::HTTP.start('userscripts.org') do |http|
      for name, id in self.class.scripts
        req = Net::HTTP::Head.new script_path(id)
        res = http.request(req)
        remote_size = res.content_length
        
        file = script_file(name)
        local_size = File.stat(file).size
        
        hardcoded_size = nil
        
        File.open(file) do |script|
          script.each do |line|
            if line =~ /\bscriptSize: (\d+)\b/
              hardcoded_size = $1.to_i
            end
          end
        end
        
        puts "#{name} -- remote: #{remote_size}, local: #{local_size}, hardcoded: #{hardcoded_size}"
      end
    end
  end
  
  def upload(name)
    id = self.class.scripts[name]
    raise ArgumentError, "cannot find script '#{name}'" unless id
    
    print 'UserScripts.org login ("email:pass"): '
    STDIN.gets
    auth = $_.chomp.split(':')
    encoded_auth = auth.map { |i| CGI::escape i }
    
    # FIXME: this is no work! (prolly because of CSRF protection)
    c = Curl::Easy.new("http://#{encoded_auth.join(':')}@userscripts.org/scripts/update_src/#{id}")
    c.multipart_form_post = true
    c.http_post(
      Curl::PostField.content('which_source', 'file'),
      Curl::PostField.file('file[src]', script_file(name))
    )
  end
  
  def self.scripts
    @@scripts ||= {
      'endless_tweets' => 24398
    }
  end
  
  private
  
  def script_path(id)
    "/scripts/source/#{id}.user.js?update"
  end
  
  def script_file(name)
    "#{name}/#{name}.user.js"
  end
  
  def normalize_partial_path(path, dir)
    if path.index('/')
      path
    else
      "#{dir}/#{path}"
    end
  end
  
  def render_template(file, target = nil)
    partial = case file.extension
    when 'sass'
      css = Sass::Engine.new(file.read, :style => :compact).to_css
      %[addCSS(#{javascript_string(css)})\n]
    when 'haml'
      html = Haml::Engine.new(file.read).to_html
      javascript_string(html.rstrip)
    when 'js'
      target ||= StringIO.new
      render_js_with_partials(file, target)
      target.string if StringIO === target
    when 'gif', 'png', 'jpg'
      encoded = [file.read].pack('m').gsub(/\s+/, '')
      javascript_string('data:image/%s;base64,%s' % [file.extension, encoded])
    else
      raise "don't know how to handle .#{file.extension}"
    end
  end
  
  def render_js_with_partials(source, target)
    dir = File.dirname(source.path)
    
    for line in source
      case line
      when %r{^(\s*)(.*)//= ([\w/.]+)}
        indentation, code, partial_name = $1, $2, $3
        partial = normalize_partial_path(partial_name, dir)
        target << indentation
        target << code
        
        if File.exists?(partial)
          partial_file = File.open(partial, 'r')
          begin
            rendered_partial = render_template(partial_file)
          ensure
            partial_file.close
          end
          
          if code.empty?
            target.puts "/*** #{partial} ***/"
            target << indentation
          end
          
          unless indentation.empty?
            rendered_partial.gsub!(/\n([^\n])/, "\n#{indentation}\\1")
          end
          
          target.puts rendered_partial
        else
          if code.empty?
            target.puts "/*** NOT FOUND: #{partial} ***/"
          else
            target.puts "null // NOT FOUND: #{partial}"
          end
        end
      else
        target << line
      end
    end
  end
  
  def javascript_string(string)
    string = string.gsub('\\', '\\\\').gsub(/\n+/, "\\\n").gsub('"', '\"')
    %["#{string}"]
  end
end
 
File.class_eval do
  def extension
    @extension ||= path && path =~ /\.(\w{2,5})$/ && $1
  end
end