はてなキーワード: DOMとは
Ruby全盛期のちょっと後くらいからWebエンジニアをしているんだけど、React.jsがいろんな意味で扱いにくすぎる
関わっている人にもフロントエンドエンジニア(=React.jsしかやりたくない)が多いので毒気で吐き出しておきたい
ライフサイクルや裏側の仕組みをなんとなく理解していないと使えず無意味に複雑
useEffect一つとっても~~の場合はuseStateでいけるとかTIPS集みたいのがあるけど、そういうウンチクみたいなのわかってないと使いこなせないのは仕事増えてない?
仮想DOMで高速化とか言っているけどライフサイクル理解しないと速度でないよね?いつものプロジェクトそんなにちゃんと書けてる?jQueryで良くない?
ベストプラクティス知っててちゃんと設計しないと改修する工数がすごいことになる
そもそもプロジェクトにおいて作るものは都度変わっていくので完璧な設計は存在しない。なので、設計をきちんとしないとカオスになるのはReact.jsのほうが間違っている
React.jsと別のフロントエンドライブラリ比較するだけで空気悪くなるので正直フロントエンドエンジニアの人の前で話せない話題がある
なぜかフロントエンドライブラリをReact.jsしか許さない人が多いのはなぜ
言うまでもないけどNext.jsの記法はひどすぎる。Remixは良いけどそれならもうReact.jsじゃなくていい
数少ないメリットだったエコシステムだけど、もうReact.jsしか対応していないことなんてほぼ無い
フロントエンドリッチでアクセス数ものすごいサイトを運用するのにフロントエンドライブラリが必要だった時代にReact.jsを開発する必要があったのはわかるけど、もっと便利なフロントエンドライブラリあるし正直時代遅れなのを理解してくれ
私から告白したし、行為も最初10回くらい、全部私から誘っていた。
付き合い始めてから一年くらいして、定期的に彼氏の家に泊まるようになったが、一緒に寝るごとに私はムラムラして濡れまくり、向こうもゴソゴソ触ってくるのでコッチは準備万端!って感じになっては「疲れてるから挿入はごめん」って断られることが三回に二回くらい。
それでもたまには出来るし、その頃は前戯もすごく丁寧で、今までの相手で一番気持ちよかった。相手に余裕がある時だったら週に2回も3回もしていた。
ただ断られる度に、あるいは、誘いをかけても分からないふりで無視されるたび、心がすり減っていった。
で、そのまままた一年位が過ぎてから、目に見えてオッケーの頻度が落ちた。私は泊まりに行った彼氏の家で、彼氏がお風呂に入ってる隙にこっそりオナニーをしたりして過ごした。
期待しても無駄だ、この人は私ほど意欲がないんだ、って言い聞かせすぎたせいか、三年目の中盤から、しようと誘われて始めても全然濡れなくなった。四年目の今は、キスしても胸をまさぐられてもカラカラで、「昔はあんなにすぐ濡れてたのに…濡れなくなっちゃったね…」としょんぼり言われる。
それが心苦しくて、最近はする時いつも、ちゃんと濡れてるかが心配で、彼氏がゴムを取りに立ってる間に中の濡れ方確認したり、足りてなかったら慌ててクリ触って濡らそうとしたりしている。中折れが怖くて緊張して余計できない悪循環ってこんな感じだと思う。
今となっては、私からは一切誘わず向こうが誘えばするはするけど、なかなか濡れない。
そんな感じなせいか向こうの前戯も手短になってきて、ほんとに入れてほしくてじゃなくて「フェラし続けるの疲れたからもう挿入して終わりにしたい」っていう気持ちで「そろそろ入れて?」って言ってる。
甘えられすぎて、子供みたいに見えちゃってるから。ドキドキする相手じゃない。私は結構なマゾだと思うけど、彼氏にはdom的な役割を期待されているしそう振る舞っている。面倒見のいいお母さん、たまに叱って管理して、でも基本は甘やかす、みたいな。そういうのには全然性的に興奮できない。
あとは、行為とかじゃなくて普通に、ベッドの上でスマホとかしてると、局部を触られたりするから。今日なら5回くらい、下だけで。それが続くと「この人に触られることは日常なんだ」と思って、興奮のスイッチじゃなくなっていくのが分かる。
別に私の性欲が消えたわけじゃない。
むしろ昔から強過ぎる方だから、最近は半ばセフレみたいな女友達とたまにあってレズプレイをしたり、ハプバーに行って男女問わずしたりしている。
彼女ら彼らに恋愛感情は一切ないし、双方合意の上での「オナニーの延長」だと思っている。
もちろんオナニーにも積極的で、いろんなディルドを買って、常に気持ちいいオナニーを探求してるし、オカズもたくさん揃えてる。
そして、そういう「彼氏意外とのエロい行為」では、もうびっくりするほど濡れる。
ネットのエロ広告を見てムラっとして、好きなエロ漫画をちょっと読んだりするだけでビショビショになってる。
なんだかなぁと思う。
濡れないから、当然、彼氏とのセックスは気持ちよくない。昔はあんなに気持ちよかった、という思い出を反芻しながら無理やり気持ちを高めて抱かれている。
私は今のように、本当の性欲は彼氏以外で発散して、彼氏とは彼氏のペースに合わせて、愛情の確認としてやっていければいいかなと思っている。本音を言うなら、あまり積極的にしたいとは思わないけど、なにかの記念日とかにゆっくりするなら嬉しいと思う。
だけどふと、彼氏に触られながら「昔はこのくらいですぐ濡れてたのにね…寂しいなぁ」と言われると、思う。
私が漫画読んでる時にいきなりスジなぞらないでよ、スマホ片手に手慰みで乳首いじらないでよ、自分が興奮した時だけ「フェラしてくれない?」って始めようとするのやめてよ、「何回も求めたけど断られて、期待するのやめちゃった」って告白したこと覚えてるなら、濡れない私が悪いみたいな言い方やめてよ。
今度、伝えてみようかな。でもそれもめんどくさいな、と思う程度には、私はこの問題に冷めてしまっている。
ご清聴ありがとうございました。
これを改善してってお願いした。何書いてあるかわからないけど動いたよ。
https://anond.hatelabo.jp/20240125203115
// ==UserScript== // @name 増田ミュート(白塗り版) // @namespace http://tampermonkey.net/ // @version 2024-06-26 // @description ミュートワードを含む最小限の範囲を白塗りにする // @author You // @match https://anond.hatelabo.jp/* // @icon https://www.google.com/s2/favicons?sz=64&domain=hatelabo.jp // @grant none // ==/UserScript== (function() { 'use strict'; const muteWords = [ "弱者男性", "弱男", "弱者", "婚活", "男", "女", "年収", "下方婚", "発達障害", "発達", "ハッタツ", "ハッタショ", "ハッタショ", "競プロ", "競技プログラミング", "AtCoder", ]; function whiteoutElement(element) { element.style.backgroundColor = 'white'; element.style.color = 'white'; element.style.textShadow = 'none'; element.style.cursor = 'default'; element.style.userSelect = 'none'; // テキスト選択を防止 element.style.borderBottom = '1px dashed #ccc'; // 枠線を追加してテキストがあることを示す // リンクの場合、クリックを無効化 if (element.tagName === 'A') { element.style.pointerEvents = 'none'; element.removeAttribute('href'); } // 子要素にも適用 Array.from(element.children).forEach(child => { child.style.backgroundColor = 'white'; child.style.color = 'white'; child.style.textShadow = 'none'; }); // ツールチップを追加 element.title = 'この内容にはミュートワードが含まれています'; } function shouldMute(text) { return muteWords.some(word => { const parts = word.split(''); const regex = new RegExp(parts.map(char => `${char}92;92;s*`).join(''), 'i'); return regex.test(text); }); } function findSmallestMuteableElement(element) { if (element.nodeType === Node.TEXT_NODE) { return shouldMute(element.textContent) ? element.parentElement : null; } if (element.tagName === 'PRE' || element.tagName === 'CODE') { return shouldMute(element.textContent) ? element : null; } for (let child of element.childNodes) { const result = findSmallestMuteableElement(child); if (result) return result; } return shouldMute(element.textContent) ? element : null; } function processElement(element) { const muteableElement = findSmallestMuteableElement(element); if (muteableElement) { whiteoutElement(muteableElement); } } function processAllElements(root = document.body) { const walker = document.createTreeWalker( root, NodeFilter.SHOW_ELEMENT | NodeFilter.SHOW_TEXT, null, false ); let node; while (node = walker.nextNode()) { if (node.nodeType === Node.ELEMENT_NODE) { processElement(node); } else if (node.nodeType === Node.TEXT_NODE && node.parentElement) { processElement(node.parentElement); } } } function handleClickEvent(event) { setTimeout(() => { processAllElements(event.target); }, 100); } // 初回実行 processAllElements(); // クリックイベントの監視 document.body.addEventListener('click', handleClickEvent); // DOM変更の監視 const observer = new MutationObserver(mutations => { mutations.forEach(mutation => { if (mutation.type === 'childList') { mutation.addedNodes.forEach(node => { if (node.nodeType === Node.ELEMENT_NODE) { processAllElements(node); } }); } else if (mutation.type === 'characterData') { processElement(mutation.target.parentNode); } }); }); observer.observe(document.body, { childList: true, subtree: true, characterData: true }); })();
時間を守る事には異常に固執する癖にイチャモンで電凸をしちゃいけないという常識は守れないのか・・・(呆れ)
ネットでたまに一行とか一つのコメントですら前半と後半で矛盾した事を言ってる奴がいるけど
そういう奴らの中身はこういう奴なんだろうなって
もうね、人として考えられんよ
マジでこういう権威に楯突く奴に対して異常な攻撃性発揮する奴って何なの
水俣病団体は弁護士にでも相談してわけわからん嫌がらせ電話掛けてきたアホの名前出して良いレベル
水俣病被害者の発言遮断問題に関し、伊藤信太郎環境相との懇談に出席した被害者団体などに「(あらかじめ設定された)3分の持ち時間を守らない方が悪い」などと抗議する電話が数件寄せられたことが10日、各団体への取材で分かった。
熊本県水俣市で1日に行われた懇談に参加した団体によると、伊藤氏が再び同市を訪れ謝罪した8日夜、東京都の男性を名乗る人物から「3分を守らないあなたたちが悪いのに被害者ぶって抗議するのはおかしい」と非難する電話があった。
スパム対策か何か知らんが、天◯門とか中国人に対する差別的な発言プロフに書き込んでおきながら、中国人の絵描きフォローしてる人、如何にもSNS中毒って感じで胸糞。
恥を知ってくれ。
2024-01-03 21:35:04
実際に起こって多くの死傷者を出したであろう悲劇的な事件をさ、スパム避けの魔除けとか言って揶揄する目的でアカウント名やプロフに書く人、色んなモノを失ってる事に気づいた方が良いと思う。
「たかがスパム」に強い不快感を示して、モラルと知性に欠けた言動する人、多すぎませんか?
普段知識人気取ったり、正論めいた発言したりしてる人がこういう「遊び」にキャッキャしてるの見ると、乾いた笑いが出ると同時に心が冷える。
何て幼稚なんだろう、この人達は。
そこまでその国が嫌いなのに、その国の人が描いたイラストにいいねしてたり、その国の人達が作ったゲームに夢中で金と時間を溶かしてたりする。
恥ずかしくないんかな、色々と。
2024-01-06 23:55:13
ダブスタについては本人の中で何らかの言い訳や屁理屈を用意して正当化してるのかもしれないけどさ、実際その人達がやってる事って「ヘイトクライムで特定の国・人種を攻撃しておきながら、自分はその国の人達が用意した娯楽で楽しんでる」でしかない。
2024-01-06 23:55:13
まぁ、日本に住んでる以上、食文化や日常生活を送る上でその国の恩恵に全く触れない事なんて限りなく不可能に近いだろうし、そこまで徹底しろなんて言わないけどさ。
その国を殴るなら「嫌いな国の世話になんてなるか!」くらいは言って欲しいし実行して欲しいよ、俺としては。
でないと、ダサすぎる。
2024-01-06 23:55:14
ゲームや絵なんて人間の生命活動に大きな影響も与えないんだからさぁ、我慢する事くらい造作もないだろ?
最悪裏でやっててもその“好き”をネットに出力しなければバレる事もないし、何なら別垢でやれば良いだけだというのに何で同じ垢で出力しちゃうかなぁ。
2024-01-06 23:55:14
色々言ったけど俺が何でこんなに愚痴ってるかと言うとこういう人間が自分の愛好してるコンテンツのファンに居たからなんですよね。
なのにプロフにそのワードとコンテンツ名を並べたり固定ツイでそのコンテンツの二次創作を貼る。
アホか?
2024-01-06 23:55:15
何が竜娘が好きだ。
何が🦉の雛だ。
恥を知れ。
オマエラのくだらない遊びにコンテンツを巻き込むな。
原作者様の顔に泥塗るな。
そういう遊びは、別垢作って他所でやれ。
いやこれ凄いな
未履修からのロースクール入学で司法試験1位合格って相当優秀だろうに(しかも社会人経験もばっちり有りなので勉強しか出来ないガリ勉って訳でもない)
それでも裁判官検察、大手どころか中堅の法律事務所も全部落とされるのか…
最近は社会人からの予備試験ルートの司法試験合格も盛んに宣伝されているけれど
実際に受かったとしても年齢が高ければ門前払いだって事がよーーく分かった。
そりゃあ戸籍を偽造してでも若く偽りたいと思う人が出てくるのも無理もない。
だってどれだけ苦労して実績を上げるよりも、戸籍の生年月日を若返らせる方が有効なんだから。
『ITコンサルから転身、32歳入学で司法試験1位合格 ロースクール1期生・伊藤弁護士が語る「キャリアの多様性」』
「裁判所や検察庁、大手法律事務所は、若い合格者を優遇して採用しようとします。自分も司法試験後に大手・中堅法律事務所に応募しましたが、ことごとく落とされましたから(笑)。学生がそこで活躍したいと思ったら『若いうちに合格するしかない』となってしまうのも無理ありません」
シェアウェア(という表現はおいておいてのやつ。https://anond.hatelabo.jp/20230124045812)の記事が面白かったので、自分の得意分野の領域でいろいろ紹介します。
基本的に、SaaSのサービスは便利だけど、あれもこれもと契約していったらサブスク破産するので、
もともとownCloudっていうDropbox代替があったんだけど、そこから分派して今も機能開発が続いている。
興味深いのはLAMP構成なので、VPSや自宅サーバーじゃなくても、レンサバで動くのがいいよね。
データ保存領域はオブジェクトストレージ(S3互換)も利用できるので、例えばWasabiなんかと契約してお安く済ませてしまうのも全然アリかと。
最近はカンバンシステムって、単体で使うんじゃなくていろんなアプリの中で使われる印象なので、今更Trelloだけ使いたい、なんてニーズはないかもだけど、
そこまで複雑でなく小規模なプロジェクトとかだと、意外とTrelloだけでいいよね、みたいなこともあるかな。
そういう時は、これを使うといいかも。
ちょっとUIの雰囲気が違うだけで、まんまSlackです。絵文字の追加もできるし、APIもあるし。人によって好き嫌い分かれるスレッド機能も、まあ、あのスレッド機能のまま。
n8nと書いてnodemationと読ませるらしい。初見殺しすぎんだろ。
ZapierやIFTTT、無料枠あるけど、あれもこれもやり出すとすぐ無料枠埋まっちゃうので、これ結構いいと思うんだけどな。
kintone使ってる会社増えてると思うんだけど、まだまだ1ユーザー1500円ってのは高いので、零細企業は導入し辛いと思う。
で、それの代替になるのがExment。UIがkintoneとは少し違うので代替と言い切れないかもしれないが、
やれることはkintoneのソレと全く同じなので、用途代替はできる。
開発も日本企業なので、UIも日本語化されている。LAMP構成なので、レンサバでも動くよ!
そもそもAirtableって何やねんって人もいるかもしれないけど、kintoneとGoogleスプレッドシートをいいとこ取りして、Trelloとガントチャートを足した感じ。
これもまあまあいい感じでZoom再現してます。Zoomの方が新機能の追加早いけど、Jitsiも頑張って追いついている感じです。
ただ、やる内容が複数人でのリアルタイム動画配信なので、サーバースペック・回線スペックはまあまあ必要なので要注意。
こちらは使ったことないんだけど、よりオンライン授業向けらしい。
最近よく見かけるようになった、オンラインミーティングとかの予定をブッキングさせるSaaS。
あれのはしりがCalendlyで、日本でもいくつかそれのSaaSができてますね。
あれらも無料枠だと1カレンダーだけしかできなかったりするんだけど、これなら好きなだけブッキングさせられます。
ECサイトとか、Webマーケティングを重視してるサイトによくある、画面右下に吹き出しアイコンがあって、チャットウインドウがぴょこっと出てくるやつ。
日本ではWeb接客とか言われてるけど、あれの代表的なSaaSがIntercom。Zendeskは、どちらかというと内部ツール向きかな。
これのOSS版がChatwootとPapercups。自社サイトにWeb接客入れたいけど、費用抑えたい、って時にどうぞ。
この手のツールがないと仕事にならないという人も多いと思います。
これまでだとRedmineがそれのOSS版的立ち位置でしたが、さすがにイマドキあのUIはないなぁ、と。
OpenProjectは、Microsoft Projectの代替をイメージしてるみたいですが、
ガントチャートにカンバンがデフォルトで使えるので、BacklogやAsanaの代替にはちょうど良いでしょう。
ただ、そんな高度なことしてるわけではないのに、サーバーの要求スペックはちょっと高めなのでご注意を。
UA廃止でGA離れが始まってるとも聞きますが、疎開先として有名。
PHPで動くので、PHPやWordPressでできたサイトに一緒に入れちゃってもいいと思う。
HeadlessCMSは、データ表示を持たず、フロントエンドへAPIを通じてデータを渡すタイプのCMSのこと。
このジャンルでは、SaaSだとContentfulが有名だけど、OSSでもいろいろある。
Node.js製。歴史があるので、結構いろんなことができる。
WordPressのGutenbergエディターを取り込んだプラグインなんかもある。
User認証も持ってるので、CGM的なサイトを作ろうと思ったらできなくもない。
これもNode.js製。利用できるDBが幅広く、既存のデータベースも活用できる。
なので、既にPostgresSQLとかでデータを持ってるんだけど、
非エンジニアにもデータを触らせるためのフロントエンドが欲しい、ってニーズに良いかも。
PHP製。SQLiteとMongoDBで利用可能。MySQL/PostgreSQL使えないのがちょっと残念。
近年、本腰入れて自社ECサイトをやろうと思うと必ず選択肢に上がるShopify。
インテグレートパートナー向けのエコシステムも充実してるので、取り組み始めるエンジニアやシステム会社も多い。
ヘッドレスコマースや越境ECには向いているものの、これをセルフホストしたい、というニーズに応えたのがmedusa.js。
ざっと見てみただけだけど、モダンな構成で、今時のフロントとバックエンドを分けた構成でやりたい、というのには向いている。
プラグインにmedusa-marketplace.jsというのもあり、Amazon的なマーケットプレイスも実現可能。
昨年、Adobeに買収され、デザイナーたちを驚愕させたFigma。
先日はAdobe XDが終了のお知らせとなり、UIデザイナーたちの不安は募るばかり。
そんな提供企業に振り回されたくないなら、このPenpotでUIデザインしよう。
Figmaほど機能実装はされていないが、まあまあ一通りのことはできる。
Figma代が嵩むとお嘆きの制作会社なんかは、一考の余地あるんじゃなかろうか。
企業によっては、コンタクトフォームをたくさん作りたいという会社もある。
人材採用のフォームを職種別に細かく分けたい(しかも頻繁に募集職種が変わるとか)
Google Formで大体解決しそうだけど、それをGoogleに頼りたくないならこちら。
まあまあ機能豊富なので、人によってはGoogleFormよりもこちらを好むかも。
DockerベースのWebメールUI。送受信に必要なものを、丸っとDockerで用意してくれているので便利。
HubSpotは、いわゆるMarketing AutomationとCRMを一体にしたツール。無料枠もあるが、かなり限定されている。
MauticはMarketing Automationよりの機能が多く、ユーザーのサイト上での回遊をビジュアル化してくれたりする。
SuiteCRMはザ・CRMという感じ。SalesForceをデフォルトで使う感じに近い。
ツールが分かれてしまうのは辛いところだけど、それぞれにAPIがあるので、うまく繋げられると強力なツールになってくれるはず。
Webサービス作ってると、メールの通知や一斉配信などがあると思う。
通常これらはSendGridや、AWS SESなどで処理すると思うが、これらにもOSS代替がある。
PostalはDockerでメール周りのもの全部用意してくれているので、かなり楽。
WordPressをモダンにしたような感じで、EC機能もデフォルトでついてる。マルチサイトも標準。
Jimdo/Wix代替と書いたが、もちろん自分のサイトをMicroweberで作ってもいいが、
自前ホスティングして、JimdoやWixのようなサービスを始めることもできる。
テンプレートをいくつか作っておいて、Stripeを仕込んでおけば、今日からあなたもJimdo/Wixのような事業を始められるわけだ。
JImdo/WixとSTUDIO/Webflowは一緒くたに語られがちだが、明確な違いがある。
前者はプリディファインドなブロックをGUIで構成するのに対し、後者はDOM要素ベースで構築していく。
つまりよりHTML/CSSによる細かなデザインコントロールがしやすく、Webデザイナーが親しみやすい。
それのOSS版がWebstudio。まだアルファ版だが、フロントエンドはそれなりによくできているので、
バックエンドを自前で用意してStripeを仕込んでおけば、今日からあなたも(以下略
Facebookなんか使わねーよ、っていう人も多いかもしれないが、
特定のコミュニティの中でコミュニケーション取るには、FacebookのUIと機能は優れていると思う。
なので、サークルとか同窓会、あと自治会とかPTAなんかにもいいんじゃないだろうか。
Netflixの代替って、Amazon Primeとかじゃねーの、と思われるのかもしれないが、そうではなくて、
あなたがNetflixみたいな商売したいならこれを使うといいよ、というのがJellyfin。
いや、そんな商売しないよ、と思うかもしれないが、
使いようによっては、おじいちゃんおばあちゃん向けの子供動画配信サービスとして構築するとか、
Stripeと連携して、劇団やバンドのオリジナルの配信サイトを構築するなんかも面白いと思う。
今更誰もYouTubeやVimeoの後追いをしようとはしないでしょうが、
複数のユーザーから動画のアップを受け付けて、それを閲覧したい用途もあると思う。
例えば、軽音部で複数のバンドが練習風景を録画したのを定期的にアップしたりとか。
学習塾で、授業の録画を授業ごとにアップしていったりとか。
ZoomやGoogle Meetのような双方向ではなく、一対多の一方通行配信。
個人的には、企業のウェビナーツールとしての可能性を感じる。(Zoomのウェビナープランとか高いもん)
1つのメールアドレスを複数人で運用したい時のツールがメールワイズとRe:lationどちらも日本のSaaS。
FreeScoutはOSSだけど、海外製。一応日本語化もされてるっぽい。
ECサイトの顧客問い合わせや、営業チームのプライマリー対応なんかに良いと思う。
Bubbleってなんぞ? という人のためにお伝えしておくと、ノーコードベースのWebアプリ開発ツール。
データエンティティを設計したら、自動的にCRUDを作ってくれて、フォームを配置するというような感じ。
Bubbleはそれ系の老舗で、歴史が長い分ノウハウも溜まっており、連携できるサービスも多い。
ただ、ベンダーロックインされるし、季節的なキャンペーンとかでは、アプリを使用しない期間もサブスク費用がかかる。
Budibaseは、Bubbleの思想に一番近い感じ。凝ったUIが必要なければ、ざっくりコレでなんでも作れちゃう。
AppSmithも同じような感じだが、これはDBをあらかじめスキーマ定義しておかないといけないところが若干不便かな。
ToolJetはルーティングURLの概念がなく、本格使用を諦めたんだけど、最近アップデートしたらしいので、そこのところどうなってるかまた確認しときたい。
他にもこの手のやつあったら、いろいろ教えて欲しい。単純に好きなので。
勝手に tampermonkey とかに突っ込んで使ってヨロ
スクリプト保守とかするつもりないから、保守とかするつもりのあるパワーの溢れた人が
これ参考とかにしてもっとかっちょよくしたのを greasy fork あたりに公開してくれ
そしたら俺もそれ使う
localStorage.hatebu_ng_word_list に非表示のトリガーになる文字列を|区切りで登録する。
localStorage.hatebu_ng_word_list = "池田信夫|フェミ|弱者男性|やまもといちろう"
大なり小なり(>)が実体参照で表示されるのはよくわからん。使う人で適宜コードを直してくれ。
// ==UserScript== // @name はてブの一覧NG記事非表示 // @namespace http://tampermonkey.net/ // @version 0.1 // @description try to take over the world! // @author masuda // @match https://b.hatena.ne.jp/* // @icon https://www.google.com/s2/favicons?sz=64&domain=hatena.ne.jp // @grant none // ==/UserScript== (function() { 'use strict'; if (!localStorage.hatebu_ng_word_list) { return; } console.log("はてブの一覧NG記事非表示", localStorage.hatebu_ng_word_list); /* * 例: * localStorage.hatebu_ng_word_list = * "池田信夫|フェミ|弱者男性|やまもといちろう|togetter.com"; */ let words = localStorage.hatebu_ng_word_list.split('|').map(w => new RegExp(w)); function entryDelete(els) { els.forEach(el => { let hit = false; words.forEach(w => { hit = hit|| w.test(el.textContent); }); if (hit) { el.remove(); } }); } // entrylist-header-main li 1つ目のアイテム entryDelete(document.querySelectorAll('.entrylist-header-main > li')); // 2つ目以降の li アイテム entryDelete(document.querySelectorAll('.entrylist-item > li')); })();
自動で安価をつけて返信するプログラムでもこんなに長く複雑になる(一部抜粋)
/**************************************
以下のCSV_DIR, FILE_PATHS, SETTINGSを書き換えてね。 <h3>o- *************************************/</h3>
//CSVファイルが置かれてるディレクトリのパス。投稿前にエラー出たら大体ここの設定ミス。 例:"C:\\Users\\sakuraimasahiro\\Documents\\iMacros\\Macros\\rentou\\";
'C:\\Users\\USER\\Desktop\\iMacros\\Macros\\rentou\\';
//ファイルのパス。CSVは絶対パスで、拡張子も必要。iimは相対パスでよく、拡張子不要。
const FILE_PATHS = {
textCsv: CSV_DIR + 'textNoAnker.csv',
//レス用投稿文が書かれたCSV。通常とレス用で分けないなら同じファイルを使えばいい。
replyTextCsv: CSV_DIR + 'textReply.csv',
};
baseWaitTime: 5,
//baseWaitTime+0~waitTimeRange(ランダム)だけ待つ
waitTimeRange: 5,
//連投しすぎだと忠告された場合に処理を一時停止させる時間(秒)
waitTimeForAvoidingPunishment: 60 * 30,
//メール
mail: 'sage',
//名前設定
name: '',
//以下、偽装ワッチョイ設定。浪人でワッチョイを非表示にしてるときだけtrueにしてね。
//妙なニックネーム(ワッチョイ、アウアウウーなど)をランダムで決めて付加するかどうか。true=付加する。false=付加しない。
//妙なニックネームの後に付く8桁の文字列をランダムで決めて付加するかどうか。
},
//アンカー無し投稿をするならtrue。しないならfalse。noAnkerPostかreplyPostのどちらかはtrueにすること(両方trueでもOK)。
//アンカー付き投稿(返信)をするならtrue。しないならfalse。もしnoAnkerPostとreplyPostの両方がtrueの場合、投稿は返信が優先され、返信対象が見つからなくなったらアンカー無し投稿をする。
//最初に取得するアンカー無し投稿文CSVファイルの行番号。もし返信用と同じCSVファイルを使うなら-1と入力。
noAnkerPostTextCsvStartRow: 1,
//最初に取得する返信用投稿文CSVファイルの行番号。もしアンカー無しと同じCSVファイルを使うなら-1と入力。
//テキストCSV/返信用テキストCSVの取得行が最終行に達したら最初の行まで戻るかどうか。true=戻る。false=マクロ終了。
//返信する場合、これより小さなレス番には返信しない。返信を投稿すると、この数値は前回の返信先のレス番に更新される。
minAnker: 895,
//返信する場合、名前に以下の文字列を含む投稿にアンカーをつけて返信する(ワッチョイやIPなど名前フィールドにあるものならなんでも可)。配列で複数指定可能。指定無しなら空配列([])。filterNamesとfilterNamesNotIncluded共に無指定ならレス番1から順に返信していく(minAnkerが設定されてればそこから順に)。以下のfilter系は全て併用可能。
//↑とは逆に、名前に以下の文字列を含まない投稿にアンカーをつけて返信する。↑と併用も可能。
//返信する場合、本文に以下の文字列を含む投稿にアンカーをつけて返信する。
filterText: ['自演かな', '自演わらわら', 'スクリプト使うの', '安価ガバ', '>>660', '自演で擁護', '最後' ,'あいうえお', 'かきくけこ', 'さしすせそ', 'なにぬねの', 'はひふへほ', 'まみむめも', 'やいゆえよ', 'やゆよ', 'らりるれろ', 'わいうえを', 'わをん', 'わいうえをん'],
},
//自分のIPアドレスの確認。VPNとかでIPを変更してマクロを動かしてるとき、突然VPNが作動しなくなってIPが元に戻ったときにマクロを止めるためのもの。
//以下の文字列が自分の現在のIPアドレスに含まれている場合、マクロを一時停止する。基本的に自分の本当のIPアドレスを入力。
},
//浪人設定。最後に動作を確認したのは5年くらい前で、今も同じように動作するかは、浪人を持ってないから確認できずわからない。
//浪人にログインしてるかどうかをチェックするかどうか。trueならする。falseならしない。trueにしていてもし浪人にログインしていないことを確認したらログインしにいく。
password: '1234',
},
};
/**************************************
設定箇所終わり。
https://info.5ch.net/index.php/%E6%9B%B8%E3%81%8D%E8%BE%BC%E3%82%81%E3%81%AA%E3%81%84%E6%99%82%E3%81%AE%E6%97%A9%E8%A6%8B%E8%A1%A8 <h3>o- *************************************/</h3>
/**************************************
・NULL演算子(??)は使えない。論理積(&&)は使える。
・オブジェクトの分割代入はできない。
・importはできない。 <h3>o- *************************************/</h3>
/**************************************
関数 <h3>o- *************************************/</h3>
/**
* ここから始まる。
*/
checkSettings();
var _TextCsvCursors = new TextCsvCursors(
SETTINGS.postSettings.noAnkerPostTextCsvStartRow > 0
? SETTINGS.postSettings.noAnkerPostTextCsvStartRow - 1
: SETTINGS.postSettings.noAnkerPostTextCsvStartRow,
SETTINGS.postSettings.textCsvLoop,
),
SETTINGS.postSettings.replyPostTextCsvStartRow > 0
? SETTINGS.postSettings.replyPostTextCsvStartRow - 1
: SETTINGS.postSettings.replyPostTextCsvStartRow,
SETTINGS.postSettings.textCsvLoop,
),
);
var _LoopStatuses = new LoopStatuses(0, SETTINGS.postSettings.minAnker);
const _MyPosterName = new MyPosterName({
name: SETTINGS.nameSettings.name,
});
const _ThreadUrl = openPromptThreadUrl();
//ループ
while (true) {
SETTINGS.ipSettings.checkIp && checkCurrentIpNotTheIp();
//スレを開く
openUrl(_ThreadUrl.fullUrlHttps());
//浪人にログインする設定なら、浪人にログインしているかどうかを確認し、していなければログインしにいく。
if (SETTINGS.roninSettings.checkLogin) {
}
}
if (SETTINGS.postSettings.replyPost) {
const targetAnkerNumber = createPostDOMList()
.filterPostnumberHigher(_LoopStatuses.currentMinAnker())
.filterByPostername(SETTINGS.postSettings.filterNames)
.filterByPosternameNotIncluded(
SETTINGS.postSettings.filterNamesNotIncluded,
)
.filterByText(SETTINGS.postSettings.filterText)
if (targetAnkerNumber !== null) {
const r = _TextCsvCursors.takeNextRowTextAsReply(targetAnkerNumber);
messageDisplay(`返信対象有り。アンカー先: ${targetAnkerNumber}`);
return {
...r,
updatedLoopStatuses:
_LoopStatuses.updateMinAnker(targetAnkerNumber),
};
}
}
if (SETTINGS.postSettings.noAnkerPost) {
//返信対象無し、或いは返信しない設定の場合。アンカー無し投稿文を作る。
const r = _TextCsvCursors.takeNextRowTextAsNoAnker();
messageDisplay('返信対象無し。アンカー無し投稿。');
return {
...r,
updatedLoopStatuses: _LoopStatuses,
};
}
return null;
})();
if (p) {
//投稿。
nickname: SETTINGS.nameSettings.nickname,
korokoro: SETTINGS.nameSettings.korokoro,
area: SETTINGS.nameSettings.area,
}),
SETTINGS.mail,
p.text,
);
//_TextCsvCursorsと_LoopStatusesを更新。
_TextCsvCursors = p.updatedTextCsvCursors;
_LoopStatuses = p.updatedLoopStatuses.incrementPostCount();
`投稿回数: ${_LoopStatuses.currentPostCount()}`,
`minAnker: ${_LoopStatuses.currentMinAnker()}`,
`今回アンカー無し投稿取得行: ${_TextCsvCursors.currentRows().noAnker}`,
`今回アンカー有り投稿取得行: ${_TextCsvCursors.currentRows().reply}`,
]);
} else {
`返信対象が現われるのを待機中...。`,
`投稿回数: ${_LoopStatuses.currentPostCount()}`,
`minAnker: ${_LoopStatuses.currentMinAnker()}`,
`今回アンカー無し投稿取得行: ${_TextCsvCursors.currentRows().noAnker}`,
`今回アンカー有り投稿取得行: ${_TextCsvCursors.currentRows().reply}`,
]);
}
wait(SETTINGS.baseWaitTime + randomRange(0, SETTINGS.waitTimeRange));
}
}
/**
* 投稿処理と投稿結果を見てリトライしたりマクロ終了したり。
* @param {string} serverName サーバー名
* @param {MyPosterName} _MyPosterName
* @param {string} postMail メール
*/
serverName,
postMail,
_MyText,
retryTimes = 0,
) {
const r =
retryTimes === 0
? new ValuesOfPost(serverName, _MyPosterName, postMail, _MyText).post(
postTo5chTread,
)
serverName,
postMail,
_MyText,
).postSubstring(retryTimes, postTo5chTread, postConfirm);
if (r) {
back();
return;
}
wait(7);
const error = createPostErrorMessage().analyze();
messageDisplay(error.message);
if (error.order === 'KILL') {
kill();
} else if (error.order === 'SKIP') {
return;
} else if (error.order === 'TRUNCATE') {
back();
serverName,
postMail,
_MyText,
retryTimes + 1,
);
} else if (error.order === 'WAIT') {
wait(SETTINGS.waitTimeForAvoidingPunishment);
serverName,
postMail,
_MyText,
retryTimes,
);
} else if (error.order === 'LOGIN') {
serverName,
postMail,
_MyText,
retryTimes,
);
}
return;
}
/**
* 現在のIPアドレスに、SETTINGS.ipSettings.avoidTheIpの値が含まれていないことを確認する。含まれていたらマクロを一時停止。
* @returns
*/
function checkCurrentIpNotTheIp() {
openUrl('https://www.cman.jp/network/support/go_access.cgi');
const _IpAdress = createIpAdressFromCMan();
if (_IpAdress.includes(SETTINGS.ipSettings.avoidTheIp)) {
pause('現在のIPに指定した値が含まれていることを確認。');
}
return;
}
/**
* @returns
*/
if (
SETTINGS.postSettings.noAnkerPost === false &&
SETTINGS.postSettings.replyPost === false
) {
return kill('設定エラー。noAnkerPostとreplyPost両方ともfalseになってる。');
}
if (
SETTINGS.postSettings.noAnkerPostTextCsvStartRow < 0 &&
SETTINGS.postSettings.replyPostTextCsvStartRow < 0
) {
return kill(
'設定エラー。noAnkerPostTextCsvStartRowとreplyPostTextCsvStartRow両方とも-1になってる。',
);
}
if (
SETTINGS.postSettings.noAnkerPostTextCsvStartRow === 0 ||
SETTINGS.postSettings.replyPostTextCsvStartRow === 0
) {
return kill(
'設定エラー。noAnkerPostTextCsvStartRow/replyPostTextCsvStartRowの初期値は-1或いは1以上で。',
);
}
}
/**
* 入力フォームを表示して入力されたスレのURLを受け取る。
*/
function openPromptThreadUrl() {
const url = prompt('スレURLを入力');
}
/**
* 開いてるスレのレス全て読み取ってPostListインスタンスを作って返す。
* 重すぎるので使うのやめ。どうやらインスタンスの大量生成が原因な模様。
*/
const posts = window.document.getElementsByClassName('post');
return new PostList(Array.from(posts).map((e) => new Post(e)));
}
/**
* 開いてるスレのレス全て取得してPostDOMListに格納して返す。
* @returns
*/
function createPostDOMList() {
const posts = window.document.getElementsByClassName('post');
for (let index = 0; index < posts.length; index++) {
//HTMLCollectionからElementを1つずつ抽出して配列に。
arrPostDOMList.push(posts.item(index));
}
return new PostDOMList(arrPostDOMList);
}
/**
* 開いてる投稿結果画面に表示されてるエラーを読み取ってPostErrorMessageインスタンスを作って返す。
*/
function createPostErrorMessage() {
window.document