Просматривая theotaku.com В поисках интересных обоев для рабочего стола я поймал себя на мысли, что было бы неплохо написать программу, которая автоматически скачивала бы мне обои по тегам.
Судя по тому, что я использую Mac OS X в качестве основной операционной системы программное обеспечение также должно быть для этой платформы и желательно иметь Какао интерфейс.
Мне почему-то не хотелось писать все это на Java. Альтернатив, конечно, было много, но мне почему-то хотелось попробовать что-то другое и в то же время узнать что-то новое.
я сразу вспомнил МакРуби и его тесная интеграция с Какао .
Вооружившись этой идеей, я немедленно отправился в http://www.macruby.org/ и скачал последнюю стабильную версию 0.10. После установки запустил свой любимый X-код и создал новый проект под названием АнимеОбоиЗагрузчик Наш проект на МакРуби состоит из нескольких файлов, которые X-код творит для нас.
Первый файл main.m который просто работает МакРуби сценарий rb_main.rb
rb_main.rb довольно простой скрипт, он загружает все остальные Рубин сценарии и запуски NSApplicationMain#import <Cocoa/Cocoa.h> #import <MacRuby/MacRuby.h> int main(int argc, char *argv[]) { return macruby_main("rb_main.rb", argc, argv); }
framework 'Cocoa'
# Loading all the Ruby project files.
main = File.basename(__FILE__, File.extname(__FILE__))
dir_path = NSBundle.mainBundle.resourcePath.fileSystemRepresentation
Dir.glob(File.join(dir_path, '*.
{rb,rbo}')).
map { |x| File.basename(x, File.extname(x)) }.
uniq.each do |path|
if path != main
require(path)
end
end
# Starting the Cocoa main loop.
NSApplicationMain(0, nil)
Последний файл, который для нас уже создан, — это AppDelegate.rb , что играет роль NSApplicationDelegate .
Он содержит пустой метод ПриложениеДидФинишЗапуск который вызывается, когда наша программа завершает работу.
class AppDelegate
attr_accessor :window
def applicationDidFinishLaunching(a_notification)
# Insert code here to initialize your application
end
end
Здесь attr_accessor:окно действующий IBOutlet *окно и уже привязан к нашему окну программы
Откройте MainMenu.xib и создайте простой интерфейс для нашего загрузчика обоев.
Далее мы добавляем методы и выходы в нашу AppDelegate class AppDelegate
attr_accessor :window
attr_accessor :tags
attr_accessor :size
attr_accessor :number
attr_accessor :saveInto
attr_accessor :startButton
attr_accessor :output
attr_accessor :downprogress
attr_accessor :downloader
attr_accessor :img
def applicationDidFinishLaunching(a_notification)
@startButton.setEnabled(false)
@downprogress.setStringValue('')
@output.setStringValue('')
@saveInto.stringValue = NSHomeDirectory()+"/Pictures"
end
def windowWillClose(a_notification)
NSApp.terminate(self)
end
def controlTextDidChange(notification)
sender = notification.object
if sender == tags
@startButton.setEnabled(@tags.stringValue.size > 0)
elsif sender == number
begin
@number.setIntValue(@number.intValue)
if @number.intValue < 0
@number.setIntValue([email protected])
elsif @number.intValue == 0
@number.setIntValue(20)
end
rescue
@number.setIntValue(20)
end
end
end
def browse(sender)
dialog = NSOpenPanel.openPanel
dialog.canChooseFiles = false
dialog.canChooseDirectories = true
dialog.allowsMultipleSelection = false
if dialog.runModalForDirectory(nil, file:nil) == NSOKButton
@saveInto.stringValue = dialog.filenames.first
end
end
def startStop(sender)
if @downloader == nil
@downloader = Downloader.new(@tags.stringValue,@size.selectedItem.title,@number.stringValue,@saveInto.stringValue,self)
@downloader.start
@startButton.setTitle("Stop Download")
else
@downloader.stop
@downloader = nil
@startButton.setTitle("Start Download")
end
end
def changeImage(file)
@img.setImage(NSImage.alloc.initByReferencingFile(file))
end
def clearStatus
@downprogress.setStringValue('')
end
def setStatus(i,m)
@downprogress.setStringValue("Downloading "+i.to_s()+" of "+m.to_s())
end
def setStatusEnd(i)
@downprogress.setStringValue("Downloaded "+i.to_s()+" wallpapers")
end
def puts(val)
$stdout.puts val
@output.setStringValue(val)
end
def stopped
@startButton.setTitle("Start Download")
down = @downloader
@downloader = nil
down.stop
end
end
Здесь все довольно просто.
Методы окноWillClose И ControlTextDidChange просто делегируем методы для окна программы и первого текстового поля (пока не введем тег, ничего скачать нельзя).
Метод просматривать открывает диалоговое окно выбора каталога, куда сохраняем наши обои, привязываем его к кнопке Просматривать .
Метод стартСтоп запускает загрузку, поэтому привязываем ее к кнопке Начать загрузку .
Остальные методы являются вспомогательными и будут использоваться классом Загрузчик , который мы будем использовать для поиска ссылок и скачивания обоев.
require 'thread'
require 'net/http'
class Downloader
attr_accessor :tags, :size, :number, :saveTo, :thread
attr_accessor :app, :exit
def initialize(tags, size, number, saveTo, app)
@tags = tags.sub(' ','_')
@size = size == 'Any' ? '' : size.sub('x','_')
@number = number
@saveTo = saveTo
@app = app
@exit = false
end
def getIndexPage(page)
walls = {}
url = ' http://www.theotaku.com/wallpapers/tags/'+tags+'/Эsort_by=&resolution='+size+'&date_filter=&category=&page='+page.to_s()
@app.puts 'getting index for page: '+page.to_s()
@app.puts url
response = Net::HTTP.get_response(URI.parse(url))
res = response.body
res.each_line { |line|
f = line.index('wallpapers/view')
while f != nil
b = line.rindex('"',f)
e = line.index('"',b+1)
u = line[b+1,e-b].
gsub('"','') walls[u] = u line = line.sub(u,'') f = line.index('wallpapers/view') end } @app.puts 'got '+walls.size.to_s()+' wallpapers' return walls.keys end def downloadWall(url) @app.puts 'downloading '+url response = Net::HTTP.get_response(URI.parse(url)) res = response.body b = res.index('src',res.rindex('wall_holder'))+5 e = res.index('"',b) img = res[b,e-b] self.downloadFile(img) end def downloadFile(url) name = url[url.rindex('/')+1,1000] if File.exists?(@saveTo+'/'+name) @app.puts 'wallpaper already saved '+name @app.changeImage(@saveTo+'/'+name) else @app.puts 'downloading file '+url response = Net::HTTP.get_response(URI.parse(url)) open(@saveTo+'/'+name, 'wb') { |file| file.write(response.body) } @app.puts 'wallpaper saved '+name @app.changeImage(@saveTo+'/'+name) end end def getWallUrl(i,url,size) sizes = {} i = i+1 @app.puts 'getting '+url+' sizes' response = Net::HTTP.get_response(URI.parse(url)) res = response.body res.each_line { |line| f = line.index('wallpapers/download') while f != nil b = line.rindex('\'',f) e = line.index('\'',b+1) u = line[b+1,e-b] u = u.gsub('\'','') sizes[u] = u line = line.sub(u,'') f = line.index('wallpapers/download') end } sizef = @size.sub('_','-by-') sizes = sizes.keys() if sizef == '' maxi = 0 max = 0 i = 0 sizes.each { |s| f = s.rindex('/') l = s[f+1,100] l = l.sub('-by-',' ') l = l.split(' ') rs = l[0].
to_i()*l[1].
to_i()
if rs > max
maxi = i
max = rs
end
i = i+1
}
return sizes[maxi]
else
sizes.each { |s|
if s =~ /#{Regexp.escape(sizef)}$/
return s
end
}
end
return sizes[0]
end
def start
@thread = Thread.new {
@app.puts "Download started"
begin
i = 0
p = 1
@app.clearStatus
while i < @number.to_i() and not @exit
w = self.getIndexPage(p)
if w.size == 0
break
end
w.each { |w|
wallu = self.getWallUrl(i,w,self.size)
if wallu != nil
@app.setStatus(i+1,@number.to_i())
self.downloadWall(wallu)
i = i+1
if i >= @number.to_i() or @exit
break
end
end
}
p = p+1
end
@app.puts ""
@app.setStatusEnd(i)
rescue => e
puts e
end
@app.stopped
}
end
def stop
begin
@app.puts "Download stopped"
if @thread.alive?
if @thread == Thread.current
Thread.exit(0)
else
@exit = true
end
end
rescue => e
puts e
end
end
end
Огромный класс, не так ли? Да, он напичкан логикой, но на самом деле всё довольно тривиально.
Метод начинать просто запускает отдельную ветку, в которой будут скачиваться наши обои, останавливаться останавливает его.
Методы getIndexPage , getWallUrl , скачатьСтена специфичный для сайта theotaku.com и содержат довольно много логики, но по сути довольно тривиальны и используются для поиска обоев по тегу, выбора нужной ссылки на нужный размер обоев и скачивания этих обоев Результат – хорошо проведенный воскресный вечер, хорошее чувство удовлетворения собой, а также масса интересных мыслей о будущем.
МакРуби как альтернативная платформа для развития на Mac OS X .
Конечно без грабли не получилось и некоторые вещи сделать не удалось, но я думаю, что платформа МакРуби начинает набирать популярность и имеет блестящее будущее.
Результат можно увидеть здесь здесь , ну а готовый билд можно скачать здесь отсюда (Вы должны иметь МакРуби )
Спасибо за внимание
пока, братик
УПД: Спасибо Эстет по рефакторингу парсера выглядит просто великолепно, последнюю версию смотрите на Github
Теги: #mac os x #mac os x #ruby #Cocoa #macruby #ruby
-
Ядов Владимир Александрович.
19 Oct, 24 -
Микро Бд Для Настройки На Микроконтроллере
19 Oct, 24 -
Горизонтально-Шлифовальный Станок
19 Oct, 24 -
Выделение Комментариев Автора
19 Oct, 24 -
Crisisonline.ru — Двухдневный Проект.
19 Oct, 24 -
Фотографии Домашнего Офиса-3
19 Oct, 24 -
Запуск Iphone Sdk На Powerpc
19 Oct, 24