initial commit
This commit is contained in:
commit
064003fa20
19 changed files with 573 additions and 0 deletions
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
.DS_Store
|
30
config.ru
Executable file
30
config.ru
Executable file
|
@ -0,0 +1,30 @@
|
|||
#$LOAD_PATH.unshift ('/home/eschaton/.gem/ruby/1.8/gems/rack-0.9.1/lib')
|
||||
#require ('/home/eschaton/.gem/ruby/1.8/gems/rack-0.9.1/lib/rack.rb')
|
||||
#require ('/home/eschaton/.gem/ruby/1.8/gems/sinatra-0.9.1.1/lib/sinatra.rb')
|
||||
|
||||
#$LOAD_PATH.unshift '/Library/Ruby/Gems/1.8/gems/sqlite3-ruby-1.2.4/lib'
|
||||
#require ('/Library/Ruby/Gems/1.8/gems/sqlite3-ruby-1.2.4/sqlite3.rb')
|
||||
#$LOAD_PATH.unshift '/Library/Ruby/Gems/1.8/gems/sequel-3.0.0/lib'
|
||||
#require ('/home/eschaton/.gems/gems/sequel-2.12.0/lib/sequel.rb')
|
||||
|
||||
require 'rubygems'
|
||||
require 'sequel'
|
||||
require 'rack'
|
||||
require 'sinatra'
|
||||
|
||||
#require File.expand_path('~/.gem/ruby/1.8/gems/rack*')
|
||||
#require File.expand_path('~/.gem/ruby/1.8/gems/sinatra*')
|
||||
|
||||
Sinatra::Application.default_options.merge!(
|
||||
:views => File.join(File.dirname(__FILE__), 'views'),
|
||||
:run => false,
|
||||
:env => ENV['RACK_ENV'],
|
||||
:raise_errors => true
|
||||
)
|
||||
|
||||
log = File.new("sinatra.log", "a")
|
||||
$stdout.reopen(log)
|
||||
$stderr.reopen(log)
|
||||
|
||||
require 'main'
|
||||
run Sinatra::Application
|
12
lib/log.rb
Normal file
12
lib/log.rb
Normal file
|
@ -0,0 +1,12 @@
|
|||
class Log < Sequel::Model
|
||||
unless table_exists?
|
||||
set_schema do
|
||||
primary_key :id
|
||||
Integer :shorten_url_id
|
||||
String :ip
|
||||
String :coordinates
|
||||
Time :time
|
||||
end
|
||||
create_table
|
||||
end
|
||||
end
|
74
lib/shorteners/base62.rb
Executable file
74
lib/shorteners/base62.rb
Executable file
|
@ -0,0 +1,74 @@
|
|||
class Base62
|
||||
@@ranges = [
|
||||
('0'..'9'),
|
||||
('a'..'z'),
|
||||
('A'..'Z')
|
||||
]
|
||||
@@base = nil
|
||||
@@offsets = nil
|
||||
|
||||
def self.to_s(number)
|
||||
if @@base.nil?
|
||||
@@base = self.calculate_base
|
||||
end
|
||||
string = ""
|
||||
while number > (@@base - 1)
|
||||
place = number % @@base
|
||||
string = self.lookup(place) + string
|
||||
number = number / @@base
|
||||
end
|
||||
|
||||
self.lookup(number) + string
|
||||
end
|
||||
|
||||
def self.to_i(string)
|
||||
if @@base.nil?
|
||||
@@base = self.calculate_base
|
||||
end
|
||||
number = 0
|
||||
i = string.length - 1
|
||||
string.each_byte do |c|
|
||||
c = c.chr
|
||||
@@ranges.each_index do |j|
|
||||
range = @@ranges[j]
|
||||
if range.member? c
|
||||
number += (c[0] - range.to_a.first[0] + @@offsets[j]) * (@@base ** i)
|
||||
break
|
||||
end
|
||||
end
|
||||
i -= 1
|
||||
end
|
||||
number
|
||||
end
|
||||
|
||||
def self.lookup(place)
|
||||
string = ""
|
||||
if @@base.nil?
|
||||
@@base = self.calculate_base
|
||||
end
|
||||
(0..(@@ranges.length-1)).each do |i|
|
||||
range_array = @@ranges[i].to_a
|
||||
start = 0 + @@offsets[i]
|
||||
stop = range_array.length - 1 + @@offsets[i]
|
||||
if (start..stop).member? place
|
||||
string = range_array[place - @@offsets[i]]
|
||||
break
|
||||
end
|
||||
end
|
||||
string
|
||||
end
|
||||
|
||||
def self.next_integer(integer)
|
||||
integer + 1
|
||||
end
|
||||
|
||||
def self.calculate_base
|
||||
i = 0
|
||||
@@offsets = []
|
||||
@@ranges.each do |range|
|
||||
@@offsets << i
|
||||
i += range.to_a.length
|
||||
end
|
||||
i
|
||||
end
|
||||
end
|
97
lib/shorteners/base71.rb
Normal file
97
lib/shorteners/base71.rb
Normal file
|
@ -0,0 +1,97 @@
|
|||
class Base71
|
||||
@@ranges = [
|
||||
('0'..'9'),
|
||||
('a'..'z'),
|
||||
('A'..'Z'),
|
||||
('$'..'$'),
|
||||
('-'..'.'),
|
||||
('_'..'_'),
|
||||
('('..')'),
|
||||
('*'..'+'),
|
||||
('!'..'!')
|
||||
]
|
||||
@@base = nil
|
||||
@@offsets = nil
|
||||
|
||||
def self.to_s(number)
|
||||
if @@base.nil?
|
||||
@@base = self.calculate_base
|
||||
end
|
||||
string = ""
|
||||
while number > (@@base - 1)
|
||||
place = number % @@base
|
||||
string = self.lookup(place) + string
|
||||
number = number / @@base
|
||||
end
|
||||
|
||||
self.lookup(number) + string
|
||||
end
|
||||
|
||||
def self.to_i(string)
|
||||
if @@base.nil?
|
||||
@@base = self.calculate_base
|
||||
end
|
||||
number = 0
|
||||
i = string.length - 1
|
||||
string.each_byte do |c|
|
||||
c = c.chr
|
||||
@@ranges.each_index do |j|
|
||||
range = @@ranges[j]
|
||||
if range.member? c
|
||||
number += (c[0] - range.to_a.first[0] + @@offsets[j]) * (@@base ** i)
|
||||
break
|
||||
end
|
||||
end
|
||||
#if ("0".."9").member? c
|
||||
# number += c.to_i * (@@base ** i)
|
||||
#elsif ("a".."z").member? c
|
||||
# first = "a"
|
||||
# number += (c[0] - first[0] + 10) * (@@base ** i)
|
||||
#else
|
||||
# first = "A"
|
||||
# number += (c[0] - first[0] + 36) * (@@base ** i)
|
||||
#end
|
||||
i -= 1
|
||||
end
|
||||
number
|
||||
end
|
||||
|
||||
def self.lookup(place)
|
||||
string = ""
|
||||
if @@base.nil?
|
||||
@@base = self.calculate_base
|
||||
end
|
||||
(0..(@@ranges.length-1)).each do |i|
|
||||
range_array = @@ranges[i].to_a
|
||||
start = 0 + @@offsets[i]
|
||||
stop = range_array.length - 1 + @@offsets[i]
|
||||
if (start..stop).member? place
|
||||
string = range_array[place - @@offsets[i]]
|
||||
break
|
||||
end
|
||||
end
|
||||
#if (0..9).member? place
|
||||
# string = "#{place}"
|
||||
#elsif (10..35).member? place
|
||||
# string = ("a".."z").to_a[place - 10]
|
||||
#else
|
||||
# string = ("A".."Z").to_a[place - 36]
|
||||
#end
|
||||
|
||||
string
|
||||
end
|
||||
|
||||
def self.next_integer(integer)
|
||||
integer + 1
|
||||
end
|
||||
|
||||
def self.calculate_base
|
||||
i = 0
|
||||
@@offsets = []
|
||||
@@ranges.each do |range|
|
||||
@@offsets << i
|
||||
i += range.to_a.length
|
||||
end
|
||||
i
|
||||
end
|
||||
end
|
34
lib/shortenurl.rb
Executable file
34
lib/shortenurl.rb
Executable file
|
@ -0,0 +1,34 @@
|
|||
class ShortenUrl < Sequel::Model
|
||||
unless table_exists?
|
||||
set_schema do
|
||||
primary_key :id
|
||||
String :key
|
||||
String :url
|
||||
Time :time
|
||||
end
|
||||
create_table
|
||||
end
|
||||
|
||||
def short_url
|
||||
"#{Shorten.base_url}#{Shorten.shortener.to_s(id)}"
|
||||
end
|
||||
|
||||
def self.create_url(link)
|
||||
uri = URI::parse(link)
|
||||
raise "Invalid URL" unless uri.kind_of? URI::HTTP or uri.kind_of? URI::HTTPS
|
||||
|
||||
url = self.filter(:url => link).first
|
||||
if !url
|
||||
max_id = self.order(:id.desc).first
|
||||
if !max_id
|
||||
max_id = 0
|
||||
else
|
||||
max_id = max_id.id
|
||||
end
|
||||
url = self.new(:url => link)
|
||||
url.save
|
||||
end
|
||||
|
||||
url
|
||||
end
|
||||
end
|
117
main.rb
Executable file
117
main.rb
Executable file
|
@ -0,0 +1,117 @@
|
|||
require 'rubygems'
|
||||
require 'sinatra'
|
||||
require 'sequel'
|
||||
require 'uri'
|
||||
|
||||
configure do
|
||||
Sequel::Model.plugin(:schema)
|
||||
|
||||
Sequel.connect(ENV['DATABASE_URL'] || 'sqlite://shorten.db')
|
||||
|
||||
require 'ostruct'
|
||||
Shorten = OpenStruct.new(
|
||||
:base_url => "http://localhost:4567/",
|
||||
:service_name => "Lavish URL Shortener",
|
||||
:button_text => "Short ♥!"
|
||||
)
|
||||
|
||||
$LOAD_PATH.unshift(File.dirname(__FILE__) + '/lib')
|
||||
|
||||
# Change these two references from "62" to "71" if you want to include
|
||||
# URL-legal, non-alphanumeric characters in your URLs.
|
||||
require "shorteners/base62"
|
||||
Shorten.shortener = Base62
|
||||
end
|
||||
|
||||
$LOAD_PATH.unshift(File.dirname(__FILE__) + '/lib')
|
||||
|
||||
require 'shortenurl'
|
||||
|
||||
helpers do
|
||||
def show_information
|
||||
erb :information, :layout => false
|
||||
end
|
||||
|
||||
def validate_link(link)
|
||||
halt 401, 'We do not accept local URLs to be shortened' unless valid_url? link
|
||||
end
|
||||
|
||||
# Determine if a URL is valid. We run it through
|
||||
def valid_url?(url)
|
||||
if url.include? "%3A"
|
||||
url = URI.unescape(url)
|
||||
end
|
||||
|
||||
retval = true
|
||||
|
||||
begin
|
||||
uri = URI.parse(URI.escape(url))
|
||||
if uri.class != URI::HTTP
|
||||
retval = false
|
||||
end
|
||||
|
||||
host = (URI.split(url))[2]
|
||||
if host =~ /^(localhost|192\.168\.\d{1,3}\.\d{1,3}|127\.0\.0\.1|172\.((1[6-9])|(2[0-9])|(3[0-1])).\d{1,3}\.\d{1,3}|10.\d{1,3}\.\d{1,3}.\d{1,3})/
|
||||
retval = false
|
||||
end
|
||||
rescue URI::InvalidURIError
|
||||
retval = false
|
||||
end
|
||||
|
||||
retval
|
||||
end
|
||||
end
|
||||
|
||||
get '/' do
|
||||
@information = show_information
|
||||
erb :index, :locals => { :type => "main" }
|
||||
end
|
||||
|
||||
get %r(/(api-){0,1}create/(.*)) do |api, link|
|
||||
#link = params[:link]
|
||||
validate_link link
|
||||
|
||||
url = ShortenUrl.create_url(link)
|
||||
|
||||
if api == "api-"
|
||||
"#{url.short_url}"
|
||||
else
|
||||
erb :finished, :locals => { :url => url, :type => "finished" }
|
||||
end
|
||||
end
|
||||
|
||||
get %r(/(api-){0,1}create) do |api|
|
||||
if request['url']
|
||||
validate_link request['url']
|
||||
url = ShortenUrl.create_url(request['url'])
|
||||
if api == "api-"
|
||||
"#{url.short_url}"
|
||||
else
|
||||
erb :finished, :locals => { :url => url, :type => "finished" }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
post '/' do
|
||||
validate_link params[:url]
|
||||
|
||||
url = ShortenUrl.create_url(params[:url])
|
||||
|
||||
#"#{url.short_url}"
|
||||
erb :finished, :locals => { :url => url, :type => "finished" }
|
||||
end
|
||||
|
||||
get '/:short' do
|
||||
url = ShortenUrl.filter(:id => Shorten.shortener.to_i(params[:short])).first
|
||||
|
||||
require 'log'
|
||||
|
||||
log = Log.new
|
||||
log.ip = request.ip
|
||||
log.time = Time.now
|
||||
log.shorten_url_id = url.id
|
||||
log.save
|
||||
|
||||
halt 404, "Page not found" unless url
|
||||
redirect url.url
|
||||
end
|
BIN
public/images/finished_background.png
Executable file
BIN
public/images/finished_background.png
Executable file
Binary file not shown.
After Width: | Height: | Size: 4.3 KiB |
BIN
public/images/main_background.png
Executable file
BIN
public/images/main_background.png
Executable file
Binary file not shown.
After Width: | Height: | Size: 4.3 KiB |
67
public/main.css
Executable file
67
public/main.css
Executable file
|
@ -0,0 +1,67 @@
|
|||
a {
|
||||
text-decoration: none;
|
||||
color: #5671a7;
|
||||
}
|
||||
|
||||
a:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
a:active {
|
||||
color: #ff9400;
|
||||
}
|
||||
|
||||
#content {
|
||||
width: 689px;
|
||||
height: 295px;
|
||||
margin: 1.5em auto;
|
||||
padding: 83px 0px 0px 22px;
|
||||
}
|
||||
|
||||
#content p {
|
||||
margin-top: 0px;
|
||||
}
|
||||
|
||||
#url {
|
||||
font-size: 1.8em;
|
||||
font-weight: bold;
|
||||
font-family: "Verdana", sans-serif;
|
||||
border: 7px solid black;
|
||||
padding: 7px;
|
||||
}
|
||||
|
||||
#content input[type="submit"] {
|
||||
font-size: 1.8em;
|
||||
font-family: "Verdana", sans-serif;
|
||||
font-weight: bold;
|
||||
border: 7px solid black;
|
||||
padding: 7px;
|
||||
}
|
||||
|
||||
#information {
|
||||
width: 490px;
|
||||
padding-top: 0.5em;
|
||||
padding-right: 199px;
|
||||
margin: 0 auto;
|
||||
margin-top: -197px;
|
||||
|
||||
font-family: "Verdana", sans-serif;
|
||||
}
|
||||
|
||||
#information h2 {
|
||||
font-size: 1.2em;
|
||||
}
|
||||
|
||||
#information p {
|
||||
font-size: 0.90em;
|
||||
}
|
||||
.main {
|
||||
background: url('images/main_background.png') no-repeat;
|
||||
}
|
||||
|
||||
.finished {
|
||||
background: url('images/finished_background.png') no-repeat;
|
||||
font-size: 1.8em;
|
||||
font-family: "Verdana", sans-serif;
|
||||
font-weight: bold;
|
||||
}
|
BIN
public/shorten.zip
Normal file
BIN
public/shorten.zip
Normal file
Binary file not shown.
18
public/ubiquity/index.html
Normal file
18
public/ubiquity/index.html
Normal file
|
@ -0,0 +1,18 @@
|
|||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
|
||||
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head>
|
||||
<meta http-equiv="Content-type" content="text/html; charset=utf-8">
|
||||
<title>Andrew's URL Shortener</title>
|
||||
<link rel="stylesheet" type="text/css" href="/main.css" />
|
||||
<link rel="commands" href="shorten.js" name="Shorten w/ u.pilsch.com" />
|
||||
</head>
|
||||
<body>
|
||||
<div id="content" class="finished">
|
||||
<p>Install Ubiquity Command!</p>
|
||||
</div>
|
||||
<div id="information">
|
||||
<p><a href="/">Back to Main Page</a></p>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
82
public/ubiquity/shorten.js
Normal file
82
public/ubiquity/shorten.js
Normal file
|
@ -0,0 +1,82 @@
|
|||
/*var isParser2 = function(){
|
||||
var prefs = Components.classes["@mozilla.org/preferences-service;1
|
||||
"].getService(Components.interfaces.nsIPrefService);
|
||||
var branch = prefs.getBranch("extensions.ubiquity.");
|
||||
return (branch.getPrefType("parserVersion") != 0) ?
|
||||
branch.getIntPref("parserVersion") == 2 : false;
|
||||
|
||||
}
|
||||
|
||||
if (isParser2()) {*/
|
||||
/* Parser 2 version of the CmdUtils.CreateCommand calls here */
|
||||
CmdUtils.CreateCommand({
|
||||
names: ['shorten'],
|
||||
icon: "http://u.pilsch.com/favicon.png",
|
||||
homepage: "http://u.pilsch.com",
|
||||
author: { name: "Andrew Pilsch (based on code by Arun Shivaram)", email: "andrew@pilsch.com"},
|
||||
license: "GPL",
|
||||
description: "Shortens the selected URL using u.pilsch.com",
|
||||
help: "shorten <long url>",
|
||||
arguments: [ {role: 'object', nountype: noun_arb_text, label: 'longurl'} ],
|
||||
preview: function( pblock, args ) {
|
||||
pblock.innerHTML = _("Replaces the selected URL with a u.pilsch.com URL");
|
||||
this._shorturl(pblock,args.object,"preview");
|
||||
},
|
||||
execute: function(object, args) {
|
||||
this._shorturl("",args.object,"execute");
|
||||
},
|
||||
|
||||
_shorturl: function( pblock,lurl,call ) {
|
||||
var baseUrl = "http://u.pilsch.com/api-create?url=" + lurl.text;
|
||||
//var params = {longurl: lurl.text};
|
||||
var params = {}
|
||||
jQuery.get( baseUrl, params,function(sUrl){
|
||||
if (call=="preview"){
|
||||
pblock.innerHTML = _("Replaces the selected URL with "+sUrl);
|
||||
}
|
||||
if (call=="execute"){
|
||||
CmdUtils.setSelection(sUrl);
|
||||
CmdUtils.copyToClipboard(sUrl);
|
||||
}
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
});
|
||||
/* ... */
|
||||
/*} else {
|
||||
CmdUtils.CreateCommand({
|
||||
name: "shorten",
|
||||
icon: "http://is.gd/favicon.ico",
|
||||
homepage: "http://u.pilsch.com",
|
||||
author: { name: "Andrew Pilsch (based on code by Arun Shivaram)", email: "andrew@pilsch.com"},
|
||||
license: "GPL",
|
||||
description: "Shortens the selected URL using u.pilsch.com",
|
||||
help: "shorten <long url>",
|
||||
takes: {"longurl": noun_arb_text},
|
||||
preview: function( pblock, lurl ) {
|
||||
pblock.innerHTML = "Replaces the selected URL with a u.pilsch.com URL";
|
||||
this._shorturl(pblock,lurl,"preview");
|
||||
},
|
||||
execute: function(lurl) {
|
||||
this._shorturl("",lurl,"execute");
|
||||
},
|
||||
|
||||
_shorturl: function( pblock,lurl,call){
|
||||
var baseUrl = "http://u.pilsch.com/api-create/" + lurl.text;
|
||||
//var params = {longurl: lurl.text};
|
||||
var params = {}
|
||||
jQuery.get( baseUrl, params,function(sUrl){
|
||||
if (call=="preview"){
|
||||
pblock.innerHTML = "Replaces the selected URL with "+sUrl;
|
||||
}
|
||||
if (call=="execute"){
|
||||
CmdUtils.setSelection(sUrl);
|
||||
CmdUtils.copyToClipboard(sUrl);
|
||||
}
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
});
|
||||
}*/
|
BIN
shorten.db
Normal file
BIN
shorten.db
Normal file
Binary file not shown.
11
sinatra.log
Normal file
11
sinatra.log
Normal file
|
@ -0,0 +1,11 @@
|
|||
./main.rb:112: warning: Object#id will be deprecated; use Object#object_id
|
||||
::1 - - [12/Jul/2009 13:10:27] "GET /favicon.ico " 404 14 0.0112
|
||||
./main.rb:112: warning: Object#id will be deprecated; use Object#object_id
|
||||
::1 - - [12/Jul/2009 13:10:31] "GET /favicon.ico " 404 14 0.0055
|
||||
./main.rb:112: warning: Object#id will be deprecated; use Object#object_id
|
||||
::1 - - [12/Jul/2009 13:10:31] "GET /favicon.ico " 404 14 0.0073
|
||||
::1 - - [12/Jul/2009 13:10:32] "GET /~test/mysql " 404 420 0.0014
|
||||
::1 - - [12/Jul/2009 13:10:32] "GET /__sinatra__/404.png " 200 23305 0.0029
|
||||
::1 - - [12/Jul/2009 13:10:46] "GET /~test/mysql " 404 420 0.0023
|
||||
::1 - - [12/Jul/2009 13:10:46] "GET /__sinatra__/404.png " 304 - 0.0020
|
||||
::1 - - [12/Jul/2009 13:10:48] "GET /~test/mysql " 404 420 0.0020
|
1
views/finished.erb
Executable file
1
views/finished.erb
Executable file
|
@ -0,0 +1 @@
|
|||
<p><a href="<%= url.short_url %>"><%= url.short_url %></a></p>
|
4
views/index.erb
Executable file
4
views/index.erb
Executable file
|
@ -0,0 +1,4 @@
|
|||
<form method="POST" action="/">
|
||||
<input type="text" name="url" id="url" />
|
||||
<input type="submit" value="<%= Shorten.button_text %>" id="create_url" />
|
||||
</form>
|
10
views/information.erb
Executable file
10
views/information.erb
Executable file
|
@ -0,0 +1,10 @@
|
|||
<div id="information">
|
||||
<h2>use this site from your browser:</h2>
|
||||
<p>
|
||||
<a href="javascript:void(location.href='<%= Shorten.base_url %>create/' + encodeURIComponent(location.href));"><%= Shorten.button_text %></a> - Drag this link to your bookmark bar or right click and select "Bookmark This Location." When you want to shorten a URL, just click on the bookmark! Hooray!
|
||||
</p>
|
||||
<h2>try our ubiquity command:</h2>
|
||||
<p>
|
||||
<a href="/ubiquity">Click here to go to the install page.</a> For more information about Ubiquity, <a href="http://labs.mozilla.com/projects/ubiquity/">click here</a>.
|
||||
</p>
|
||||
</div>
|
15
views/layout.erb
Executable file
15
views/layout.erb
Executable file
|
@ -0,0 +1,15 @@
|
|||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
|
||||
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head>
|
||||
<meta http-equiv="Content-type" content="text/html; charset=utf-8">
|
||||
<title><%= Shorten.service_name %></title>
|
||||
<link rel="stylesheet" type="text/css" href="/main.css" />
|
||||
</head>
|
||||
<body>
|
||||
<div id="content" class="<%= type %>">
|
||||
<%= yield %>
|
||||
</div>
|
||||
<%= @information %>
|
||||
</body>
|
||||
</html>
|
Loading…
Reference in a new issue