「やく見てる」エクステンション作った
クソアプリアドベントカレンダー 13日目の記事です
こんにちは、ライオンです
皆さん、やくみつるはご存知ですか?
ええ、いろいろと炎上したりするコメンテーターですね
自分のリアルを知っている人はご存知だと思うんですが、よく似ているって言われるんですよね
10人中9人ぐらいに似ているって言われるんですよね
そんなに似ているのかなーって2年前ぐらいに実家に帰ったら兄弟に似ているって爆笑されたんですよね
ショックです
そんなわけでchrome extensionを作ることにしました
開発の話に興味ない人用のリンク googleまで戻る
開発の話
最初、imgタグのsrc変えれば余裕でしょって考えてたんですよね
でやってみたら、こんな感じになったわけですね
すごいですよね、皆やくみつるですよ
ざまぁみろ
で、ひとしきりゲラゲラ笑い終わって、いやーぁもう仕事終わっちゃったなー
クソアプリすぎるどころか面白さすらないなーとか考えながらおっぱいの画像を探してたんですよね(精神衛生上の健康のためにお医者さんから処方されている)
で、そしたら途中から気づいたんですよ
画像が変わってない
でもすぐに気づくんですよね、lazy loadだって
普通の画像ならsrc属性だけで済むけど、data-*属性を使っているならビンゴです
方法までは難読化されたソースコードを読まないといけないので読んでいませんが、クソアプリにそんな時間はかけていられません
で、こうなったらreplaceChildでimgタグを塗り替えてやるしかないですね
で、書き換えて見て見ました
クソが
よくよく考えたらインフィニティスクロールに対して、非同期処理してないなんてありえないですよね
こうなったら何が何でも書き換えてやりたくなりますよね
何とか奪えないかと考え始めます
まぁそうするとsetTimeoutかsetIntervalするしかないかなって考えが出て来ますね
非同期でDOMを追加される以上、そこに存在してないのでそれが追加されるまでをwatchするしかなくなりますね(悲しい
(() => { 'use strict'; const replaceMemo = { src: 'http://www.xn--l8j6cuc0dv605bd1f.jp/yuumeijin/photo/yakumituru.jpg', prepare: [], }; const replaceImage = () => { const $images = document.querySelectorAll('img'); replaceMemo.prepare.forEach($el => { const $img = document.createElement('img'); $img.src = replaceMemo.src; $el.parentNode.replaceChild($img, $el); }); }; const onWatch = () => { const $images = document.querySelectorAll('img'); replaceMemo.prepare = Array.from($images).filter($el => $el.src !== replaceMemo.src); replaceImage(); }; const main = () => { setInterval(onWatch, 1000); }; main(); })();
こんな感じのコードになりました
ここまで行くと瞬間的な表示はあるものの確実に変えられますね
しかしまだこれだと直接指定されているstyleなどが反映されていないですよね
cssTextを使ってそのまま持って来ます
こんな感じだったのが...
こうなります(画像は大槻ひびきさんです)
はーかわいいですね
で、上の画像見た人なら気づいていると思うんですが、左上の画像がとてつもなく邪魔ですよね?
これ開発中にも何度となく邪魔をされて本当に精神を壊しそうになりました
(googleからおっぱい検索をして画像タブをクリックするわけですが、押せないわけですね!)
で、よくよく調べてみると直接widthとheightを指定しているパターンもあるんですよね
$img.height = $el.height;
みたいなコードを追加します
綺麗に収まりましたね
皆さんの言いたいことはわかります
「大槻ひびきさん見せろよ!!」ですよね?
ですが、もともとアス比の合わないCSSに対して、決まった画像をあてがうので大槻ひびきさんがひどいことになってしまいます
酷い状態になった女優を見たくないですよね?(血涙
さて、この調子で直していって大体変わるわけですね
これは好きなライターさんの小野ほりでいさんの記事です
全部やくみつるでカオスですよね
カオス、カオス以外のことばが思いつかない
文字の色がなかったら誰が喋っているかすらわかりません
つまり小野ほりでいさんはこういうことをされることを分かっていて、それでも読みやすい記事を作ってくださっているわけですね!
で、何気なく下までスクロールしていって「あー大体変わっているなー」と思ったら、また変わってないところがあるわけですよ
クソがぁ...
何で変わらないんだろうと思ったらcssの中で呼ばれているURLですよね
backgroundで指定するパターンとbackground-imageで指定するパターンの2つですね
直接書き換えても書き換わらずに、 ''
を代入するとなぜか空にはなるという現象に見舞われ、今回もimgタグ同様replaceChildを使う強行手段に出ました
const replaceImage = (images, aTags, divs) => { images.forEach($el => { const $img = document.createElement('img'); $img.className = $el.className; $img.style.cssText = $el.style.cssText; $img.height = $el.height; $img.width = $el.width; $img.src = replaceMemo.src; $el.parentNode.replaceChild($img, $el); }); aTags.bk.forEach($a => { const $newA = document.createElement('a'); $a.style.background = ''; $newA.style.cssText = $a.style.cssText; $newA.style.background = `url("${replaceMemo.src}")`; $a.parentNode.replaceChild($newA, $a); }); aTags.bki.forEach($a => { const $newA = document.createElement('a'); $a.style.backgroundImage = ''; $newA.style.cssText = $a.style.cssText; $newA.style.backgroundImage = `url("${replaceMemo.src}")`; $a.parentNode.replaceChild($newA, $a); }); divs.bk.forEach($div => { const $newDiv = document.createElement('div'); $div.style.background = ''; $newDiv.style.cssText = $div.style.cssText; $newDiv.style.background = `url("${replaceMemo.src}")`; $div.parentNode.replaceChild($newDiv, $div); }); divs.bki.forEach($div => { const $newDiv = document.createElement('div'); $div.style.backgroundImage = ''; $newDiv.style.cssText = $div.style.cssText; $newDiv.style.backgroundImage = `url("${replaceMemo.src}")`; $div.parentNode.replaceChild($newDiv, $div); }); }; const includeBKUrl = ($el) => { return $el.style.background.includes('url'); }; const includeBKIUrl = ($el) => { return $el.style.backgroundImage.includes('url'); }; const onWatch = () => { const $images = document.querySelectorAll('img'); const $aTags = document.querySelectorAll('a'); const $divs = document.querySelectorAll('div'); const images = Array.from($images).filter($el => $el.src !== replaceMemo.src); const backgroundForATags = Array.from($aTags).filter($a => includeBKUrl($a)); const backgroundImageForATags = Array.from($aTags).filter($a => includeBKIUrl($a)); const backgroundForDivs = Array.from($divs).filter($div => includeBKUrl($div)); const backgroundImageForDivs = Array.from($divs).filter($div => includeBKIUrl($div)); replaceImage(images, { bk: backgroundForATags, bki: backgroundImageForATags }, { bk: backgroundForDivs, bki: backgroundImageForDivs }); }; const main = () => { setInterval(onWatch, 1000); }; main();
汚い匂いを放ち始めてワクワクしてきましたね!
ですがそのスペルマコードによって、ようやく姿を変えるわけです
Amazing!
しかしここまでやってもまだまだ残っている画像やurl cssが残っているわけですね
必殺の技としては onLoad
で直す、というのもあるわけですが、効かなかったです
iframeの中にあるimgタグがconsole上で document.querySelectorAll('img')
を出力すると取れるのですが、cotent_script内で動いている document.querySelectorAll('img')
からは取れず、ここら辺はセキュリティの問題なんですかね?
なので不十分に残ります
次にやっぱり、同じ画像が出てくるのはあんまり楽しくないですよね
で、何か画像検索できるようなやつがいいなーと思ってやっぱりgoogle様のお力を借りたいですよね
を見ていたのですが、「やってられるか!」となりましたね
それはもうすごい勢いで
で、考えた結果webスクレイピングすりゃいいんじゃねってなりますよね
クッソ悩みました
もはや禿げていく人の焦燥感並に悩みました
backgroundで実行するEvent Pageで設定した非同期実行処理がContent Scripts内でどうやってタイミングよく受け取れるのか分からず本当に悩みまくりました
そしたら蛇足に書いてある部分があったことによって助かりました
涙しそうになりますよね、こういう時
嬉しかったのでお昼ご飯はキムチ鍋にしました
background.jsにはこんな感じで用意
const parser = new DOMParser(); const onMessage = (request, sender, callback) => { const xhr = new XMLHttpRequest(); const url = `https://www.google.co.jp/search?q=${encodeURI(request.query)}&num=100&safe=off&tbm=isch&source=lnms&sa=X&ved=0ahUKEwiR0sro4-zXAhVKmZQKHaJYDdEQ_AUICygC&biw=1920&bih=983&dpr=1`; xhr.onload = () => { const doc = parser.parseFromString(xhr.responseText, 'text/html'); const divs = Array.from(doc.querySelectorAll('.rg_meta')); const images = divs.map(div => JSON.parse(div.innerText).ou); callback(images); }; xhr.open('GET', url, true); xhr.send(); return true; // これがchrome extensionが非同期かどうかを判断するライン }; chrome.extension.onMessage.addListener(onMessage);
そして表側のcontentscripts.jsにこんな感じのコードを埋め込みます
const regex = { base64: /^data:/, }; const onResponse = (yakulist) => { choiceYakuMitsuru(yakulist); }; const choiceYakuMitsuru = (yakulist) => { const random = Math.floor(Math.random() * 101); const url = yakulist[random]; if (regex.base64.test(url)) { choiceYakuMitsuru(yakulist); } else { replaceMemo.src = yakulist[random]; } }; chrome.extension.sendMessage({ query: 'やくみつる' }, onResponse);
これでアクセスするたびにやくみつるが変わりますね
やくみつるじゃない知らないおっさんが見てますね
調べたら野球評論家だそうで、別のコメンテーターでした
さて、一通りのchrome extensionが作れたので満足しました
webstoreに登録しようかなとも思ったんですが、クソアプリに$5はちょっと冒険が過ぎるな、と思い、やめることにしました
代わりにGitHubには置いておこうと思います
これをcloneしてきて、chromeのエクステンションに開発中のやつ食わせるだけです
簡単でしょ?
余談1:
中高生、果てはおっさんにまで有名になってしまった動画サイトを見てみたら 全てがやくみつる になったので面白かったです
共用パソコンとか使っててクソガキにエロサイト見るのはまだ早いって思うお子さんをお持ちの方は導入して見ると良いんじゃ無いでしょうか
余談2:
これすごいのが、えっちな感じのやつ入れるとど迫力な感じになってめっちゃ面白かったです
普段意識しないで見てる部分とかが違和感になって映るので、女性器やらおっぱいやらが更に強調されて見えます
あとデバッグしてて、やくみつるずっと見てるのも精神的にきついのでAV女優にしてデバッグするのは良いんですが、そのまま閉じてカフェ行かない方が良いです
嫌な汗をかきます
次のクソアプリアドベントカレンダー 14日目は @tokeikun さんです