murlsh 0.2.4 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.textile +2 -2
- data/Rakefile +1 -0
- data/VERSION +1 -1
- data/bin/murlsh +1 -1
- data/config.yaml +1 -1
- data/lib/murlsh/atom_feed.rb +12 -0
- data/lib/murlsh/auth.rb +10 -0
- data/lib/murlsh/dispatch.rb +4 -0
- data/lib/murlsh/get_content_type.rb +15 -7
- data/lib/murlsh/get_title.rb +7 -0
- data/lib/murlsh/markup.rb +27 -0
- data/lib/murlsh/plugin.rb +14 -1
- data/lib/murlsh/referrer.rb +3 -0
- data/lib/murlsh/sqlite3_adapter.rb +1 -0
- data/lib/murlsh/time.rb +2 -0
- data/lib/murlsh/url.rb +10 -11
- data/lib/murlsh/url_body.rb +15 -0
- data/lib/murlsh/url_server.rb +6 -3
- data/lib/murlsh/xhtml_response.rb +3 -2
- data/murlsh.gemspec +5 -2
- data/plugins/hostrec_redundant.rb +14 -0
- data/plugins/hostrec_skip.rb +23 -0
- data/plugins/lookup_content_type_title.rb +17 -0
- data/public/css/phone.css +12 -0
- data/public/js/js.js +6 -1
- metadata +5 -2
data/README.textile
CHANGED
data/Rakefile
CHANGED
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.3.0
|
data/bin/murlsh
CHANGED
@@ -6,7 +6,7 @@ FileUtils.cp_r(
|
|
6
6
|
%w{.htaccess config.ru config.yaml plugins/ public/ Rakefile}.collect { |x|
|
7
7
|
File.join(File.dirname(__FILE__), '..', x) }, '.', :verbose => true)
|
8
8
|
|
9
|
-
FileUtils.
|
9
|
+
FileUtils.mkdir_p('tmp', :verbose => true)
|
10
10
|
|
11
11
|
puts <<eos
|
12
12
|
Next steps:
|
data/config.yaml
CHANGED
data/lib/murlsh/atom_feed.rb
CHANGED
@@ -5,8 +5,14 @@ require 'uri'
|
|
5
5
|
|
6
6
|
module Murlsh
|
7
7
|
|
8
|
+
# ATOM feed builder.
|
8
9
|
class AtomFeed
|
9
10
|
|
11
|
+
# root_url is the base url for the feed items.
|
12
|
+
#
|
13
|
+
# Options:
|
14
|
+
# * :filename - the file name of the feed (atom.xml)
|
15
|
+
# * :title - the feed title
|
10
16
|
def initialize(root_url, options={})
|
11
17
|
options = {
|
12
18
|
:filename => 'atom.xml',
|
@@ -18,6 +24,7 @@ module Murlsh
|
|
18
24
|
setup_id_fields
|
19
25
|
end
|
20
26
|
|
27
|
+
# Set up fields to use for building item ids.
|
21
28
|
def setup_id_fields
|
22
29
|
uri_parsed = URI(@root_url)
|
23
30
|
|
@@ -28,6 +35,7 @@ module Murlsh
|
|
28
35
|
@path = uri_parsed.path
|
29
36
|
end
|
30
37
|
|
38
|
+
# Generate the feed and write it to the filesystem with locking.
|
31
39
|
def write(entries, path)
|
32
40
|
open(path, 'w') do |f|
|
33
41
|
f.flock(File::LOCK_EX)
|
@@ -38,6 +46,8 @@ module Murlsh
|
|
38
46
|
end
|
39
47
|
end
|
40
48
|
|
49
|
+
# Build the feed using XML builder. Options are passed to
|
50
|
+
# Builder::XmlMarkup.new.
|
41
51
|
def make(entries, options={})
|
42
52
|
xm = Builder::XmlMarkup.new(options)
|
43
53
|
xm.instruct! :xml
|
@@ -62,10 +72,12 @@ module Murlsh
|
|
62
72
|
xm
|
63
73
|
end
|
64
74
|
|
75
|
+
# Build the entry's id.
|
65
76
|
def entry_id(url)
|
66
77
|
"tag:#{@domain},#{url.time.strftime('%Y-%m-%d')}:#{@host}#{@path}#{url.id}"
|
67
78
|
end
|
68
79
|
|
80
|
+
# Add an ATOM enclosure if the url is an image.
|
69
81
|
def enclosure(xm, mu)
|
70
82
|
xm.link(:rel => 'enclosure', :type => mu.content_type, :href => mu.url,
|
71
83
|
:title => 'Full-size') if mu.is_image?
|
data/lib/murlsh/auth.rb
CHANGED
@@ -6,12 +6,21 @@ require 'digest/md5'
|
|
6
6
|
|
7
7
|
module Murlsh
|
8
8
|
|
9
|
+
# Interface to authentication file. Format of authentication file:
|
10
|
+
#
|
11
|
+
# username,MD5 hash of email address,bcrypted password
|
12
|
+
#
|
13
|
+
# Authentication is done using password only to make adding easier and
|
14
|
+
# because there will be a small number of trusted users.
|
15
|
+
#
|
16
|
+
# See Rakefile for user maintenance tasks.
|
9
17
|
class Auth
|
10
18
|
|
11
19
|
def initialize(file)
|
12
20
|
@file = file
|
13
21
|
end
|
14
22
|
|
23
|
+
# Authenticate a user by password. Return their name and email if correct.
|
15
24
|
def auth(password)
|
16
25
|
CSV::Reader.parse(open(@file)) do |row|
|
17
26
|
return { :name => row[0], :email => row[1] } if
|
@@ -19,6 +28,7 @@ module Murlsh
|
|
19
28
|
end
|
20
29
|
end
|
21
30
|
|
31
|
+
# Add a user to the authentication file.
|
22
32
|
def add_user(username, email, password)
|
23
33
|
open(@file, 'a') do |f|
|
24
34
|
f.flock(File::LOCK_EX)
|
data/lib/murlsh/dispatch.rb
CHANGED
@@ -11,8 +11,10 @@ yaml
|
|
11
11
|
|
12
12
|
module Murlsh
|
13
13
|
|
14
|
+
# Dispatch requests.
|
14
15
|
class Dispatch
|
15
16
|
|
17
|
+
# Set up config hash and database connection.
|
16
18
|
def initialize
|
17
19
|
@config = YAML.load_file('config.yaml')
|
18
20
|
@url_root = URI(@config.fetch('root_url')).path
|
@@ -25,6 +27,7 @@ module Murlsh
|
|
25
27
|
@url_server = Murlsh::UrlServer.new(@config, @db)
|
26
28
|
end
|
27
29
|
|
30
|
+
# Rack call.
|
28
31
|
def call(env)
|
29
32
|
dispatch = {
|
30
33
|
['GET', @url_root] => [@url_server, :get],
|
@@ -41,6 +44,7 @@ module Murlsh
|
|
41
44
|
obj.send(meth, req).finish
|
42
45
|
end
|
43
46
|
|
47
|
+
# Called if the request is not found.
|
44
48
|
def not_found(req)
|
45
49
|
Rack::Response.new("<p>#{req.url} not found</p>
|
46
50
|
|
@@ -4,6 +4,7 @@ require 'uri'
|
|
4
4
|
|
5
5
|
class URI::Generic
|
6
6
|
|
7
|
+
# Return the path and query string.
|
7
8
|
def path_query
|
8
9
|
path + (query ? "?#{query}" : '')
|
9
10
|
end
|
@@ -14,6 +15,11 @@ module Murlsh
|
|
14
15
|
|
15
16
|
module_function
|
16
17
|
|
18
|
+
# Try to get the content type of a url.
|
19
|
+
#
|
20
|
+
# Options:
|
21
|
+
# * :failproof - if true hide all exceptions and return empty string on failure
|
22
|
+
# * :headers - hash of headers to send in request
|
17
23
|
def get_content_type(url, options={})
|
18
24
|
options[:headers] = default_headers(url).merge(
|
19
25
|
options.fetch(:headers, {}))
|
@@ -48,6 +54,10 @@ module Murlsh
|
|
48
54
|
uri.is_a?(URI::HTTP) ? uri : URI(uri)
|
49
55
|
end
|
50
56
|
|
57
|
+
# Create a Net::HTTP to a host and port.
|
58
|
+
#
|
59
|
+
# Options:
|
60
|
+
# * :debug - stream to write debug output to
|
51
61
|
def make_net_http(url, options={})
|
52
62
|
net_http = Net::HTTP.new(url.host, url.port)
|
53
63
|
net_http.use_ssl = (url.scheme == 'https')
|
@@ -55,16 +65,14 @@ module Murlsh
|
|
55
65
|
net_http
|
56
66
|
end
|
57
67
|
|
58
|
-
# Get the response to HTTP HEAD. If HEAD
|
68
|
+
# Get the response to HTTP HEAD. If HEAD returns anything other than success
|
69
|
+
# try GET.
|
59
70
|
def get_resp(http, url, headers={})
|
60
|
-
resp = http.request_head(url.path_query, headers)
|
61
|
-
|
62
|
-
http.request_get(url.path_query, headers)
|
63
|
-
else
|
64
|
-
resp
|
65
|
-
end
|
71
|
+
resp = http.request_head(url.path_query, headers) === Net::HTTPSuccess ?
|
72
|
+
resp : http.request_get(url.path_query, headers)
|
66
73
|
end
|
67
74
|
|
75
|
+
# Get default headers sent with the request. Can be based on url.
|
68
76
|
def default_headers(url)
|
69
77
|
result = {
|
70
78
|
'User-Agent' =>
|
data/lib/murlsh/get_title.rb
CHANGED
@@ -10,6 +10,11 @@ module Murlsh
|
|
10
10
|
|
11
11
|
module_function
|
12
12
|
|
13
|
+
# Try to get the title of a url.
|
14
|
+
#
|
15
|
+
# Options:
|
16
|
+
# * :failproof - if true hide all exceptions and return empty string on failure
|
17
|
+
# * :headers - hash of headers to send in request
|
13
18
|
def get_title(url, options={})
|
14
19
|
options[:headers] = default_headers(url).merge(
|
15
20
|
options.fetch(:headers, {}))
|
@@ -35,6 +40,8 @@ module Murlsh
|
|
35
40
|
(result and !result.empty?) ? result : url
|
36
41
|
end
|
37
42
|
|
43
|
+
# Return true if the content type is likely to have a title that can be
|
44
|
+
# parsed.
|
38
45
|
def might_have_title(content_type)
|
39
46
|
content_type[/^text\/html/]
|
40
47
|
end
|
data/lib/murlsh/markup.rb
CHANGED
@@ -1,7 +1,12 @@
|
|
1
1
|
module Murlsh
|
2
2
|
|
3
|
+
# Helper mixin for XML builder.
|
3
4
|
module Markup
|
4
5
|
|
6
|
+
# Javascript link builder. Takes list of script urls.
|
7
|
+
#
|
8
|
+
# Options:
|
9
|
+
# * :prefix - prefix to append to all script urls
|
5
10
|
def javascript(sources, options={})
|
6
11
|
sources.to_a.each do |src|
|
7
12
|
script('', :type => 'text/javascript',
|
@@ -9,6 +14,15 @@ module Murlsh
|
|
9
14
|
end
|
10
15
|
end
|
11
16
|
|
17
|
+
# Image tag builder.
|
18
|
+
#
|
19
|
+
# Options:
|
20
|
+
# * :href - make the image a link to this url
|
21
|
+
# * :prefix - prefix to append to all image urls
|
22
|
+
# * :size - image size if square or [w, h]
|
23
|
+
# * :text - text for alt and title tag
|
24
|
+
#
|
25
|
+
# Any other options in hash will be added as attributes.
|
12
26
|
def murlsh_img(options={})
|
13
27
|
img_convert_prefix(options)
|
14
28
|
img_convert_size(options)
|
@@ -24,10 +38,16 @@ module Murlsh
|
|
24
38
|
end
|
25
39
|
end
|
26
40
|
|
41
|
+
# ATOM feed link builder.
|
27
42
|
def atom(href)
|
28
43
|
link(:rel => 'alternate', :type => 'application/atom+xml', :href => href)
|
29
44
|
end
|
30
45
|
|
46
|
+
# CSS link builder.
|
47
|
+
#
|
48
|
+
# Options:
|
49
|
+
# * :media - optional media attribute
|
50
|
+
# * :prefix - prepended to all CSS urls
|
31
51
|
def css(hrefs, options={})
|
32
52
|
hrefs.to_a.each do |href|
|
33
53
|
attrs = {
|
@@ -40,10 +60,16 @@ module Murlsh
|
|
40
60
|
end
|
41
61
|
end
|
42
62
|
|
63
|
+
# Meta tag builder. Takes a hash of name => content.
|
43
64
|
def metas(tags)
|
44
65
|
tags.each { |k,v| meta(:name => k, :content => v) }
|
45
66
|
end
|
46
67
|
|
68
|
+
# Gravatar builder. Takes MD5 hash of email address.
|
69
|
+
# Options:
|
70
|
+
# * 'd' - default Gravatar (identicon, monsterid, or wavatar)
|
71
|
+
# * 's' - size (0 - 512)
|
72
|
+
# * 'r' - rating (g, pg, r or x)
|
47
73
|
def gravatar(email_hash, options={})
|
48
74
|
query = options.reject do |k,v|
|
49
75
|
not ((k == 'd' and %w{identicon monsterid wavatar}.include?(v)) or
|
@@ -60,6 +86,7 @@ module Murlsh
|
|
60
86
|
murlsh_img(options)
|
61
87
|
end
|
62
88
|
|
89
|
+
# Query string builder. Takes hash of query string variables.
|
63
90
|
def build_query(h)
|
64
91
|
h.empty? ? '' :
|
65
92
|
'?' + h.collect { |k,v| URI.escape("#{k}=#{v}") }.join('&')
|
data/lib/murlsh/plugin.rb
CHANGED
@@ -1,13 +1,26 @@
|
|
1
1
|
module Murlsh
|
2
2
|
|
3
|
+
# Superclass for plugins. How plugins are registered.
|
4
|
+
#
|
5
|
+
# Hooks:
|
6
|
+
# * add_pre - called before a new url is saved
|
7
|
+
# run arguments (url, config hash)
|
8
|
+
# * add_post - called after a new url is saved
|
9
|
+
# run arguments (config hash)
|
10
|
+
# * hostrec - called to post process the domain that shows after links
|
11
|
+
# run arguments (domain, url, title)
|
3
12
|
class Plugin
|
4
13
|
|
14
|
+
# Called when a plugin class inherits from this class (the way plugins
|
15
|
+
# are registered).
|
5
16
|
def self.inherited(child)
|
6
17
|
registered << child
|
7
18
|
end
|
8
19
|
|
20
|
+
# Get registered plugins by hook (add_pre, add_post, etc.)
|
9
21
|
def self.hooks(name)
|
10
|
-
matches = registered.select { |p| p::Hook == name }
|
22
|
+
matches = registered.select { |p| p::Hook == name }.
|
23
|
+
sort { |a,b| a.to_s <=> b.to_s }
|
11
24
|
|
12
25
|
if block_given?
|
13
26
|
matches.each { |p| yield p }
|
data/lib/murlsh/referrer.rb
CHANGED
@@ -3,6 +3,7 @@ require 'uri'
|
|
3
3
|
|
4
4
|
module Murlsh
|
5
5
|
|
6
|
+
# For parsing query strings from referring search engines.
|
6
7
|
class Referrer
|
7
8
|
|
8
9
|
def initialize(url)
|
@@ -19,6 +20,7 @@ module Murlsh
|
|
19
20
|
end
|
20
21
|
end
|
21
22
|
|
23
|
+
# Get the searched for string from a search engine query string.
|
22
24
|
def search_query(qmap=Qmap)
|
23
25
|
if hostpath and query_string
|
24
26
|
qmap.each_pair do |r,v|
|
@@ -34,6 +36,7 @@ module Murlsh
|
|
34
36
|
nil
|
35
37
|
end
|
36
38
|
|
39
|
+
# Regex host match to name of query string parameter.
|
37
40
|
Qmap = {
|
38
41
|
/^www\.google\.(bs|ca|com|cz|dk|es|fi|nl)(\/m)?\/search$/ => 'q',
|
39
42
|
/^www\.bing\.com\/search$/ => 'q',
|
@@ -2,6 +2,7 @@ require 'active_record/connection_adapters/sqlite3_adapter'
|
|
2
2
|
|
3
3
|
class ActiveRecord::ConnectionAdapters::SQLite3Adapter
|
4
4
|
|
5
|
+
# Add MATCH function for regex matching.
|
5
6
|
def initialize(connection, logger, config)
|
6
7
|
super
|
7
8
|
@connection.create_function('MATCH', 2) do |func,search_in,search_for|
|
data/lib/murlsh/time.rb
CHANGED
data/lib/murlsh/url.rb
CHANGED
@@ -5,36 +5,35 @@ require 'uri'
|
|
5
5
|
|
6
6
|
module Murlsh
|
7
7
|
|
8
|
+
# URL ActiveRecord.
|
8
9
|
class Url < ActiveRecord::Base
|
9
10
|
|
11
|
+
# Get the title of this url.
|
10
12
|
def title
|
11
13
|
read_attribute(:title) || read_attribute(:url) || 'title missing'
|
12
14
|
end
|
13
15
|
|
16
|
+
# Return true if this url has the same author as another url.
|
14
17
|
def same_author?(other)
|
15
18
|
other and other.email and other.name and
|
16
19
|
email and name and email == other.email and name == other.name
|
17
20
|
end
|
18
21
|
|
19
|
-
|
20
|
-
wikipedia.org
|
21
|
-
flickr.com
|
22
|
-
github.com
|
23
|
-
twitter.com
|
24
|
-
vimeo.com
|
25
|
-
youtube.com
|
26
|
-
}
|
27
|
-
|
22
|
+
# Return text showing what domain a link goes to.
|
28
23
|
def hostrec
|
29
24
|
begin
|
30
25
|
domain = URI(url).host[/[a-z\d-]+\.[a-z]{2,}(\.[a-z]{2})?$/].downcase
|
31
26
|
rescue Exception => e
|
32
27
|
domain = nil
|
33
28
|
end
|
34
|
-
|
35
|
-
|
29
|
+
|
30
|
+
domain = Murlsh::Plugin.hooks('hostrec').inject(domain) {
|
31
|
+
|result,plugin| plugin.run(result, url, title) }
|
32
|
+
|
33
|
+
yield domain if domain
|
36
34
|
end
|
37
35
|
|
36
|
+
# Return true if this url is an image.
|
38
37
|
def is_image?
|
39
38
|
%w{image/gif image/jpeg image/png}.include?(content_type)
|
40
39
|
end
|
data/lib/murlsh/url_body.rb
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
module Murlsh
|
2
2
|
|
3
|
+
# Url list page builder.
|
3
4
|
class UrlBody < Builder::XmlMarkup
|
4
5
|
include Murlsh::Markup
|
5
6
|
|
@@ -8,12 +9,14 @@ module Murlsh
|
|
8
9
|
super(:indent => 2)
|
9
10
|
end
|
10
11
|
|
12
|
+
# Fetch urls base on query string parameters.
|
11
13
|
def urls
|
12
14
|
Murlsh::Url.all(:conditions => search_conditions, :order => 'id DESC',
|
13
15
|
:limit => @req.params['n'] ? @req.params['n'].to_i :
|
14
16
|
@config.fetch('num_posts_page', 100))
|
15
17
|
end
|
16
18
|
|
19
|
+
# Search conditions builder for ActiveRecord conditions.
|
17
20
|
def search_conditions
|
18
21
|
if @q
|
19
22
|
search_cols = %w{name title url}
|
@@ -24,6 +27,7 @@ module Murlsh
|
|
24
27
|
end
|
25
28
|
end
|
26
29
|
|
30
|
+
# Url list page body builder.
|
27
31
|
def each
|
28
32
|
instruct! :xml
|
29
33
|
declare! :DOCTYPE, :html, :PUBLIC, '-//W3C//DTD XHTML 1.1//EN',
|
@@ -65,10 +69,12 @@ module Murlsh
|
|
65
69
|
clear
|
66
70
|
powered_by
|
67
71
|
js
|
72
|
+
div('', :id => 'bottom')
|
68
73
|
}
|
69
74
|
}
|
70
75
|
end
|
71
76
|
|
77
|
+
# Head builder.
|
72
78
|
def headd
|
73
79
|
head {
|
74
80
|
titlee
|
@@ -84,20 +90,24 @@ module Murlsh
|
|
84
90
|
}
|
85
91
|
end
|
86
92
|
|
93
|
+
# Title builder.
|
87
94
|
def titlee
|
88
95
|
title(@config.fetch('page_title', '') + (@q ? " /#{@q}" : ''))
|
89
96
|
end
|
90
97
|
|
98
|
+
# Google verification link builder.
|
91
99
|
def google_verify
|
92
100
|
(gv = @config.fetch('google_verify')) and metas('verify-v1' => gv)
|
93
101
|
end
|
94
102
|
|
103
|
+
# Feed icon builder.
|
95
104
|
def feed_icon
|
96
105
|
div(:class => 'icon') {
|
97
106
|
a('feed', :href => @config.fetch('feed_file'), :class => 'feed')
|
98
107
|
}
|
99
108
|
end
|
100
109
|
|
110
|
+
# Search form builder.
|
101
111
|
def search_form
|
102
112
|
form(:action => '', :method => 'get') {
|
103
113
|
value = @q
|
@@ -113,6 +123,7 @@ module Murlsh
|
|
113
123
|
}
|
114
124
|
end
|
115
125
|
|
126
|
+
# Url add form builder.
|
116
127
|
def add_form
|
117
128
|
form(:action => '', :method => 'post') {
|
118
129
|
fieldset(:id => 'add') {
|
@@ -125,15 +136,18 @@ module Murlsh
|
|
125
136
|
}
|
126
137
|
end
|
127
138
|
|
139
|
+
# Url add form input builder.
|
128
140
|
def add_form_input(label, id, size, tipe='text')
|
129
141
|
label(label, :for => id)
|
130
142
|
input(:type => tipe, :id => id, :name => id, :size => size)
|
131
143
|
end
|
132
144
|
|
145
|
+
# Clear div builder.
|
133
146
|
def clear
|
134
147
|
div(:style => 'clear : both')
|
135
148
|
end
|
136
149
|
|
150
|
+
# Powered by builder.
|
137
151
|
def powered_by
|
138
152
|
self.p {
|
139
153
|
text! 'powered by '
|
@@ -141,6 +155,7 @@ module Murlsh
|
|
141
155
|
}
|
142
156
|
end
|
143
157
|
|
158
|
+
# Required javascript builder.
|
144
159
|
def js
|
145
160
|
javascript(%w{
|
146
161
|
jquery-1.3.2.min.js
|
data/lib/murlsh/url_server.rb
CHANGED
@@ -6,6 +6,7 @@ rack
|
|
6
6
|
|
7
7
|
module Murlsh
|
8
8
|
|
9
|
+
# Build responses for HTTP requests.
|
9
10
|
class UrlServer
|
10
11
|
|
11
12
|
def initialize(config, db)
|
@@ -16,6 +17,8 @@ module Murlsh
|
|
16
17
|
Dir['plugins/*.rb'].each { |p| load p }
|
17
18
|
end
|
18
19
|
|
20
|
+
# Respond to a GET request. Return a page of urls based on the query
|
21
|
+
# string parameters.
|
19
22
|
def get(req)
|
20
23
|
resp = Murlsh::XhtmlResponse.new
|
21
24
|
|
@@ -30,6 +33,7 @@ module Murlsh
|
|
30
33
|
resp
|
31
34
|
end
|
32
35
|
|
36
|
+
# Respond to a POST request. Add the new url and return json.
|
33
37
|
def post(req)
|
34
38
|
resp = Rack::Response.new
|
35
39
|
|
@@ -42,16 +46,15 @@ module Murlsh
|
|
42
46
|
ActiveRecord::Base.establish_connection(:adapter => 'sqlite3',
|
43
47
|
:database => @config.fetch('db_file'))
|
44
48
|
|
45
|
-
content_type = Murlsh.get_content_type(url)
|
46
49
|
mu = Murlsh::Url.new do |u|
|
47
50
|
u.time = Time.now.gmtime
|
48
51
|
u.url = url
|
49
52
|
u.email = user[:email]
|
50
53
|
u.name = user[:name]
|
51
|
-
u.title = Murlsh.get_title(url, :content_type => content_type)
|
52
|
-
u.content_type = content_type
|
53
54
|
end
|
54
55
|
|
56
|
+
Murlsh::Plugin.hooks('add_pre') { |p| p.run(mu, @config) }
|
57
|
+
|
55
58
|
mu.save
|
56
59
|
|
57
60
|
Murlsh::Plugin.hooks('add_post') { |p| p.run(@config) }
|
@@ -1,9 +1,10 @@
|
|
1
1
|
module Murlsh
|
2
2
|
|
3
|
+
# Set the content type correctly based on accept header and user agent.
|
3
4
|
class XhtmlResponse < Rack::Response
|
4
5
|
|
5
|
-
#
|
6
|
-
# claims to accept it, for anything else or IE use text/html
|
6
|
+
# Set the content type to application/xhtml+xml for anything that
|
7
|
+
# claims to accept it, for anything else or IE use text/html.
|
7
8
|
def set_content_type(http_accept, http_user_agent)
|
8
9
|
self['Content-Type'] = if http_accept and
|
9
10
|
http_accept[/((\*|application)\/\*|application\/xhtml\+xml)/i] and
|
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.3.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{2009-
|
12
|
+
s.date = %q{2009-11-05}
|
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}
|
@@ -43,6 +43,9 @@ Gem::Specification.new do |s|
|
|
43
43
|
"lib/murlsh/url_server.rb",
|
44
44
|
"lib/murlsh/xhtml_response.rb",
|
45
45
|
"murlsh.gemspec",
|
46
|
+
"plugins/hostrec_redundant.rb",
|
47
|
+
"plugins/hostrec_skip.rb",
|
48
|
+
"plugins/lookup_content_type_title.rb",
|
46
49
|
"plugins/update_feed.rb",
|
47
50
|
"public/css/jquery.jgrowl.css",
|
48
51
|
"public/css/phone.css",
|
@@ -0,0 +1,14 @@
|
|
1
|
+
module Murlsh
|
2
|
+
|
3
|
+
# skip showing host record if domain is contained in title
|
4
|
+
class HostrecRedundant < Plugin
|
5
|
+
|
6
|
+
Hook = 'hostrec'
|
7
|
+
|
8
|
+
def self.run(domain, url, title)
|
9
|
+
domain unless (title and domain and title.downcase.index(domain))
|
10
|
+
end
|
11
|
+
|
12
|
+
end
|
13
|
+
|
14
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module Murlsh
|
2
|
+
|
3
|
+
# skip showing host record for some domains
|
4
|
+
class HostrecSkip < Plugin
|
5
|
+
|
6
|
+
Hook = 'hostrec'
|
7
|
+
|
8
|
+
def self.run(domain, url, title)
|
9
|
+
domain unless Skips.include?(domain)
|
10
|
+
end
|
11
|
+
|
12
|
+
Skips = %w{
|
13
|
+
wikipedia.org
|
14
|
+
flickr.com
|
15
|
+
github.com
|
16
|
+
twitter.com
|
17
|
+
vimeo.com
|
18
|
+
youtube.com
|
19
|
+
}
|
20
|
+
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'murlsh'
|
2
|
+
|
3
|
+
module Murlsh
|
4
|
+
|
5
|
+
# try to fetch the content type and title of a url
|
6
|
+
class LookupContentTypeTitle < Plugin
|
7
|
+
|
8
|
+
Hook = 'add_pre'
|
9
|
+
|
10
|
+
def self.run(url, config)
|
11
|
+
url.content_type = Murlsh.get_content_type(url.url)
|
12
|
+
url.title = Murlsh.get_title(url.url, :content_type => url.content_type)
|
13
|
+
end
|
14
|
+
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
data/public/css/phone.css
CHANGED
@@ -1,3 +1,7 @@
|
|
1
|
+
a.feed {
|
2
|
+
display : none;
|
3
|
+
}
|
4
|
+
|
1
5
|
body {
|
2
6
|
margin : 0;
|
3
7
|
padding : 0;
|
@@ -9,6 +13,14 @@ body {
|
|
9
13
|
width : 290px;
|
10
14
|
}
|
11
15
|
|
16
|
+
#urls li {
|
17
|
+
overflow : hidden;
|
18
|
+
}
|
19
|
+
|
12
20
|
input#q {
|
13
21
|
width : 130px;
|
14
22
|
}
|
23
|
+
|
24
|
+
input#url {
|
25
|
+
width : 160px;
|
26
|
+
}
|
data/public/js/js.js
CHANGED
@@ -205,7 +205,12 @@ Murlsh.orientation_changed = function() {
|
|
205
205
|
window.onorientationchange = Murlsh.orientation_changed;
|
206
206
|
|
207
207
|
$(document).ready(function() {
|
208
|
-
Murlsh.
|
208
|
+
if (Murlsh.is_iphone()) {
|
209
|
+
Murlsh.orientation_changed();
|
210
|
+
$('#urls li:first').prepend($('<a />').attr('href', '#bottom').text(
|
211
|
+
'bottom'));
|
212
|
+
$('#urls li:last').append($('<a />').attr('href', '#urls').text('top'));
|
213
|
+
}
|
209
214
|
$('a').map(Murlsh.add_extra);
|
210
215
|
$('#urls li:even').addClass('even');
|
211
216
|
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: murlsh
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Matthew M. Boedicker
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2009-
|
12
|
+
date: 2009-11-05 00:00:00 -05:00
|
13
13
|
default_executable: murlsh
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
@@ -116,6 +116,9 @@ files:
|
|
116
116
|
- lib/murlsh/url_server.rb
|
117
117
|
- lib/murlsh/xhtml_response.rb
|
118
118
|
- murlsh.gemspec
|
119
|
+
- plugins/hostrec_redundant.rb
|
120
|
+
- plugins/hostrec_skip.rb
|
121
|
+
- plugins/lookup_content_type_title.rb
|
119
122
|
- plugins/update_feed.rb
|
120
123
|
- public/css/jquery.jgrowl.css
|
121
124
|
- public/css/phone.css
|