murlsh 0.2.4 → 0.3.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 +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
|