MacRubyでのアニメ壁紙ダウンローダーの作成

面白いデスクトップの壁紙を探してtheotaku.comを見ると、タグではなく壁紙自体に自動的にタグを付けるソフトウェアを作成するのがいいと思った。 私はMac OS Xをメインのオペレーティングシステムとして使用しているという事実に基づいて、ソフトウェアはこのプラットフォームにも対応している必要があり、 Cocoaインターフェースが必要です。 何らかの理由で、私はこれらすべてをJavaで書きたくありませんでした。 もちろん、多くの選択肢がありましたが、何らかの理由で他のことを試して、同時に何か新しいことを学びたかったのです。 私はすぐにMacRubyCocoaとの密接な統合を思い出しました。 このアイデアを武器に、すぐにhttp://www.macruby.org/にアクセスして、最新の安定バージョン0.10をダウンロードしました。 インストール後、お気に入りのXcodeを起動し、 AnimeWallpaperDownloaderという新しいプロジェクトを作成しました



MacRubyプロジェクトは、 Xcodeが作成するいくつかのファイルで構成されています。 最初のファイルはmain.mで、 MacRubyスクリプトrb_main.rbを実行するだけです

#import <Cocoa/Cocoa.h> #import <MacRuby/MacRuby.h> int main(int argc, char *argv[]) { return macruby_main("rb_main.rb", argc, argv); }
      
      





rb_main.rbはかなり単純なスクリプトで、他のすべてのRubyスクリプトをロードして実行します

NSApplicationMain

 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の役割を果たします。 これには、プログラムの起動が終了したときに呼び出される空のapplicationDidFinishLaunchingメソッドが含まれています。

 class AppDelegate attr_accessor :window def applicationDidFinishLaunching(a_notification) # Insert code here to initialize your application end end
      
      





ここでattr_accessor:windowIBOutlet * windowの役割を果たし、すでにプログラムのウィンドウに関連付けられています



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(-@number.intValue) 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
      
      





ここではすべてが非常に簡単です。 windowWillCloseメソッドとcontrolTextDidChangeメソッドは、プログラムウィンドウと最初のテキストフィールドのデリゲートメソッドにすぎません(タグを入力するまで何もダウンロードできません)。

参照メソッドは、壁紙を保存するディレクトリを選択するダイアログボックスを開き、[ 参照 ]ボタンに添付します。 startStopメソッドはジャンプを開始するため、 [ダウンロード開始 ]ボタンにアタッチします。 残りのメソッドは補助的なものであり、 Downloaderクラスによって使用されます。これは、リンクの検索と壁紙のダウンロードに使用します



 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,eb].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,eb] 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,eb] 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
      
      





巨大なクラスは本当ですか? はい、ロジックが詰め込まれていますが、実際にはすべてが非常に簡単です。

startメソッドは、壁紙をダウンロードする別のスレッドを開始し、 停止するだけです。 メソッドgetIndexPagegetWallUrldownloadWallは theotaku.comに固有であり、多くのロジックを含んでいますが、基本的に簡単で、タグで壁紙を検索し、目的の壁紙サイズへの目的のリンクを選択し、これらの壁紙をダウンロードするために使用されます



結果は日曜日の夜に費やされ、自己満足の良さ、そしてMac OS Xの代替開発プラットフォームとしてのMacRubyの将来についての多くの興味深い考えがありました もちろん、 レーキがあり、いくつかのことができませんでしたが、 MacRubyプラットフォームが人気を集め始めており、明るい未来があると思います。



ここで結果を見ることができますが、 ここ から完成したビルドダウンロードできます( MacRubyがインストールされている必要があります)



ご清聴ありがとうございました



バイバイ







UPD:パーサーをリファクタリングしてくれたEsthete感謝します






All Articles