subdb 0.1.5 → 0.1.6
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 +17 -5
- data/lib/subdb.rb +1 -133
- data/lib/subdb/client_utils.rb +77 -75
- data/lib/subdb/ui/swing.rb +139 -88
- data/lib/subdb/upload_cache.rb +4 -0
- data/lib/subdb/version.rb +2 -2
- data/lib/subdb/video.rb +162 -0
- metadata +5 -4
data/README.textile
CHANGED
@@ -1,13 +1,13 @@
|
|
1
|
-
h1. Ruby SubDB
|
1
|
+
h1. Ruby SubDB "!http://travis-ci.org/wilkerlucio/subdb.png!":http://travis-ci.org/wilkerlucio/subdb
|
2
2
|
|
3
|
-
This project aims to provide a simple API for accessing "
|
3
|
+
This project aims to provide a simple API for accessing "SubDB":http://thesubdb.com/
|
4
4
|
|
5
5
|
h2. GUI client
|
6
6
|
|
7
7
|
We are proud to annouce now we have a GUI client to make it easy for anyone to use SubDB, you can download client with following links:
|
8
8
|
|
9
|
-
"Mac Version":https://github.com/downloads/wilkerlucio/subdb/subdb-0.1.
|
10
|
-
"Windows / Linux version (requires Java)":https://github.com/downloads/wilkerlucio/subdb/subdb-0.1.
|
9
|
+
"Mac Version":https://github.com/downloads/wilkerlucio/subdb/subdb-0.1.6.dmg
|
10
|
+
"Windows / Linux version (requires Java)":https://github.com/downloads/wilkerlucio/subdb/subdb-0.1.6.jar
|
11
11
|
|
12
12
|
Just download, open, and drag your files on program window. It will work in same way as Command Line tool.
|
13
13
|
|
@@ -29,9 +29,21 @@ If you plan to use on your project, SubDB gem also provides a simple interface f
|
|
29
29
|
|
30
30
|
bc.. require 'subdb'
|
31
31
|
|
32
|
-
file = Subdb.new("path_to_your_movie.mp4")
|
32
|
+
file = Subdb::Video.new("path_to_your_movie.mp4")
|
33
33
|
file.search # will retrieve a string with available languages (ex: "pt,en") or nil if don't have anyone
|
34
34
|
file.download(["en", "pt"]) # will download the subtitle for given language, it tries in order of array
|
35
35
|
file.upload("path_to_subtitle.str") # will upload a subtitle for this movie
|
36
36
|
|
37
37
|
p. It's only this :)
|
38
|
+
|
39
|
+
h2. Development
|
40
|
+
|
41
|
+
If you are looking to help with project code, please checkout the @develop@ branch, the edge stuff is there.
|
42
|
+
|
43
|
+
h2. Changelog
|
44
|
+
|
45
|
+
h3. 0.1.6
|
46
|
+
|
47
|
+
* Main class @Subdb@ was moved to @Subdb::Video@
|
48
|
+
* Ability to drop files direct on Dock Icon (Mac Only)
|
49
|
+
* Display a list of downloaded subtitles at end of sync process
|
data/lib/subdb.rb
CHANGED
@@ -19,139 +19,7 @@
|
|
19
19
|
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
20
|
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
21
21
|
|
22
|
-
require 'net/http'
|
23
|
-
require 'uri'
|
24
|
-
require 'cgi'
|
25
|
-
require 'digest/md5'
|
26
|
-
require 'net/http/post/multipart'
|
27
|
-
|
28
22
|
require 'subdb/version'
|
23
|
+
require 'subdb/video'
|
29
24
|
require 'subdb/client_utils'
|
30
25
|
require 'subdb/upload_cache'
|
31
|
-
|
32
|
-
class Subdb
|
33
|
-
API = "http://api.thesubdb.com/"
|
34
|
-
SANDBOX = "http://sandbox.thesubdb.com/"
|
35
|
-
|
36
|
-
class << self
|
37
|
-
attr_accessor :test_mode
|
38
|
-
|
39
|
-
def api_url
|
40
|
-
test_mode ? SANDBOX : API
|
41
|
-
end
|
42
|
-
end
|
43
|
-
|
44
|
-
self.test_mode = false
|
45
|
-
|
46
|
-
attr_reader :hash, :path
|
47
|
-
|
48
|
-
def initialize(path)
|
49
|
-
fail "#{path} is not a file" unless File.exists?(path)
|
50
|
-
|
51
|
-
@path = path
|
52
|
-
@hash = build_hash
|
53
|
-
end
|
54
|
-
|
55
|
-
def search
|
56
|
-
res = request("search")
|
57
|
-
check_get(res)
|
58
|
-
end
|
59
|
-
|
60
|
-
def download(languages = ["en"])
|
61
|
-
res = request("download", :language => languages.join(","))
|
62
|
-
check_get(res)
|
63
|
-
end
|
64
|
-
|
65
|
-
def upload(path)
|
66
|
-
fail "Invalid subtitle file #{path}" unless File.exists?(path)
|
67
|
-
|
68
|
-
params = {:action => "upload", :hash => @hash}
|
69
|
-
|
70
|
-
url = URI.parse(self.class.api_url)
|
71
|
-
|
72
|
-
begin
|
73
|
-
file = File.open(path, "rb")
|
74
|
-
|
75
|
-
io = UploadIO.new(file, "application/octet-stream", File.basename(path))
|
76
|
-
|
77
|
-
req = Net::HTTP::Post::Multipart.new(url.path + stringify_params(params), {"file" => io, "hash" => @hash})
|
78
|
-
req["User-Agent"] = user_agent
|
79
|
-
|
80
|
-
res = Net::HTTP.start(url.host, url.port) do |http|
|
81
|
-
http.request(req)
|
82
|
-
end
|
83
|
-
|
84
|
-
case res.code.to_s
|
85
|
-
when "201" then true
|
86
|
-
when "403" then false
|
87
|
-
when "400" then fail "Malformed request"
|
88
|
-
when "415" then fail "Invalid subtitle type"
|
89
|
-
end
|
90
|
-
ensure
|
91
|
-
file.close
|
92
|
-
end
|
93
|
-
end
|
94
|
-
|
95
|
-
def pathbase
|
96
|
-
File.basename(path)
|
97
|
-
end
|
98
|
-
|
99
|
-
protected
|
100
|
-
|
101
|
-
def build_hash
|
102
|
-
chunk_size = 64 * 1024
|
103
|
-
|
104
|
-
size = File.size(@path)
|
105
|
-
file = File.open(@path, "rb")
|
106
|
-
data = file.read(chunk_size)
|
107
|
-
file.seek(size - chunk_size)
|
108
|
-
data += file.read(chunk_size)
|
109
|
-
|
110
|
-
file.close
|
111
|
-
|
112
|
-
Digest::MD5.hexdigest(data)
|
113
|
-
end
|
114
|
-
|
115
|
-
def user_agent
|
116
|
-
"SubDB/1.0 (RubySubDB/#{VERSION}; http://github.com/wilkerlucio/subdb)"
|
117
|
-
end
|
118
|
-
|
119
|
-
def request(action, params = {}, body = nil)
|
120
|
-
params = {:action => action, :hash => @hash}.merge(params)
|
121
|
-
|
122
|
-
url = URI.parse(self.class.api_url)
|
123
|
-
|
124
|
-
req = Net::HTTP::Get.new(url.path + stringify_params(params))
|
125
|
-
req["User-Agent"] = user_agent
|
126
|
-
req.set_form_data(body) if body
|
127
|
-
|
128
|
-
Net::HTTP.start(url.host, url.port) do |http|
|
129
|
-
http.request(req)
|
130
|
-
end
|
131
|
-
end
|
132
|
-
|
133
|
-
def check_get(res)
|
134
|
-
case res.code.to_s
|
135
|
-
when "200" then res.body
|
136
|
-
when "400" then fail "Malformed request"
|
137
|
-
when "404" then nil
|
138
|
-
else
|
139
|
-
fail "Unexpected response code - #{res.code}"
|
140
|
-
end
|
141
|
-
end
|
142
|
-
|
143
|
-
def stringify_params(params)
|
144
|
-
params_string = []
|
145
|
-
|
146
|
-
params.each do |key, value|
|
147
|
-
next unless value
|
148
|
-
|
149
|
-
key = CGI.escape(key.to_s)
|
150
|
-
value = CGI.escape(value.to_s)
|
151
|
-
|
152
|
-
params_string << "#{key}=#{value}"
|
153
|
-
end
|
154
|
-
|
155
|
-
params_string.length.zero? ? "" : "?" + params_string.join("&")
|
156
|
-
end
|
157
|
-
end
|
data/lib/subdb/client_utils.rb
CHANGED
@@ -18,115 +18,117 @@
|
|
18
18
|
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
19
19
|
# THE SOFTWARE.
|
20
20
|
|
21
|
-
module Subdb
|
22
|
-
|
23
|
-
|
21
|
+
module Subdb
|
22
|
+
module ClientUtils
|
23
|
+
VIDEO_EXTENSIONS = ['.avi', '.mkv', '.mp4', '.mov', '.mpg', '.wmv', '.rm', '.rmvb', '.divx']
|
24
|
+
SUB_EXTESNIONS = ['.srt', '.sub']
|
24
25
|
|
25
|
-
|
26
|
-
|
27
|
-
|
26
|
+
class << self
|
27
|
+
def scan_paths(paths)
|
28
|
+
video_ext = VIDEO_EXTENSIONS.join(",")
|
28
29
|
|
29
|
-
|
30
|
+
files = []
|
30
31
|
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
32
|
+
for path in paths
|
33
|
+
if File.directory?(path)
|
34
|
+
path = path.chomp(File::SEPARATOR)
|
35
|
+
globpath = "#{path.gsub("\\", "/")}/**/*{#{video_ext}}"
|
35
36
|
|
36
|
-
|
37
|
+
yield globpath if block_given?
|
37
38
|
|
38
|
-
|
39
|
-
|
40
|
-
|
39
|
+
files = files.concat(Dir.glob(globpath))
|
40
|
+
else
|
41
|
+
files << path if VIDEO_EXTENSIONS.include?(File.extname(path))
|
42
|
+
end
|
41
43
|
end
|
42
|
-
end
|
43
44
|
|
44
|
-
|
45
|
-
|
45
|
+
files.sort
|
46
|
+
end
|
46
47
|
|
47
|
-
|
48
|
-
|
49
|
-
|
48
|
+
def sync(paths, languages = ["en"])
|
49
|
+
yield :loading_cache
|
50
|
+
cache = Subdb::UploadCache.new(cache_file_path)
|
50
51
|
|
51
|
-
|
52
|
-
|
52
|
+
results = {:download => [], :upload => []}
|
53
|
+
i = 0
|
53
54
|
|
54
|
-
|
55
|
-
|
56
|
-
|
55
|
+
for path in paths
|
56
|
+
base = File.dirname(path) + File::SEPARATOR + File.basename(path, File.extname(path))
|
57
|
+
sub = find_subtitle(path)
|
57
58
|
|
58
|
-
|
59
|
+
yield :scan, [path, i]
|
59
60
|
|
60
|
-
|
61
|
-
|
61
|
+
begin
|
62
|
+
subdb = Video.new(path)
|
62
63
|
|
63
|
-
|
64
|
+
yield :scanned, subdb
|
64
65
|
|
65
|
-
|
66
|
-
|
66
|
+
if sub and !cache.uploaded?(subdb.hash, sub)
|
67
|
+
yield :uploading, subdb
|
67
68
|
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
69
|
+
begin
|
70
|
+
subdb.upload(sub)
|
71
|
+
cache.push(subdb.hash, sub)
|
72
|
+
results[:upload].push(sub)
|
73
|
+
yield :upload_ok, subdb
|
74
|
+
rescue
|
75
|
+
yield :upload_failed, [subdb, $!]
|
76
|
+
end
|
75
77
|
end
|
76
|
-
end
|
77
78
|
|
78
|
-
|
79
|
-
|
79
|
+
if !sub
|
80
|
+
yield :downloading, subdb
|
80
81
|
|
81
|
-
|
82
|
-
|
82
|
+
begin
|
83
|
+
downloaded = subdb.download(languages)
|
83
84
|
|
84
|
-
|
85
|
-
|
85
|
+
if downloaded
|
86
|
+
sub = base + ".srt"
|
86
87
|
|
87
|
-
|
88
|
-
|
89
|
-
|
88
|
+
File.open(sub, "wb") do |f|
|
89
|
+
f << downloaded
|
90
|
+
end
|
90
91
|
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
92
|
+
cache.push(subdb.hash, sub)
|
93
|
+
results[:download].push(sub)
|
94
|
+
yield :download_ok, [subdb, sub]
|
95
|
+
else
|
96
|
+
yield :download_not_found, subdb
|
97
|
+
end
|
98
|
+
rescue
|
99
|
+
yield :download_failed, [subdb, $!]
|
96
100
|
end
|
97
|
-
rescue
|
98
|
-
yield :download_failed, [subdb, $!]
|
99
101
|
end
|
102
|
+
rescue
|
103
|
+
yield :scan_failed, path, $!
|
100
104
|
end
|
101
|
-
|
102
|
-
|
105
|
+
|
106
|
+
i += 1
|
107
|
+
|
108
|
+
yield :file_done, [subdb, i]
|
103
109
|
end
|
104
110
|
|
105
|
-
|
111
|
+
yield :storing_cache
|
112
|
+
cache.store!
|
106
113
|
|
107
|
-
|
114
|
+
results
|
108
115
|
end
|
109
116
|
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
results
|
114
|
-
end
|
117
|
+
def find_subtitle(path)
|
118
|
+
base = File.dirname(path) + File::SEPARATOR + File.basename(path, File.extname(path))
|
115
119
|
|
116
|
-
|
117
|
-
|
120
|
+
for subext in SUB_EXTESNIONS
|
121
|
+
subpath = base + subext
|
118
122
|
|
119
|
-
|
120
|
-
|
123
|
+
return subpath if File.exists?(subpath)
|
124
|
+
end
|
121
125
|
|
122
|
-
|
126
|
+
nil
|
123
127
|
end
|
124
128
|
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
def cache_file_path
|
129
|
-
File.join((ENV["HOME"] || ENV["USERPROFILE"]), ".subdb_cache")
|
129
|
+
def cache_file_path
|
130
|
+
File.join((ENV["HOME"] || ENV["USERPROFILE"]), ".subdb_cache")
|
131
|
+
end
|
130
132
|
end
|
131
133
|
end
|
132
134
|
end
|
data/lib/subdb/ui/swing.rb
CHANGED
@@ -37,135 +37,186 @@ import javax.swing.JTextArea
|
|
37
37
|
import javax.swing.SwingConstants
|
38
38
|
import javax.swing.UIManager
|
39
39
|
|
40
|
-
|
41
|
-
|
40
|
+
begin
|
41
|
+
import com.apple.eawt.Application
|
42
|
+
import com.apple.eawt.AppEventListener
|
43
|
+
import com.apple.eawt.OpenFilesHandler
|
44
|
+
rescue
|
45
|
+
# just fake classes
|
46
|
+
class Application
|
47
|
+
def self.application
|
48
|
+
self.new
|
49
|
+
end
|
42
50
|
|
43
|
-
|
44
|
-
|
51
|
+
def add_app_event_listener(listener)
|
52
|
+
end
|
45
53
|
|
46
|
-
|
47
|
-
|
54
|
+
def open_file_handler=(handle)
|
55
|
+
end
|
56
|
+
end
|
48
57
|
|
49
|
-
|
58
|
+
module AppEventListener
|
50
59
|
|
51
|
-
self.init_ui
|
52
60
|
end
|
53
61
|
|
54
|
-
|
55
|
-
begin
|
56
|
-
icon = ImageIO.read(getClass.getResource("images/subdb128.png"))
|
57
|
-
set_icon_image icon
|
58
|
-
rescue
|
59
|
-
end
|
62
|
+
module OpenFilesHandler
|
60
63
|
|
61
|
-
|
64
|
+
end
|
65
|
+
end
|
62
66
|
|
63
|
-
|
64
|
-
|
67
|
+
include_class java.lang.System
|
68
|
+
include_class Java::FileDrop
|
65
69
|
|
66
|
-
|
70
|
+
module Subdb
|
71
|
+
module UI
|
72
|
+
class Swing < JFrame
|
73
|
+
include FileDrop::Listener
|
74
|
+
include AppEventListener
|
75
|
+
include OpenFilesHandler
|
67
76
|
|
68
|
-
|
69
|
-
|
77
|
+
def initialize
|
78
|
+
super "SubDB Sync"
|
70
79
|
|
71
|
-
|
80
|
+
@uploading = false
|
72
81
|
|
73
|
-
|
74
|
-
|
82
|
+
app = Application.application
|
83
|
+
app.add_app_event_listener(self)
|
84
|
+
app.open_file_handler = self
|
75
85
|
|
76
|
-
|
86
|
+
self.init_ui
|
87
|
+
end
|
77
88
|
|
78
|
-
|
79
|
-
|
80
|
-
|
89
|
+
def init_ui
|
90
|
+
begin
|
91
|
+
icon = ImageIO.read(get_class.get_resource("/images/subdb128.png"))
|
92
|
+
self.icon_image = icon
|
93
|
+
rescue
|
94
|
+
puts "Can't set window icon: #{$!}"
|
95
|
+
end
|
81
96
|
|
82
|
-
|
97
|
+
border_size = 1
|
83
98
|
|
84
|
-
|
85
|
-
|
86
|
-
set_default_close_operation JFrame::EXIT_ON_CLOSE
|
87
|
-
set_location_relative_to nil
|
88
|
-
set_visible true
|
99
|
+
@dropper = JPanel.new
|
100
|
+
@dropper.border = BorderFactory.create_compound_border(BorderFactory.create_empty_border(border_size, border_size, border_size, border_size), BorderFactory.create_line_border(Color.black))
|
89
101
|
|
90
|
-
|
91
|
-
|
102
|
+
@progress = JProgressBar.new(0, 100)
|
103
|
+
@progress.string_painted = true
|
92
104
|
|
93
|
-
|
94
|
-
|
105
|
+
hint = JLabel.new("Arraste suas pastas ou arquivos com videos aqui.", SwingConstants::CENTER)
|
106
|
+
hint.preferred_size = Dimension.new(500, 60)
|
95
107
|
|
96
|
-
|
108
|
+
@dropper.add(hint, BorderLayout::CENTER)
|
97
109
|
|
98
|
-
|
110
|
+
@log = JTextArea.new
|
111
|
+
@log.editable = false
|
99
112
|
|
100
|
-
|
101
|
-
@progress.set_indeterminate true
|
113
|
+
@scroller = JScrollPane.new(@log)
|
102
114
|
|
103
|
-
|
115
|
+
content_pane.add(@dropper, BorderLayout::NORTH)
|
116
|
+
content_pane.add(@scroller, BorderLayout::CENTER)
|
117
|
+
content_pane.add(@progress, BorderLayout::SOUTH)
|
104
118
|
|
105
|
-
|
106
|
-
|
119
|
+
FileDrop.new(nil, @dropper, self)
|
120
|
+
|
121
|
+
set_size 800, 300
|
122
|
+
set_resizable true
|
123
|
+
set_default_close_operation JFrame::EXIT_ON_CLOSE
|
124
|
+
set_location_relative_to nil
|
125
|
+
set_visible true
|
107
126
|
end
|
108
127
|
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
@progress.set_indeterminate false
|
113
|
-
@progress.set_maximum files.length
|
114
|
-
|
115
|
-
results = Subdb::ClientUtils.sync files, ["pt", "en"] do |action, arg|
|
116
|
-
case action
|
117
|
-
when :loading_cache then log "Carregando cache de legendas enviadas..."
|
118
|
-
when :scan then log "Abrindo #{arg[0]}..."
|
119
|
-
when :scanned then log "Verificando #{arg.pathbase} [#{arg.hash}]..."
|
120
|
-
when :uploading then log "Enviando legenda local para o servidor..."
|
121
|
-
when :upload_failed then error "Erro ao enviar legenda #{arg[0]}: #{arg[1]}"
|
122
|
-
when :downloading then log "Procurando legenda no servidor..."
|
123
|
-
when :download_not_found then log "Nenhuma legenda encontrada no seu indioma"
|
124
|
-
when :download_failed then error "Erro ao tentar baixar #{arg[0].path}: #{arg[1]}"
|
125
|
-
when :scan_failed then error "Erro ao abrir arquivo #{arg[0]}: #{arg[1]}"
|
126
|
-
when :storing_cache then log "Salvando cache de legendas enviadas..."
|
127
|
-
when :file_done
|
128
|
-
log "Concluido #{arg[0].path}"
|
129
|
-
log_separator
|
130
|
-
@progress.set_value arg[1]
|
131
|
-
end
|
128
|
+
def openFiles(e)
|
129
|
+
sleep(0.5) until visible?
|
130
|
+
filesDropped(e.files)
|
132
131
|
end
|
133
132
|
|
134
|
-
|
135
|
-
|
136
|
-
log "#{results[:upload].length} legendas enviadas"
|
137
|
-
log_separator
|
133
|
+
def filesDropped(files)
|
134
|
+
return if @uploading
|
138
135
|
|
139
|
-
|
140
|
-
end
|
141
|
-
end
|
136
|
+
files = files.map { |f| f.to_s }
|
142
137
|
|
143
|
-
|
144
|
-
@log.append msg + "\n"
|
138
|
+
@uploading = true
|
145
139
|
|
146
|
-
|
140
|
+
Thread.new do
|
141
|
+
@progress.indeterminate = true
|
147
142
|
|
148
|
-
|
149
|
-
scroll.value = scroll.maximum if scroll.value > scroll.maximum - (@scroller.height + 30)
|
143
|
+
log "Gerando lista de arquivos..."
|
150
144
|
|
151
|
-
|
152
|
-
|
145
|
+
files = Subdb::ClientUtils.scan_paths(files) do |path|
|
146
|
+
log "Escaneando #{path}..."
|
147
|
+
end
|
153
148
|
|
154
|
-
|
155
|
-
|
156
|
-
|
149
|
+
log "Finalizado, #{files.length} arquivos para escanear."
|
150
|
+
log_separator
|
151
|
+
|
152
|
+
@progress.indeterminate = false
|
153
|
+
@progress.maximum = files.length
|
154
|
+
|
155
|
+
results = Subdb::ClientUtils.sync files, ["pt", "en"] do |action, arg|
|
156
|
+
case action
|
157
|
+
when :loading_cache then log "Carregando cache de legendas enviadas..."
|
158
|
+
when :scan then log "Abrindo #{arg[0]}..."
|
159
|
+
when :scanned then log "Verificando #{arg.pathbase} [#{arg.hash}]..."
|
160
|
+
when :uploading then log "Enviando legenda local para o servidor..."
|
161
|
+
when :upload_failed then error "Erro ao enviar legenda #{arg[0]}: #{arg[1]}"
|
162
|
+
when :downloading then log "Procurando legenda no servidor..."
|
163
|
+
when :download_ok then log "Legenda baixada com sucesso: #{arg[1]}"
|
164
|
+
when :download_not_found then log "Nenhuma legenda encontrada no seu idioma"
|
165
|
+
when :download_failed then error "Erro ao tentar baixar #{arg[0].path}: #{arg[1]}"
|
166
|
+
when :scan_failed then error "Erro ao abrir arquivo #{arg[0]}: #{arg[1]}"
|
167
|
+
when :storing_cache then log "Salvando cache de legendas enviadas..."
|
168
|
+
when :file_done
|
169
|
+
log "Concluido #{arg[0].path}"
|
170
|
+
log_separator
|
171
|
+
@progress.value = arg[1]
|
172
|
+
end
|
173
|
+
end
|
174
|
+
|
175
|
+
log "Concluido"
|
176
|
+
log_separator
|
177
|
+
|
178
|
+
if results[:download].length > 0
|
179
|
+
log "Legendas baixadas:"
|
180
|
+
results[:download].each { |s| log s }
|
181
|
+
log_separator
|
182
|
+
end
|
183
|
+
|
184
|
+
log "#{results[:download].length} legendas baixadas"
|
185
|
+
log "#{results[:upload].length} legendas enviadas"
|
186
|
+
log_separator
|
187
|
+
|
188
|
+
@uploading = false
|
189
|
+
end
|
190
|
+
end
|
191
|
+
|
192
|
+
def log(msg)
|
193
|
+
@log.append msg + "\n"
|
194
|
+
|
195
|
+
sleep 0.1
|
196
|
+
|
197
|
+
scroll = @scroller.vertical_scroll_bar
|
198
|
+
scroll.value = scroll.maximum if scroll.value > scroll.maximum - (@scroller.height + 30)
|
199
|
+
|
200
|
+
puts msg
|
201
|
+
end
|
202
|
+
|
203
|
+
def log_separator
|
204
|
+
log "------------------------------"
|
205
|
+
end
|
157
206
|
|
158
|
-
|
159
|
-
|
207
|
+
def error(msg)
|
208
|
+
log msg
|
209
|
+
end
|
210
|
+
end
|
160
211
|
end
|
161
212
|
end
|
162
213
|
|
163
214
|
# try use system look and feel
|
164
215
|
begin
|
165
|
-
UIManager.
|
216
|
+
UIManager.look_and_feel = UIManager.system_look_and_feel_class_name
|
166
217
|
rescue
|
167
218
|
# no lucky...
|
168
219
|
end
|
169
220
|
|
170
221
|
# start application
|
171
|
-
|
222
|
+
Subdb::UI::Swing.new
|
data/lib/subdb/upload_cache.rb
CHANGED
data/lib/subdb/version.rb
CHANGED
data/lib/subdb/video.rb
ADDED
@@ -0,0 +1,162 @@
|
|
1
|
+
# Copyright (c) 2011 Wilker Lucio da Silva
|
2
|
+
#
|
3
|
+
# Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
# a copy of this software and associated documentation files (the
|
5
|
+
# "Software"), to deal in the Software without restriction, including
|
6
|
+
# without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
# distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
# permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
# the following conditions:
|
10
|
+
#
|
11
|
+
# The above copyright notice and this permission notice shall be
|
12
|
+
# included in all copies or substantial portions of the Software.
|
13
|
+
#
|
14
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
21
|
+
|
22
|
+
require 'net/http'
|
23
|
+
require 'uri'
|
24
|
+
require 'cgi'
|
25
|
+
require 'digest/md5'
|
26
|
+
require 'net/http/post/multipart'
|
27
|
+
|
28
|
+
require 'subdb/version'
|
29
|
+
require 'subdb/client_utils'
|
30
|
+
require 'subdb/upload_cache'
|
31
|
+
|
32
|
+
module Subdb
|
33
|
+
class Video
|
34
|
+
API = "http://api.thesubdb.com/"
|
35
|
+
SANDBOX = "http://sandbox.thesubdb.com/"
|
36
|
+
|
37
|
+
class << self
|
38
|
+
attr_accessor :test_mode
|
39
|
+
|
40
|
+
def api_url
|
41
|
+
test_mode ? SANDBOX : API
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
self.test_mode = false
|
46
|
+
|
47
|
+
attr_reader :hash, :path
|
48
|
+
|
49
|
+
def initialize(path)
|
50
|
+
fail "#{path} is not a file" unless File.exists?(path)
|
51
|
+
|
52
|
+
@path = path
|
53
|
+
@hash = build_hash
|
54
|
+
end
|
55
|
+
|
56
|
+
def search
|
57
|
+
res = request("search")
|
58
|
+
check_get(res)
|
59
|
+
end
|
60
|
+
|
61
|
+
def download(languages = ["en"])
|
62
|
+
res = request("download", :language => languages.join(","))
|
63
|
+
check_get(res)
|
64
|
+
end
|
65
|
+
|
66
|
+
def upload(path)
|
67
|
+
fail "Invalid subtitle file #{path}" unless File.exists?(path)
|
68
|
+
|
69
|
+
params = {:action => "upload", :hash => @hash}
|
70
|
+
|
71
|
+
url = URI.parse(self.class.api_url)
|
72
|
+
|
73
|
+
begin
|
74
|
+
file = File.open(path, "rb")
|
75
|
+
|
76
|
+
io = UploadIO.new(file, "application/octet-stream", File.basename(path))
|
77
|
+
|
78
|
+
req = Net::HTTP::Post::Multipart.new(url.path + stringify_params(params), {"file" => io, "hash" => @hash})
|
79
|
+
req["User-Agent"] = user_agent
|
80
|
+
|
81
|
+
res = Net::HTTP.start(url.host, url.port) do |http|
|
82
|
+
http.request(req)
|
83
|
+
end
|
84
|
+
|
85
|
+
case res.code.to_s
|
86
|
+
when "201" then true
|
87
|
+
when "403" then false
|
88
|
+
when "400" then fail "Malformed request"
|
89
|
+
when "415" then fail "Invalid subtitle type"
|
90
|
+
end
|
91
|
+
ensure
|
92
|
+
file.close
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
def pathbase
|
97
|
+
File.basename(path)
|
98
|
+
end
|
99
|
+
|
100
|
+
protected
|
101
|
+
|
102
|
+
def build_hash
|
103
|
+
chunk_size = 64 * 1024
|
104
|
+
|
105
|
+
size = File.size(@path)
|
106
|
+
|
107
|
+
raise ArgumentError.new("The video file need to have at least 128kb") if size < chunk_size * 2
|
108
|
+
|
109
|
+
file = File.open(@path, "rb")
|
110
|
+
data = file.read(chunk_size)
|
111
|
+
file.seek(size - chunk_size)
|
112
|
+
data += file.read(chunk_size)
|
113
|
+
|
114
|
+
file.close
|
115
|
+
|
116
|
+
Digest::MD5.hexdigest(data)
|
117
|
+
end
|
118
|
+
|
119
|
+
def user_agent
|
120
|
+
"SubDB/1.0 (RubySubDB/#{VERSION}; http://github.com/wilkerlucio/subdb)"
|
121
|
+
end
|
122
|
+
|
123
|
+
def request(action, params = {}, body = nil)
|
124
|
+
params = {:action => action, :hash => @hash}.merge(params)
|
125
|
+
|
126
|
+
url = URI.parse(self.class.api_url)
|
127
|
+
|
128
|
+
req = Net::HTTP::Get.new(url.path + stringify_params(params))
|
129
|
+
req["User-Agent"] = user_agent
|
130
|
+
req.set_form_data(body) if body
|
131
|
+
|
132
|
+
Net::HTTP.start(url.host, url.port) do |http|
|
133
|
+
http.request(req)
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
def check_get(res)
|
138
|
+
case res.code.to_s
|
139
|
+
when "200" then res.body
|
140
|
+
when "400" then fail "Malformed request"
|
141
|
+
when "404" then nil
|
142
|
+
else
|
143
|
+
fail "Unexpected response code - #{res.code}"
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
def stringify_params(params)
|
148
|
+
params_string = []
|
149
|
+
|
150
|
+
params.each do |key, value|
|
151
|
+
next unless value
|
152
|
+
|
153
|
+
key = CGI.escape(key.to_s)
|
154
|
+
value = CGI.escape(value.to_s)
|
155
|
+
|
156
|
+
params_string << "#{key}=#{value}"
|
157
|
+
end
|
158
|
+
|
159
|
+
params_string.length.zero? ? "" : "?" + params_string.join("&")
|
160
|
+
end
|
161
|
+
end
|
162
|
+
end
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: subdb
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 23
|
5
5
|
prerelease: false
|
6
6
|
segments:
|
7
7
|
- 0
|
8
8
|
- 1
|
9
|
-
-
|
10
|
-
version: 0.1.
|
9
|
+
- 6
|
10
|
+
version: 0.1.6
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Wilker Lucio
|
@@ -15,7 +15,7 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2011-04-
|
18
|
+
date: 2011-04-28 00:00:00 -03:00
|
19
19
|
default_executable:
|
20
20
|
dependencies:
|
21
21
|
- !ruby/object:Gem::Dependency
|
@@ -49,6 +49,7 @@ files:
|
|
49
49
|
- lib/subdb/ui/swing.rb
|
50
50
|
- lib/subdb/upload_cache.rb
|
51
51
|
- lib/subdb/version.rb
|
52
|
+
- lib/subdb/video.rb
|
52
53
|
- lib/subdb.rb
|
53
54
|
- LICENSE
|
54
55
|
- README.textile
|