2013年お疲れ様でした
新年あけましておめでとうございます.
あっという間に2014年に突入してしまいましたね.
ということで2013年を振り返ります.(本当は2013年のうちにやりたかったんですが,PCが不調だったりでちょっとできなかった)
1月 就活に励む
2月 就活に勤しむ
3月 就活に暗雲が立ち込める
4月 進学にシフト.自前でサーバーを借り,ドメインを取り,遊ぶ.研究室に配属され,大学=研究室の日々をスタートする.
5月 Kinectで遊ぶ.研究室楽しい!!✌('ω'✌ )三✌('ω')✌三( ✌'ω')✌
6月 Twitterクライアント制作を始める.
7月 Twitterクライアントが形になってくる.
8月 院試が終わる.とりあえずTwitterクライアントを公開する.以後ちまちまとアップデートをする.
9月 某IT系企業でインターン開始
10月 インターン楽しい!!✌('ω'✌ )三✌('ω')✌三( ✌'ω')✌
11月 インターン楽しい!!✌('ω'✌ )三✌('ω')✌三( ✌'ω')✌
12月 25日に一人ですき家でカレー食ったあと一人で研究室行ってプリン食って研究室で寝た.
まあこんなところです.最後は笑うとこです.
2013年で触った技術的なことをざっと列挙すると
- Android(Twitterクライアント,WebView周り,課金処理,Push通知などなど)
- Kinect/OpenNI/Nite2/OpenCV
- Ruby, Ruby on Rails
- サーバー周り(GitLab, Redmine, WordPress, Rails実行環境などなど)
研究室では理論が疎かになっている感MAXなので,今年はしっかりそっちの方もやっていきたいところ.せっかくハードもソフトもやる研究室なので,ハードも作っていきたいなーとか思ってたりしてます.
まあ,あと2年間モラトリアムが続くので,研究にせよ趣味にせよ,全力で楽しいことをやっていきたいですね.
今年もよろしくお願いします.
はてブで人気動画を狙うよりも自分でキーワード使って狙って行ったほうが精度が高い
こんばんは,みなさまいかがお過ごしでしょうか.もうすぐクリスマスですね.
今日はまた凝りもせず大人向け動画サイトから動画を収集するためのプログラムについての記事です.
はてブは万能じゃない
まず,はてブで人気動画を狙った場合なのですが,結構高い確率で元動画が死んでいます.XVIDEOSなら7,8割,xHamsterなら4,5割といったところでしょうか.これは悲しいです.
また,カテゴリなどもバラバラで,全く好みでないジャンルの動画もまとめて引っこ抜いてしまいます.ホモビデオなんて大嫌いだ.
これはかなりキツイし面白く無いので改善します
キーワードを投げる
上記の問題をどう解決するか.簡単ですね.たいていの大人向け動画サイトというのは,検索用のページが有ります.そこにキーワードを投げて返ってきた画面を元に動画を引っこ抜いていけばいいのです.
そういう感じに前書いたスクリプトを改修していったらそれなりに上手いこと出来ました.
コードはGitHubにおいておいたので,自由に使ってください.良いホワイトクリスマスを!
はてブで人気のある動画を自動的にダウンロードするスクリプト書いた
はてブで人気のエロ動画を自動でダウンロードするツール “xxxdl” 開発しましたを読んで、windows版を使ってみたら動かなかったので自分で作ってみた。
Windows上で動かせるものを作るのはめんどくさそうだったので、ちょっと勉強していたRubyの練習がてらRubyで書いてUbuntuで動かすことにした。
処理の流れとしては、
- はてブから動画サイトのURLを引っ張ってくる
- 動画サイトのURLに飛んで、動画ファイルのURLを何とかして見つけるor生成する
- ファイルに保存
require "./downloader.rb" require "./hatebu_loader.rb" thread_max = 5 max_count = 100 xloader = HatebuLoader.new #xloader.setHamster #xHamsterの動画をダウンロードするときはコメントを外す xthreads = [] count = 0 locker = Mutex::new thread_max.times do xthreads << Thread.start do while count < max_count link = nil cnt = nil locker.synchronize do cnt = count link = xloader.getUrl(count) count += 1 end dl = VideoDownloader.new begin dl.setUrl(link) rescue OpenURI::HTTPError => e p e puts"error" else #dl.dlFromHamster #xHamsterの動画をダウンロードするときはこっちを使う dl.dlFromXVideos end puts "#{cnt} is finished." end end end xthreads.each do |x| x.join end puts "finish"
require "open-uri" require "nokogiri" class HatebuLoader def initialize @url = "http://b.hatena.ne.jp/entrylist" @query ={"url"=>"http://www.xvideos.jp", "sort"=>"count"} end def getUrl(count) @query["of"] = count.to_s url = @url.clone @query.each do |key, value| if !url.include?('?') url << '?' << key << '=' << value else url << '&' << key << '=' << value end end doc = Nokogiri::HTML(open(url)) entries = doc.css('.entry-link') #puts url return entries[0].attributes['href'].value end def setHamster @query["url"]="http://xhamster.com" end end
require "open-uri" require "nokogiri" class VideoDownloader def setUrl(url) @url = url @doc = Nokogiri::HTML(open(url)) @html = @doc.to_s @title = @doc.title @title.gsub!("/", "-") if @title.include? "/" #puts "loaded #{url}" end def dlFromXVideos if !@html.include? "flv_url" puts "cannot find video #{@url}" return end pos1 = @html.index("flv_url") + 8 pos2 = @html.index("&", pos1) len = pos2 - pos1 @downloadUrl = URI.decode(@html[pos1, len]) @title = @doc.css('div#main > h2')[0].child.text.strip downLoad end def dlFromHamster if @doc.css('#playerSwf').empty? puts "cannot find video #{@url}" return end pos1 = @html.index("\'srv\'") + 8 pos2 = @html.index("\'file\'", pos1) - 8 len = pos2 - pos1 srv = @html[pos1, len] pos1 = @html.index("\'file\'") + 9 pos2 = @html.index(".flv", pos1) + 4 len = pos2 - pos1 file = "/flv2/key=" + @html[pos1, len] @downloadUrl = srv + file @title = @doc.css("div#playerBox > h2.gr").text.strip downLoad end def downLoad fileName = "dl/" + @title + ".flv" if File.exist?(fileName) puts "#{@title}.flv is already downloaded" return end puts "downloading #{@title} #{@url}" File.open(fileName, 'wb') do |output| begin open(@downloadUrl) do |data| output.write(data.read) end rescue OpenURI::HTTPError File.open("error.log", 'a') do |f| f.puts "HTTPError, cannot download #{@title}, #{@url}\n#{@downloadUrl}" end end end end end
GitHubに置いといたのでご自由にどうぞ。
マルチスレッドで動くんですが、排他制御が微妙で、設定したmax_countを多少ぶち抜いてしまったりします。直さなければ…
Twitterクライアント出来てました
Twitterクライアント,出来てました.実は先月末に公開してたんですけど記事に書く余力がなかったので.
Twitterクライアントを作ろうと思ったきっかけとなった某クライアントをリスペクトした結果がこのタイトルです.
リストをぬるぬる閲覧できるのが特徴です.
PagerSlidingTabStripという素晴らしいライブラリのおかげです.
他にも,ViewPagerIndicator,twitter4j,PullToRefreshListviewを使いました.
車輪の再発明を防ぐどころか,自分ではとても作れそうにない素敵な車輪を提供してくれる方々にほんとうに感謝です.
いずれは自分も利用する側ではなく提供する側に回りたいものです.
ソースを整理したら,GitHubできっと公開します.
Twitterクライアント製作記その5 複数アカウント対応+会話を表示
複数アカウント対応しました(仮)
アカウントごとに,認証して得られるOAuthTokenのTokenとTokenSecretをデータベースに保存するようにした.
ただ,色々動作が怪しすぎてデバッグしきれない(`;ω;´)
アカウントの削除はボタンだけ用意してあるけどまだ消せない.
リストはユーザーIDでデータベースから情報を引っ張ってこれる形にしたので,アカウントを切り替えた時にリストの状態も切り替わります.素敵.
会話を表示するのは,AsyncTaskでInRepyToStatusIDを追っていけば余裕だろうと思っていたけど,1つを使いまわすと恐ろしいことになった.
2つAsyncTaskを使うメソッドを用意して,順番に回すとうまく行った.これでいいのかはわからないけど.
そして,EGitが使えるようになった!というか元々入ってた!
追記
AsyncTaskの使い方が悪かったみたい.こういう感じに書けばリプライを順番に追えた.
AsyncTask<Void, Void, Status> loadTask; private class LoadConversationTask extends AsyncTask<Void, Void, Status> { @Override protected void onPreExecute() { //プログレスバーを表示したりする } @Override protected twitter4j.Status doInBackground(Void... params) { return nextTweet(nextId);//nextIdのツイートを持ってくる } @Override protected void onPostExecute(twitter4j.Status result) { if (result != null) { mAdapter.add(result); mAdapter.notifyDataSetChanged(); nextId = result.getInReplyToStatusId(); Log.d(TAG, "nextId:" + nextId); if (nextId > 0) { loadTask = new LoadConversationTask(); loadTask.execute(); } else { Log.d(TAG, "正常終了"); } } else { //取得できなかった時の処理をかく } } @Override protected void onCancelled() { super.onCancelled(); Log.d(TAG, "onCancelled()"); setFooterViewStandby(); } } void loadPrevious() { if (loadTask != null && loadTask.getStatus() == AsyncTask.Status.RUNNING) { Log.d(TAG, "loadPrevious() return : loadTask is running."); return; } loadTask = new LoadConversationTask(); loadTask.execute(); } private twitter4j.Status nextTweet(long id) { try { return mTwitter.showStatus(nextId); } catch (TwitterException e) { e.printStackTrace(); } return null; }
適当なタイミングでloadPrevious()を呼べば,ツイートが読み込み終わるたびにリプライ先を読みこんでくれる.
読み込み中に会話を表示するアクティビティが死んでも,loadTaskは走り続けるので,onPauseの時に,loadTask.cancel(true);を書いておく
trueだとdoInbackGroudの処理が直ちにとまってonCancel()に移り,falseだとが終わるまで待ってonCancel(Object)が動く.
Twitterクライアント製作記その4
なぜかリストを選んだり,会話を表示する前に複数アカウントを実装しようとしていた.
けどSharedPreferenceで複数アカウントの情報を保持してさらにリストの設定とかも保存するとなるとかなりやばいよなあ.
SQLite使えばUserIdをキーにして,色んな情報を保存しておけるっぽいし削除もわかりやすいっぽいからそうしよう.
それよりも早く会話を表示できるようにしよう.
出来たこと
- アカウント管理画面を作った(追加はまだできない)
- 再認証出来るようにした
- ユーザーIDとスクリーンネームをSharedPreferenceに保存するようにした
- ツイートをタップした時のDialogFragmentの表示が切れる
- EGitの使い方がわからない