murlsh 0.10.0 → 0.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/README.textile +31 -0
- data/Rakefile +17 -2
- data/VERSION +1 -1
- data/config.yaml +9 -3
- data/lib/murlsh/config_server.rb +2 -0
- data/lib/murlsh/dispatch.rb +5 -0
- data/lib/murlsh/doc.rb +2 -2
- data/lib/murlsh/flickr_server.rb +2 -0
- data/lib/murlsh/head_from_get.rb +15 -0
- data/lib/murlsh/sqlite3_adapter.rb +1 -1
- data/lib/murlsh/twitter_server.rb +2 -0
- data/lib/murlsh/uri_ask.rb +16 -7
- data/lib/murlsh/url.rb +1 -0
- data/lib/murlsh/url_body.rb +5 -1
- data/lib/murlsh/url_server.rb +30 -26
- data/lib/murlsh.rb +2 -0
- data/murlsh.gemspec +4 -2
- data/plugins/add_pre_50_lookup_content_type_title.rb +5 -2
- data/plugins/add_pre_60_github_title.rb +1 -1
- data/plugins/add_pre_60_google_code_title.rb +27 -0
- data/plugins/via_50_domain.rb +1 -1
- data/public/css/screen.css +2 -3
- data/public/js/comments.json +1 -12
- data/public/js/js.js +36 -31
- metadata +6 -4
    
        data/README.textile
    CHANGED
    
    | @@ -84,4 +84,35 @@ subscribe_url is what gets put in the feed as link rel="hub" | |
| 84 84 |  | 
| 85 85 | 
             
            This will make updates to your feed show up in Google Reader instantly.
         | 
| 86 86 |  | 
| 87 | 
            +
            h1. Thumbnail Locators
         | 
| 88 | 
            +
             | 
| 89 | 
            +
            If the url for a thumbnail image can be generated by regex search and replace
         | 
| 90 | 
            +
            on a posted url, a rule can be added to the configuration to automatically
         | 
| 91 | 
            +
            show a thumbnail image for it. The 'thumb_locators' config key is a hash
         | 
| 92 | 
            +
            of Javascript regex to Javascript replacement string (which can include
         | 
| 93 | 
            +
            captured groups). The hash key is wrapped in ^ and $ before compilation so
         | 
| 94 | 
            +
            it must match the entire url. The regex is compiled case-insensitive.
         | 
| 95 | 
            +
             | 
| 96 | 
            +
            For example:
         | 
| 97 | 
            +
             | 
| 98 | 
            +
            * Show the GitHub octocat Apple touch icon
         | 
| 99 | 
            +
            (http://github.com/apple-touch-icon.png) as a thumbnail for GitHub links
         | 
| 100 | 
            +
            * Show a friend's Gravatar for the thumbnails of links to his blog
         | 
| 101 | 
            +
             | 
| 102 | 
            +
            <pre>
         | 
| 103 | 
            +
            <code>
         | 
| 104 | 
            +
            thumb_locators:
         | 
| 105 | 
            +
              (http:\/\/github\.com\/).*: $1apple-touch-icon.png
         | 
| 106 | 
            +
              http:\/\/myfriend\.com\/.*: http://gravatar.com/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx</code>
         | 
| 107 | 
            +
            </pre>
         | 
| 108 | 
            +
             | 
| 109 | 
            +
            h1. Design Goals
         | 
| 110 | 
            +
             | 
| 111 | 
            +
            * make site fast and very cacheable, caching wrapper around calls to third party JSON APIs
         | 
| 112 | 
            +
            * low effort required to add a url, get metadata programatically instead of requiring user to specify
         | 
| 113 | 
            +
            * heavy lifting on the client side
         | 
| 114 | 
            +
            * allow customization with config and plugins
         | 
| 115 | 
            +
            * full regex search for finding saved urls
         | 
| 116 | 
            +
            * simple security (no sessions, no cookies)
         | 
| 117 | 
            +
             | 
| 87 118 | 
             
            Questions and comments: "matthewm@boedicker.org":mailto:matthewm@boedicker.org
         | 
    
        data/Rakefile
    CHANGED
    
    | @@ -15,6 +15,11 @@ sqlite3 | |
| 15 15 | 
             
            murlsh
         | 
| 16 16 | 
             
            }.each { |d| require d }
         | 
| 17 17 |  | 
| 18 | 
            +
            # optional libraries
         | 
| 19 | 
            +
            %w{
         | 
| 20 | 
            +
            metric_fu
         | 
| 21 | 
            +
            }.each { |d| Murlsh::failproof { require d } }
         | 
| 22 | 
            +
             | 
| 18 23 | 
             
            config = YAML.load_file('config.yaml')
         | 
| 19 24 |  | 
| 20 25 | 
             
            desc 'Initialize a new installation.'
         | 
| @@ -261,6 +266,8 @@ directory 'public/js' | |
| 261 266 |  | 
| 262 267 | 
             
            namespace :js do
         | 
| 263 268 |  | 
| 269 | 
            +
              MURLSH_JS = %w{public/js/js.js}
         | 
| 270 | 
            +
             | 
| 264 271 | 
             
              desc 'Combine and compress javascript.'
         | 
| 265 272 | 
             
              task :compress => ['public/js'] do
         | 
| 266 273 | 
             
                combined = cat(config['js_files'].map { |x| "public/#{x}" } )
         | 
| @@ -293,13 +300,21 @@ namespace :js do | |
| 293 300 | 
             
              end
         | 
| 294 301 |  | 
| 295 302 | 
             
              desc 'Run javascript through jslint.'
         | 
| 296 | 
            -
              task : | 
| 297 | 
            -
                 | 
| 303 | 
            +
              task :jslint do
         | 
| 304 | 
            +
                MURLSH_JS.each do |jsf|
         | 
| 298 305 | 
             
                  puts jsf
         | 
| 299 306 | 
             
                  puts `rhino http://www.jslint.com/rhino/jslint.js #{jsf}`
         | 
| 300 307 | 
             
                end
         | 
| 301 308 | 
             
              end
         | 
| 302 309 |  | 
| 310 | 
            +
              desc "Run javascript through Google's Closure Linter."
         | 
| 311 | 
            +
              task :gjslint do
         | 
| 312 | 
            +
                MURLSH_JS.each do |jsf|
         | 
| 313 | 
            +
                  puts jsf
         | 
| 314 | 
            +
                  puts `gjslint #{jsf}`
         | 
| 315 | 
            +
                end
         | 
| 316 | 
            +
              end
         | 
| 317 | 
            +
             | 
| 303 318 | 
             
            end
         | 
| 304 319 |  | 
| 305 320 | 
             
            def ask(prompt, sep=':')
         | 
    
        data/VERSION
    CHANGED
    
    | @@ -1 +1 @@ | |
| 1 | 
            -
            0. | 
| 1 | 
            +
            0.11.0
         | 
    
        data/config.yaml
    CHANGED
    
    | @@ -1,11 +1,9 @@ | |
| 1 1 | 
             
            --- 
         | 
| 2 | 
            -
            apple_icon_hosts: []
         | 
| 3 | 
            -
             | 
| 4 2 | 
             
            auth_file: murlsh_users
         | 
| 5 3 | 
             
            cache_entitystore: file:tmp/cache/rack/body
         | 
| 6 4 | 
             
            cache_metastore: file:tmp/cache/rack/meta
         | 
| 7 5 | 
             
            config_js: 
         | 
| 8 | 
            -
            -  | 
| 6 | 
            +
            - thumb_locators
         | 
| 9 7 | 
             
            css_files: 
         | 
| 10 8 | 
             
            - css/jquery.jgrowl.css
         | 
| 11 9 | 
             
            - css/screen.css
         | 
| @@ -27,3 +25,11 @@ pubsubhubbub_hubs: [] | |
| 27 25 |  | 
| 28 26 | 
             
            root_url: http://urls.matthewm.boedicker.org/
         | 
| 29 27 | 
             
            show_names: true
         | 
| 28 | 
            +
            thumb_locators:
         | 
| 29 | 
            +
              (http:\/\/(cgi\.)?ebay\.(com|co\.uk)\/).*: $1apple-touch-icon.png
         | 
| 30 | 
            +
              (http:\/\/blog\.makezine\.com\/).*: $1apple-touch-icon.png
         | 
| 31 | 
            +
              (http:\/\/en\.wikipedia\.org\/).*: $1apple-touch-icon.png
         | 
| 32 | 
            +
              (http:\/\/github\.com\/).*: $1apple-touch-icon.png
         | 
| 33 | 
            +
              (http:\/\/stackoverflow\.com\/).*: $1apple-touch-icon.png
         | 
| 34 | 
            +
              (http:\/\/www\.nytimes\.com\/).*: $1apple-touch-icon.png
         | 
| 35 | 
            +
              (http:\/\/www\.wired\.com\/).*: $1apple-touch-icon.png
         | 
    
        data/lib/murlsh/config_server.rb
    CHANGED
    
    
    
        data/lib/murlsh/dispatch.rb
    CHANGED
    
    | @@ -16,6 +16,7 @@ module Murlsh | |
| 16 16 |  | 
| 17 17 | 
             
                  ActiveRecord::Base.establish_connection(
         | 
| 18 18 | 
             
                    :adapter => 'sqlite3', :database => @config.fetch('db_file'))
         | 
| 19 | 
            +
                  ActiveRecord::Base.include_root_in_json = false
         | 
| 19 20 |  | 
| 20 21 | 
             
                  db = ActiveRecord::Base.connection.instance_variable_get(:@connection)
         | 
| 21 22 |  | 
| @@ -27,10 +28,14 @@ module Murlsh | |
| 27 28 | 
             
                  root_path = URI(@config.fetch('root_url')).path
         | 
| 28 29 |  | 
| 29 30 | 
             
                  @dispatch = [
         | 
| 31 | 
            +
                    [%r{^HEAD #{root_path}(url)?$}, url_server.method(:head)],
         | 
| 30 32 | 
             
                    [%r{^GET #{root_path}(url)?$}, url_server.method(:get)],
         | 
| 31 33 | 
             
                    [%r{^POST #{root_path}(url)?$}, url_server.method(:post)],
         | 
| 34 | 
            +
                    [%r{^HEAD #{root_path}config$}, config_server.method(:head)],
         | 
| 32 35 | 
             
                    [%r{^GET #{root_path}config$}, config_server.method(:get)],
         | 
| 36 | 
            +
                    [%r{^HEAD #{root_path}flickr$}, flickr_server.method(:head)],
         | 
| 33 37 | 
             
                    [%r{^GET #{root_path}flickr$}, flickr_server.method(:get)],
         | 
| 38 | 
            +
                    [%r{^HEAD #{root_path}twitter/.+$}, twitter_server.method(:head)],
         | 
| 34 39 | 
             
                    [%r{^GET #{root_path}twitter/.+$}, twitter_server.method(:get)],
         | 
| 35 40 | 
             
                  ]
         | 
| 36 41 | 
             
                end
         | 
    
        data/lib/murlsh/doc.rb
    CHANGED
    
    | @@ -18,8 +18,8 @@ module Murlsh | |
| 18 18 | 
             
                  nil
         | 
| 19 19 | 
             
                end
         | 
| 20 20 |  | 
| 21 | 
            -
                # Check a list of xpaths in order and return the  | 
| 22 | 
            -
                # one that is not nil | 
| 21 | 
            +
                # Check a list of xpaths in order and yield and return the node matching
         | 
| 22 | 
            +
                # the first one that is not nil
         | 
| 23 23 | 
             
                def xpath_search(xpaths)
         | 
| 24 24 | 
             
                  [*xpaths].each do |xpath|
         | 
| 25 25 | 
             
                    selection = (self/xpath).first
         | 
    
        data/lib/murlsh/flickr_server.rb
    CHANGED
    
    
| @@ -7,7 +7,7 @@ class ActiveRecord::ConnectionAdapters::SQLite3Adapter | |
| 7 7 | 
             
              # Add MATCH function for regex matching.
         | 
| 8 8 | 
             
              def initialize(connection, logger, config)
         | 
| 9 9 | 
             
                super
         | 
| 10 | 
            -
                @connection.create_function(' | 
| 10 | 
            +
                @connection.create_function('MURLSHMATCH', 2) do |func,search_in,search_for|
         | 
| 11 11 | 
             
                  func.result = search_in.to_s.match(/#{search_for}/i) ? 1 : nil
         | 
| 12 12 | 
             
                end
         | 
| 13 13 | 
             
              end
         | 
    
        data/lib/murlsh/uri_ask.rb
    CHANGED
    
    | @@ -4,6 +4,7 @@ net/https | |
| 4 4 | 
             
            open-uri
         | 
| 5 5 | 
             
            uri
         | 
| 6 6 |  | 
| 7 | 
            +
            hpricot
         | 
| 7 8 | 
             
            htmlentities
         | 
| 8 9 | 
             
            iconv
         | 
| 9 10 | 
             
            }.each { |m| require m }
         | 
| @@ -22,19 +23,23 @@ module Murlsh | |
| 22 23 | 
             
                  return @content_type if defined?(@content_type)
         | 
| 23 24 | 
             
                  options[:headers] = default_headers.merge(options.fetch(:headers, {}))
         | 
| 24 25 |  | 
| 25 | 
            -
                   | 
| 26 | 
            +
                  content_type = ''
         | 
| 26 27 | 
             
                  Murlsh::failproof(options) do
         | 
| 27 28 | 
             
                    # try head first to save bandwidth
         | 
| 28 29 | 
             
                    http = Net::HTTP.new(host, port)
         | 
| 29 30 | 
             
                    http.use_ssl = (scheme == 'https')
         | 
| 30 31 |  | 
| 31 32 | 
             
                    resp = http.request_head(path_query, options[:headers])
         | 
| 32 | 
            -
             | 
| 33 | 
            -
             | 
| 34 | 
            -
                       | 
| 33 | 
            +
             | 
| 34 | 
            +
                    if Net::HTTPSuccess === resp
         | 
| 35 | 
            +
                      content_type = resp['content-type']
         | 
| 36 | 
            +
                    end
         | 
| 37 | 
            +
             | 
| 38 | 
            +
                    if not content_type or content_type.empty?
         | 
| 39 | 
            +
                      content_type = self.open(options[:headers]) { |f| f.content_type }
         | 
| 35 40 | 
             
                    end
         | 
| 36 41 | 
             
                  end
         | 
| 37 | 
            -
                  @content_type
         | 
| 42 | 
            +
                  @content_type = content_type
         | 
| 38 43 | 
             
                end
         | 
| 39 44 |  | 
| 40 45 | 
             
                # Get the HTML title.
         | 
| @@ -91,8 +96,12 @@ module Murlsh | |
| 91 96 | 
             
                  if html?(options)
         | 
| 92 97 | 
             
                    Murlsh::failproof(options) do
         | 
| 93 98 | 
             
                      self.open(options[:headers]) do |f|
         | 
| 94 | 
            -
                         | 
| 95 | 
            -
             | 
| 99 | 
            +
                        html_parse_plugins = Murlsh::Plugin.hooks('html_parse')
         | 
| 100 | 
            +
                        @doc = if html_parse_plugins.empty?
         | 
| 101 | 
            +
                          Hpricot(f).extend(Murlsh::Doc)
         | 
| 102 | 
            +
                        else
         | 
| 103 | 
            +
                          html_parse_plugins.first.run(f).extend(Murlsh::Doc)
         | 
| 104 | 
            +
                        end
         | 
| 96 105 |  | 
| 97 106 | 
             
                        @charset = @doc.charset || f.charset
         | 
| 98 107 | 
             
                      end
         | 
    
        data/lib/murlsh/url.rb
    CHANGED
    
    
    
        data/lib/murlsh/url_body.rb
    CHANGED
    
    | @@ -1,3 +1,7 @@ | |
| 1 | 
            +
            %w{
         | 
| 2 | 
            +
            builder
         | 
| 3 | 
            +
            }.each { |m| require m }
         | 
| 4 | 
            +
             | 
| 1 5 | 
             
            module Murlsh
         | 
| 2 6 |  | 
| 3 7 | 
             
              # Url list page builder.
         | 
| @@ -20,7 +24,7 @@ module Murlsh | |
| 20 24 | 
             
                def search_conditions
         | 
| 21 25 | 
             
                  if @q
         | 
| 22 26 | 
             
                    search_cols = %w{name title url}
         | 
| 23 | 
            -
                    [search_cols.map { |x| " | 
| 27 | 
            +
                    [search_cols.map { |x| "MURLSHMATCH(#{x}, ?)" }.join(' OR ')].push(
         | 
| 24 28 | 
             
                      *[@q] * search_cols.size)
         | 
| 25 29 | 
             
                  else
         | 
| 26 30 | 
             
                    []
         | 
    
        data/lib/murlsh/url_server.rb
    CHANGED
    
    | @@ -8,6 +8,8 @@ module Murlsh | |
| 8 8 | 
             
              # Build responses for HTTP requests.
         | 
| 9 9 | 
             
              class UrlServer
         | 
| 10 10 |  | 
| 11 | 
            +
                include HeadFromGet
         | 
| 12 | 
            +
             | 
| 11 13 | 
             
                def initialize(config, db)
         | 
| 12 14 | 
             
                  @config, @db = config, db
         | 
| 13 15 | 
             
                  ActiveRecord::Base.default_timezone = :utc
         | 
| @@ -34,38 +36,40 @@ module Murlsh | |
| 34 36 |  | 
| 35 37 | 
             
                # Respond to a POST request. Add the new url and return json.
         | 
| 36 38 | 
             
                def post(req)
         | 
| 37 | 
            -
                   | 
| 38 | 
            -
             | 
| 39 | 
            -
                     | 
| 40 | 
            -
             | 
| 41 | 
            -
                       | 
| 42 | 
            -
             | 
| 43 | 
            -
             | 
| 44 | 
            -
                       | 
| 45 | 
            -
             | 
| 46 | 
            -
             | 
| 47 | 
            -
             | 
| 48 | 
            -
             | 
| 49 | 
            -
             | 
| 50 | 
            -
                      end
         | 
| 39 | 
            +
                  auth = req.params['auth']
         | 
| 40 | 
            +
                  if user = auth.empty? ? nil : Murlsh::Auth.new(
         | 
| 41 | 
            +
                    @config.fetch('auth_file')).auth(auth)
         | 
| 42 | 
            +
                    ActiveRecord::Base.establish_connection(:adapter => 'sqlite3',
         | 
| 43 | 
            +
                      :database => @config.fetch('db_file'))
         | 
| 44 | 
            +
             | 
| 45 | 
            +
                    mu = Murlsh::Url.new do |u|
         | 
| 46 | 
            +
                      u.time = Time.now.gmtime
         | 
| 47 | 
            +
                      u.url = req.params['url']
         | 
| 48 | 
            +
                      u.email = user[:email]
         | 
| 49 | 
            +
                      u.name = user[:name]
         | 
| 50 | 
            +
                      u.via = req.params['via'] unless (req.params['via'] || []).empty?
         | 
| 51 | 
            +
                    end
         | 
| 51 52 |  | 
| 53 | 
            +
                    begin
         | 
| 54 | 
            +
                      # validate before add_pre plugins have run and also after (in save!)
         | 
| 55 | 
            +
                      raise ActiveRecord::RecordInvalid.new(mu) unless mu.valid?
         | 
| 52 56 | 
             
                      Murlsh::Plugin.hooks('add_pre') { |p| p.run(mu, @config) }
         | 
| 53 | 
            -
             | 
| 54 | 
            -
                      mu.save
         | 
| 55 | 
            -
             | 
| 57 | 
            +
                      mu.save!
         | 
| 56 58 | 
             
                      Murlsh::Plugin.hooks('add_post') { |p| p.run(@config) }
         | 
| 57 | 
            -
             | 
| 58 | 
            -
             | 
| 59 | 
            -
             | 
| 60 | 
            -
             | 
| 61 | 
            -
             | 
| 62 | 
            -
             | 
| 63 | 
            -
                       | 
| 64 | 
            -
                        'Content-Type' => 'text/plain' })
         | 
| 59 | 
            +
                      response_body, response_code = [mu], 200
         | 
| 60 | 
            +
                    rescue ActiveRecord::RecordInvalid => error
         | 
| 61 | 
            +
                      response_body = {
         | 
| 62 | 
            +
                        'url' => error.record,
         | 
| 63 | 
            +
                        'errors' => error.record.errors,
         | 
| 64 | 
            +
                        }
         | 
| 65 | 
            +
                      response_code = 500
         | 
| 65 66 | 
             
                    end
         | 
| 66 67 | 
             
                  else
         | 
| 67 | 
            -
                     | 
| 68 | 
            +
                    response_body, response_code = '', 403
         | 
| 68 69 | 
             
                  end
         | 
| 70 | 
            +
             | 
| 71 | 
            +
                  Rack::Response.new(response_body.to_json, response_code, {
         | 
| 72 | 
            +
                    'Content-Type' => 'application/json' })
         | 
| 69 73 | 
             
                end
         | 
| 70 74 |  | 
| 71 75 | 
             
              end
         | 
    
        data/lib/murlsh.rb
    CHANGED
    
    
    
        data/murlsh.gemspec
    CHANGED
    
    | @@ -5,11 +5,11 @@ | |
| 5 5 |  | 
| 6 6 | 
             
            Gem::Specification.new do |s|
         | 
| 7 7 | 
             
              s.name = %q{murlsh}
         | 
| 8 | 
            -
              s.version = "0. | 
| 8 | 
            +
              s.version = "0.11.0"
         | 
| 9 9 |  | 
| 10 10 | 
             
              s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
         | 
| 11 11 | 
             
              s.authors = ["Matthew M. Boedicker"]
         | 
| 12 | 
            -
              s.date = %q{2010- | 
| 12 | 
            +
              s.date = %q{2010-09-21}
         | 
| 13 13 | 
             
              s.default_executable = %q{murlsh}
         | 
| 14 14 | 
             
              s.description = %q{url sharing site framework with easy adding, title lookup, atom feed, thumbnails and embedding}
         | 
| 15 15 | 
             
              s.email = %q{matthewm@boedicker.org}
         | 
| @@ -36,6 +36,7 @@ Gem::Specification.new do |s| | |
| 36 36 | 
             
                 "lib/murlsh/failproof.rb",
         | 
| 37 37 | 
             
                 "lib/murlsh/far_future_expires.rb",
         | 
| 38 38 | 
             
                 "lib/murlsh/flickr_server.rb",
         | 
| 39 | 
            +
                 "lib/murlsh/head_from_get.rb",
         | 
| 39 40 | 
             
                 "lib/murlsh/markup.rb",
         | 
| 40 41 | 
             
                 "lib/murlsh/must_revalidate.rb",
         | 
| 41 42 | 
             
                 "lib/murlsh/openlock.rb",
         | 
| @@ -57,6 +58,7 @@ Gem::Specification.new do |s| | |
| 57 58 | 
             
                 "plugins/add_post_60_notify_hubs.rb",
         | 
| 58 59 | 
             
                 "plugins/add_pre_50_lookup_content_type_title.rb",
         | 
| 59 60 | 
             
                 "plugins/add_pre_60_github_title.rb",
         | 
| 61 | 
            +
                 "plugins/add_pre_60_google_code_title.rb",
         | 
| 60 62 | 
             
                 "plugins/hostrec_50_redundant.rb",
         | 
| 61 63 | 
             
                 "plugins/hostrec_60_skip.rb",
         | 
| 62 64 | 
             
                 "plugins/html_parse_50_hpricot.rb",
         | 
| @@ -11,8 +11,11 @@ module Murlsh | |
| 11 11 |  | 
| 12 12 | 
             
                def self.run(url, config)
         | 
| 13 13 | 
             
                  ask = URI(url.url).extend(Murlsh::UriAsk)
         | 
| 14 | 
            -
                   | 
| 15 | 
            -
             | 
| 14 | 
            +
                  headers = {
         | 
| 15 | 
            +
                    'User-Agent' => 'murlsh (http://github.com/mmb/murlsh)'
         | 
| 16 | 
            +
                  }
         | 
| 17 | 
            +
                  url.content_type = ask.content_type(:headers => headers)
         | 
| 18 | 
            +
                  url.title = ask.title(:headers => headers)
         | 
| 16 19 | 
             
                end
         | 
| 17 20 |  | 
| 18 21 | 
             
              end
         | 
| @@ -11,7 +11,7 @@ module Murlsh | |
| 11 11 | 
             
                @hook = 'add_pre'
         | 
| 12 12 |  | 
| 13 13 | 
             
                def self.run(url, config)
         | 
| 14 | 
            -
                  if url.url[%r{http://github | 
| 14 | 
            +
                  if url.url[%r{^http://github\.com/\w+/[\w.-]+$}]
         | 
| 15 15 | 
             
                    ask = URI(url.url).extend(Murlsh::UriAsk)
         | 
| 16 16 | 
             
                    url.title << " - #{ask.description}" unless ask.description.empty?
         | 
| 17 17 | 
             
                  end
         | 
| @@ -0,0 +1,27 @@ | |
| 1 | 
            +
            %w{
         | 
| 2 | 
            +
            murlsh
         | 
| 3 | 
            +
            }.each { |m| require m }
         | 
| 4 | 
            +
             | 
| 5 | 
            +
            module Murlsh
         | 
| 6 | 
            +
             | 
| 7 | 
            +
              # Google Code project page titles are not very descriptive so add summary
         | 
| 8 | 
            +
              # from page
         | 
| 9 | 
            +
              class AddPre60GoogleCodeTitle < Plugin
         | 
| 10 | 
            +
             | 
| 11 | 
            +
                @hook = 'add_pre'
         | 
| 12 | 
            +
             | 
| 13 | 
            +
                def self.run(url, config)
         | 
| 14 | 
            +
                  if url.url[%r{^http://code\.google\.com/p/[\w-]+/$}]
         | 
| 15 | 
            +
                    puts 'xxx'
         | 
| 16 | 
            +
                    ask = URI(url.url).extend(Murlsh::UriAsk)
         | 
| 17 | 
            +
                    ask.doc.xpath_search("//a[@id='project_summary_link']") do |node|
         | 
| 18 | 
            +
                      summary = node ? node.inner_html : nil
         | 
| 19 | 
            +
                      url.title << " - #{ask.decode(summary)}" unless !summary or
         | 
| 20 | 
            +
                        summary.empty?
         | 
| 21 | 
            +
                    end
         | 
| 22 | 
            +
                  end
         | 
| 23 | 
            +
                end
         | 
| 24 | 
            +
             | 
| 25 | 
            +
              end
         | 
| 26 | 
            +
             | 
| 27 | 
            +
            end
         | 
    
        data/plugins/via_50_domain.rb
    CHANGED
    
    | @@ -21,7 +21,7 @@ module Murlsh | |
| 21 21 | 
             
                    "#{m[1]}.reddit"
         | 
| 22 22 | 
             
                  when m = search.match(%r{^delicious\.com/(\w+)}i)
         | 
| 23 23 | 
             
                    "delicious/#{m[1]}"
         | 
| 24 | 
            -
                  when m = search.match(%r{^twitter\.com/(\w+) | 
| 24 | 
            +
                  when m = search.match(%r{^twitter\.com/(\w+)}i)
         | 
| 25 25 | 
             
                    "twitter/#{m[1]}"
         | 
| 26 26 | 
             
                  when m = search.match(%r{^([a-z\d][a-z\d-]{0,61}[a-z\d])\.tumblr\.com/}i)
         | 
| 27 27 | 
             
                    "#{m[1]}.tumblr"
         | 
    
        data/public/css/screen.css
    CHANGED
    
    
    
        data/public/js/comments.json
    CHANGED
    
    | @@ -1,12 +1 @@ | |
| 1 | 
            -
            {
         | 
| 2 | 
            -
                "http://url/being/commented/on": [
         | 
| 3 | 
            -
                    {
         | 
| 4 | 
            -
                        "authorAvatar": "http://url/of/your/avatar/image",
         | 
| 5 | 
            -
                        "authorName": "yourname",
         | 
| 6 | 
            -
                        "authorUrl": "http://url/of/your/site",
         | 
| 7 | 
            -
                        "comment": "your comment",
         | 
| 8 | 
            -
                        "createdTime": 1275005075,
         | 
| 9 | 
            -
                        "updatedTime": 1275005075
         | 
| 10 | 
            -
                    },
         | 
| 11 | 
            -
                ],
         | 
| 12 | 
            -
            }
         | 
| 1 | 
            +
            {"http://www.youtube.com/watch?v=KrfpnbGXL70":[{"createdTime":1277520298,"updatedTime":1277520298,"authorAvatar":"http://www.gravatar.com/avatar/355af1bc931baca530e66571923286b4?s=16","authorName":"mmb","authorUrl":"http://matthewm.boedicker.org/","comment":"Through SOAP!"},{"createdTime":1277520298,"updatedTime":1277520298,"authorAvatar":"http://www.gravatar.com/avatar/355af1bc931baca530e66571923286b4?s=16","authorName":"mmb","authorUrl":"http://matthewm.boedicker.org/","comment":"dead, can be seen at http://jz10.java.no/java-4-ever-trailer.html"}]}
         | 
    
        data/public/js/js.js
    CHANGED
    
    | @@ -3,6 +3,15 @@ | |
| 3 3 | 
             
            "use strict";
         | 
| 4 4 |  | 
| 5 5 | 
             
            var Murlsh = function (config, $, navigator, window) {
         | 
| 6 | 
            +
                function compileRegexMap(regexMap) {
         | 
| 7 | 
            +
                    var result = {};
         | 
| 8 | 
            +
                    $.each(regexMap, function (reStr) {
         | 
| 9 | 
            +
                        result[reStr] = new RegExp('^' + reStr + '$', 'i'); 
         | 
| 10 | 
            +
                    });
         | 
| 11 | 
            +
             | 
| 12 | 
            +
                    return result;
         | 
| 13 | 
            +
                }
         | 
| 14 | 
            +
             | 
| 6 15 | 
             
                var my = {},
         | 
| 7 16 | 
             
                    hrefRes = {
         | 
| 8 17 | 
             
                        flickr :
         | 
| @@ -10,7 +19,7 @@ var Murlsh = function (config, $, navigator, window) { | |
| 10 19 | 
             
                        imageshack :
         | 
| 11 20 | 
             
                            /^(http:\/\/img\d+\.imageshack\.us\/img\d+\/\d+\/\w+\.)(jpe?g|gif|png)$/i,
         | 
| 12 21 | 
             
                        imgur :
         | 
| 13 | 
            -
                            /^(http:\/\/(?:i\.)?imgur\.com\/[a-z\d]+)(\.(?:jpe?g|gif|png))$/i,
         | 
| 22 | 
            +
                            /^(http:\/\/(?:i\.)?imgur\.com\/)([a-z\d]+)(\.(?:jpe?g|gif|png))$/i,
         | 
| 14 23 | 
             
                        mp3 :
         | 
| 15 24 | 
             
                            /\.mp3$/i,
         | 
| 16 25 | 
             
                        s3 :
         | 
| @@ -22,7 +31,7 @@ var Murlsh = function (config, $, navigator, window) { | |
| 22 31 | 
             
                        youtube :
         | 
| 23 32 | 
             
                            /^http:\/\/(?:(?:www|uk)\.)?youtube\.com\/watch\?v=([\w\-]+)(?:&|$)/i
         | 
| 24 33 | 
             
                    },
         | 
| 25 | 
            -
                     | 
| 34 | 
            +
                    thumbLocatorsCompiled = compileRegexMap(config.thumb_locators);
         | 
| 26 35 |  | 
| 27 36 | 
             
                function autoLink(s) {
         | 
| 28 37 | 
             
                    // turn urls into links
         | 
| @@ -75,11 +84,6 @@ var Murlsh = function (config, $, navigator, window) { | |
| 75 84 | 
             
                    return result;
         | 
| 76 85 | 
             
                }
         | 
| 77 86 |  | 
| 78 | 
            -
                function appleThumb(host) {
         | 
| 79 | 
            -
                    return img('http://' + host + '/apple-touch-icon.png', '').addClass(
         | 
| 80 | 
            -
                        'thumb apple');
         | 
| 81 | 
            -
                }
         | 
| 82 | 
            -
             | 
| 83 87 | 
             
                function closerAdd(x, header) {
         | 
| 84 88 | 
             
                    var html = (typeof x === 'object') ? $('<div />').append(x).html() : x;
         | 
| 85 89 |  | 
| @@ -226,16 +230,15 @@ var Murlsh = function (config, $, navigator, window) { | |
| 226 230 | 
             
                            .append($('<span />').append(comment.authorName).addClass(
         | 
| 227 231 | 
             
                                'comment-name'))
         | 
| 228 232 | 
             
                            .append(' : ')
         | 
| 229 | 
            -
                            .append($('<span />').append(autoLink(comment.comment)) | 
| 230 | 
            -
                                addClass('comment-comment'))
         | 
| 233 | 
            +
                            .append($('<span />').append(autoLink(comment.comment))
         | 
| 234 | 
            +
                                .addClass('comment-comment'))
         | 
| 231 235 | 
             
                            .appendTo(ul);
         | 
| 232 236 | 
             
                    }
         | 
| 233 237 | 
             
                };
         | 
| 234 238 |  | 
| 235 239 | 
             
                my.addExtra = function () {
         | 
| 236 | 
            -
                    var  | 
| 237 | 
            -
                         | 
| 238 | 
            -
                        href = $(this).attr('href'),
         | 
| 240 | 
            +
                    var thisA = $(this),
         | 
| 241 | 
            +
                        href = thisA.attr('href'),
         | 
| 239 242 | 
             
                        match = {},
         | 
| 240 243 | 
             
                        swf = 'swf/player_mp3_mini.swf',
         | 
| 241 244 | 
             
                        thumb;
         | 
| @@ -258,18 +261,19 @@ var Murlsh = function (config, $, navigator, window) { | |
| 258 261 | 
             
                            success : function (d) {
         | 
| 259 262 | 
             
                                thumbInsert(flickrThumb(d), flickrClick, $(this));
         | 
| 260 263 | 
             
                            },
         | 
| 261 | 
            -
                            context :  | 
| 264 | 
            +
                            context : thisA,
         | 
| 262 265 | 
             
                            jsonpCallback : 'flickrCallback' + match.flickr[1]
         | 
| 263 266 | 
             
                        });
         | 
| 264 267 | 
             
                    } else if (match.imageshack) {
         | 
| 265 268 | 
             
                        thumbInsert(imgThumb(match.imageshack[1], 'th.',
         | 
| 266 269 | 
             
                            match.imageshack[2]).data('href', match.imageshack[0]),
         | 
| 267 | 
            -
                                imgClick,  | 
| 270 | 
            +
                                imgClick, thisA.html('imageshack.us'));
         | 
| 268 271 | 
             
                    } else if (match.imgur) {
         | 
| 269 | 
            -
                        thumbInsert(imgThumb(match.imgur[1],  | 
| 270 | 
            -
                            'href', match.imgur[0]), imgClick, | 
| 272 | 
            +
                        thumbInsert(imgThumb(match.imgur[1], match.imgur[2], 's',
         | 
| 273 | 
            +
                            match.imgur[3]).data('href', match.imgur[0]), imgClick,
         | 
| 274 | 
            +
                            thisA.html('imgur/' + match.imgur[2] + match.imgur[3]));
         | 
| 271 275 | 
             
                    } else if (match.mp3) {
         | 
| 272 | 
            -
                         | 
| 276 | 
            +
                        thisA.before(objectTag(swf, 20, 200, [
         | 
| 273 277 | 
             
                            { name : 'bgcolor', value : '#000000' },
         | 
| 274 278 | 
             
                            { name : 'FlashVars', value : 'mp3=' + href },
         | 
| 275 279 | 
             
                            { name : 'movie', value : swf }
         | 
| @@ -278,13 +282,13 @@ var Murlsh = function (config, $, navigator, window) { | |
| 278 282 | 
             
                        thumb = imgThumb(match.s3[1], 'th.', match.s3[2]);
         | 
| 279 283 |  | 
| 280 284 | 
             
                        if (match.s3[2].match(/^pdf$/i)) {
         | 
| 281 | 
            -
                             | 
| 285 | 
            +
                            thisA.before(thumb).html('pdf');
         | 
| 282 286 | 
             
                        } else {
         | 
| 283 287 | 
             
                            if (my.isIphone()) {
         | 
| 284 | 
            -
                                 | 
| 288 | 
            +
                                thisA.html(thumb);
         | 
| 285 289 | 
             
                            } else {
         | 
| 286 | 
            -
                                 | 
| 287 | 
            -
                                 | 
| 290 | 
            +
                                thisA.html('link');
         | 
| 291 | 
            +
                                thisA.before(thumb.data('href', match.s3[0]).click(
         | 
| 288 292 | 
             
                                    imgClick));
         | 
| 289 293 | 
             
                            }
         | 
| 290 294 | 
             
                        }
         | 
| @@ -308,7 +312,7 @@ var Murlsh = function (config, $, navigator, window) { | |
| 308 312 |  | 
| 309 313 | 
             
                                $(this).replaceWith(tweet);
         | 
| 310 314 | 
             
                            },
         | 
| 311 | 
            -
                            context :  | 
| 315 | 
            +
                            context : thisA,
         | 
| 312 316 | 
             
                            jsonpCallback : 'twitterCallback' + match.twitter[1]
         | 
| 313 317 | 
             
                        });
         | 
| 314 318 | 
             
                    } else if (match.vimeo) {
         | 
| @@ -326,20 +330,21 @@ var Murlsh = function (config, $, navigator, window) { | |
| 326 330 | 
             
                                        { name : 'movie', value : movie }
         | 
| 327 331 | 
             
                                    ])), vimeoClick, $(this));
         | 
| 328 332 | 
             
                            },
         | 
| 329 | 
            -
                            context :  | 
| 333 | 
            +
                            context : thisA,
         | 
| 330 334 | 
             
                            jsonpCallback : 'vimeoCallback' + match.vimeo[1]
         | 
| 331 335 | 
             
                        });
         | 
| 332 336 | 
             
                    } else if (match.youtube) {
         | 
| 333 | 
            -
                        thumbInsert(youtubeThumb(match.youtube[1]), youtubeClick,  | 
| 337 | 
            +
                        thumbInsert(youtubeThumb(match.youtube[1]), youtubeClick, thisA);
         | 
| 334 338 | 
             
                    } else {
         | 
| 335 | 
            -
                         | 
| 336 | 
            -
             | 
| 337 | 
            -
             | 
| 338 | 
            -
             | 
| 339 | 
            -
             | 
| 340 | 
            -
             | 
| 339 | 
            +
                        $.each(config.thumb_locators, function (reStr) {
         | 
| 340 | 
            +
                            var re = thumbLocatorsCompiled[reStr];
         | 
| 341 | 
            +
                            if (href.match(re)) {
         | 
| 342 | 
            +
                                thumbInsert(img(href.replace(re,
         | 
| 343 | 
            +
                                    config.thumb_locators[reStr])).addClass(
         | 
| 344 | 
            +
                                    'thumb locator'), null, thisA);
         | 
| 345 | 
            +
                                return false;
         | 
| 341 346 | 
             
                            }
         | 
| 342 | 
            -
                        }
         | 
| 347 | 
            +
                        });
         | 
| 343 348 | 
             
                    }
         | 
| 344 349 | 
             
                };
         | 
| 345 350 |  | 
    
        metadata
    CHANGED
    
    | @@ -1,13 +1,13 @@ | |
| 1 1 | 
             
            --- !ruby/object:Gem::Specification 
         | 
| 2 2 | 
             
            name: murlsh
         | 
| 3 3 | 
             
            version: !ruby/object:Gem::Version 
         | 
| 4 | 
            -
              hash:  | 
| 4 | 
            +
              hash: 51
         | 
| 5 5 | 
             
              prerelease: false
         | 
| 6 6 | 
             
              segments: 
         | 
| 7 7 | 
             
              - 0
         | 
| 8 | 
            -
              -  | 
| 8 | 
            +
              - 11
         | 
| 9 9 | 
             
              - 0
         | 
| 10 | 
            -
              version: 0. | 
| 10 | 
            +
              version: 0.11.0
         | 
| 11 11 | 
             
            platform: ruby
         | 
| 12 12 | 
             
            authors: 
         | 
| 13 13 | 
             
            - Matthew M. Boedicker
         | 
| @@ -15,7 +15,7 @@ autorequire: | |
| 15 15 | 
             
            bindir: bin
         | 
| 16 16 | 
             
            cert_chain: []
         | 
| 17 17 |  | 
| 18 | 
            -
            date: 2010- | 
| 18 | 
            +
            date: 2010-09-21 00:00:00 -04:00
         | 
| 19 19 | 
             
            default_executable: murlsh
         | 
| 20 20 | 
             
            dependencies: 
         | 
| 21 21 | 
             
            - !ruby/object:Gem::Dependency 
         | 
| @@ -237,6 +237,7 @@ files: | |
| 237 237 | 
             
            - lib/murlsh/failproof.rb
         | 
| 238 238 | 
             
            - lib/murlsh/far_future_expires.rb
         | 
| 239 239 | 
             
            - lib/murlsh/flickr_server.rb
         | 
| 240 | 
            +
            - lib/murlsh/head_from_get.rb
         | 
| 240 241 | 
             
            - lib/murlsh/markup.rb
         | 
| 241 242 | 
             
            - lib/murlsh/must_revalidate.rb
         | 
| 242 243 | 
             
            - lib/murlsh/openlock.rb
         | 
| @@ -258,6 +259,7 @@ files: | |
| 258 259 | 
             
            - plugins/add_post_60_notify_hubs.rb
         | 
| 259 260 | 
             
            - plugins/add_pre_50_lookup_content_type_title.rb
         | 
| 260 261 | 
             
            - plugins/add_pre_60_github_title.rb
         | 
| 262 | 
            +
            - plugins/add_pre_60_google_code_title.rb
         | 
| 261 263 | 
             
            - plugins/hostrec_50_redundant.rb
         | 
| 262 264 | 
             
            - plugins/hostrec_60_skip.rb
         | 
| 263 265 | 
             
            - plugins/html_parse_50_hpricot.rb
         |