twitter API 有料化対応
を行いました。
自動投稿系サービスの移転
NodeJSとVercel Functions(NodeJS)からtwitter APIを叩いている2つのサービスがあり、 いずれもマストドンへ投稿するように以下の記事を参考にマストドンのAPIへと切り替えた。
twitter APIからデータ取得していた部分の廃止
firebaseでtwitterログインを実装しているものの、firebaseのサーバサイドでは
- twitterのID(通し番号)
- 現在の表示名
は取得できるが、twitterのスクリーンネーム(@以降)が取得できなかったため、 twitter APIを用いてスクリーンネームを別途取得していました。
クライアントサイドだとログイン時にfirebaseから渡されるようなのですが、そちらを修正するのはまた工数が要るので...
データベースにFirebaseのUUIDだけ格納しておけば、コンソールから紐づいているアカウントがわかるので、 多少運用の手間が増えますが致し方ないところです。
キャップ野球情報局更新[2.39.0 → 2.39.2]
チームページ/エイリアス・連合表示
チームページにどのチームの別名(alias)なのか、連合チームなのかどうかという表示をするように修正
成績内訳に対戦チームを表示
成績の試合ごとの内訳で試合日付と試合番号のみを表示していたが、対戦チームを表示するように修正
試合ページのカラムで未使用のものを除去
自作PCの構成まるっと変えました(9年ぶり)
久々に自作PCの構成を一から変えました。 光学ドライブと起動以外のHDDはそのまま引越しです。
旧構成 | 新構成 | |
---|---|---|
CPU | Intel Core i7-3770S(3.1GHz/4C/8T) | AMD Ryzen5 5600X(3.7GHz/6C/12T) |
RAM | DDR3 16GB | DDR4 32GB |
M/B | ASUS P8H67-V REV3.0 | MSI B450 GAMING PLUS MAX |
SSD | TOSHIBA 128GB(SATA 6G) | WD 500GB(M.2 NVMe) |
VGA | On Board | GeForce GTX 1050 |
ケース | OWL-612 | ANTEC P10 flux |
Optical | PIONEER BDR-209 | 同左 |
電源 | SilverStone(容量不明) | 玄人志向 650W |
モニタ | 三菱RDT231WM(23.1inch/FHD) | DELL S2721Q(27inch/4K) |
ベンチマークスコアは30%up。 動画エンコードの速度は同じ設定のままで3倍近くになりました。 9年前でもそこそこスペックにこだわって作ったので結構もちましたが、 GW暇過ぎたので思い切って買い替えました。さすがに起動は速くなりました。
AMD Ryzen 5 5600X with Wraith Stealth cooler 3.7GHz 6コア / 12スレッド 35MB 65W【国内正規代理店品】 100-100000065BOX
- 発売日: 2020/11/06
- メディア: Personal Computers
MSI B450 GAMING PLUS MAX ATX マザーボード MB4821
- 発売日: 2019/08/09
- メディア: Personal Computers
CFD販売 デスクトップPC用ゲーミングメモリ CX1シリーズ Intel XMP2.0 サポート PC4-21300(DDR4-2666) 16GB×2枚 無期限保証 W4U2666CX1-16G
- 発売日: 2019/10/12
- メディア: Personal Computers
玄人志向 ビデオカードGEFORCE GTX 1050搭載 GF-GTX1050-2GB/OC/SF
- 発売日: 2016/11/01
- メディア: Personal Computers
Western Digital SSD 500GB WD Blue SN550 PC M.2-2280 NVMe WDS500G2B0C-EC 【国内正規代理店品】
- 発売日: 2020/01/15
- メディア: Personal Computers
Dell S2721Q 27インチ 4K UHD、IPS 超薄型ベゼルモニター、AMD FreeSync、HDMI、DisplayPort、VESA認証、シルバー
- 発売日: 2020/08/21
- メディア: Personal Computers
玄人志向 電源 KRPW-BKシリーズ 80PLUS Bronze 650W ATX電源 KRPW-BK650W/85+
- 発売日: 2018/01/18
- メディア: Personal Computers
react-planetがsafari12系で動かない問題
react-planet
手軽に円形メニュー(Circular Menu)を提供できるライブラリ。
ResizeObserver is not defined
react-planetではリサイズイベントをResizeObseverによって検知しています。
ただし、ResizeObserverはsafari 13.1以降に対応しています。 手元にあるiPhone5Sはsafari12系でした。
react-planet ┗ use-resize-observer ┗ resize-observer-polyfill
今回、おそらく動いていないのはresize-observer-polyfillのようです。 きちんとメンテされてそうなのはこれ。 resize-observer
ただ、use-resize-observerのソースを書き換えて、 react-planetのdependencyも変えないといけないので一旦調査してエラー回避する方向で終了。
TopMenuコンポーネントの中でreact-planetを使っています。
{typeof ResizeObserver !== 'undefined' ? <div id="topMenu"> <TopMenu/> </div> :<></> }
キャップ野球情報局v2.0リリースしました。
「キャップ野球情報局」というサイトを作っています。
アップデート履歴
- 2019年12月
- 2020年1月
ちまちまとマイナーアップデートを重ねていましたが、 5/17からNextJSへ移植するのと同時に、次のメジャーアップデート(v2.0)を7月リリースを目標に作っています。
次バージョン新機能
twitterアカウントを持っていれば誰でもログインできます。
マイページ
ユーザページ編集
別サービス「みんなのSCORE」のデータに対応する形で選手ページを持っています。
選手へのコメント機能
選手間で「この選手はどういう選手です」という他己紹介をする機能です。
チームページ編集
別サービス「みんなのSCORE」のデータに対応する形でチームページを持っています。 チームの紹介のほか、チームのテーマカラーが設定できます。
イベント登録・編集
キャップ野球には、主なイベントとして
- 大会
- リーグ
- 練習会
がありますが、それらの情報を登録・編集することができます。
次バージョンに採用している技術
- フロント
- NextJS
- ReactJS
- Netlify
- TypeScript
- サーバサイド
- NodeJS
- MySQL
- Docker(-compose)
- TypeScript
- ミドルウェアなど
- slack
- firebase
- cloudinary
imgurではなくcloudinaryを採用した理由
運営者ギルドでは画像ストレージとしてimgurを薦められていたのですが、imgurとcloudinary両方を実装して、使いやすさの観点からcloudinaryを採用することにしました。
ログイン
imgurはOAuth認証すればログイン状態でアップロードできるのですが、ブラウザでPINが必要など使い勝手と実装に難がある印象です。
匿名アップロード
比較的実装が簡単ですが、imgurでは匿名アップロードした画像をGUIでは管理できません。
工数的にはcloudinaryのログイン状態アップロード≒imgurの匿名アップロードという印象だったので、GUIで全体管理ができるcloudinaryを選びました。用途としては無料枠で足りると思います。
React/NodeJS/Passportでtwitterログインを実装してみた
こちらの記事をベースにしてReactJS/NodeJSのシステムにtwitterログインを組み込んでみた。 qiita.com
主に異なるのは型指定が緩めななんちゃって
typescriptを使っているところか。
蓋々交換機能
技術的なこと
passport-config.ts
export default function passportConfig() { var TWITTER_CONSUMER_KEY = "*****"; var TWITTER_CONSUMER_SECRET = "*******"; var passport = require("passport"), TwitterStrategy = require("passport-twitter").Strategy; // Sessionの設定 passport.serializeUser(function (user, done) { done(null, user); }); passport.deserializeUser(function (obj, done) { done(null, obj); }); passport.use( new TwitterStrategy( { consumerKey: TWITTER_CONSUMER_KEY, consumerSecret: TWITTER_CONSUMER_SECRET, callbackURL: "https://********/auth/twitter/callback", }, function (token, tokenSecret, profile, done) { passport.session.user = profile; // tokenとtoken_secretをセット profile.twitter_token = token; profile.twitter_token_secret = tokenSecret; process.nextTick(function () { return done(null, profile); }); } ) ); }
auth.ts
NodeJSでtwitter認証からのコールバックなどを担当するコントローラ。
import * as express from "express"; import * as session from 'express-session'; import { Request } from "./interface/express.Request"; const passport = require("passport"); export class Auth{ public router: express.Router; constructor() { this.router = express.Router(); this.router.get("/twitter", passport.authenticate('twitter')); this.router.get("/twitter/success", this.success); this.router.get("/twitter/callback", passport.authenticate('twitter', { successRedirect: 'https://******/api/v2/auth/twitter/success', failureRedirect: 'https://******/' }) )} private success(req:Request,res:express.Response):void{ if(req.session.passport !== undefined){ res.json(req.session.passport.user.username); }else{ res.sendStatus(401); } } }
express.Requestインターフェースの拡張
import * as Express from 'express'; export interface Request extends Express.Request { session:any; }
app.ts
import { Auth } from './auth'; import * as session from 'express-session'; import passportConfig from './passport-config'; passportConfig(); const passport = require("passport"); app.use(passport.initialize()); app.use(passport.session()); app.use( session({ secret: '********', resave: false, saveUninitialized: false, cookie:{ httpOnly: true, secure: true, maxage: 1000 * 60 * 30 } }) );
ReactでNodeJS/Passportから認証情報を受け取る
credentialsオプションが必要。
const response = await fetch('/auth/twitter/success', { method:'GET', credentials: "include", headers: { Accept: "application/json", "Content-Type": "application/json", "Access-Control-Allow-Credentials": true } });
認証が終わったタイミングで認証情報を受け取る
認証のためのウインドウを開き、 そのウインドウが閉じられたタイミングで親の画面をリロードする。 リロードの際に認証情報を受け取っている。
onClick={()=>{ const authWindow = window.open('/auth/twitter','newTab'); var timer = setInterval(function() { if(authWindow.closed) { clearInterval(timer); window.location.reload(); } }, 1000); }}
OSSコミットは難しい
FacebookのメッセンジャーlikeなUIの実装をしていて、 以下のライブラリを使っているのですが、 github.com このうちChatListというコンポーネントで、どの相手を選択しているかという状態をコンポーネントが持っていなかったため、 このコンポーネントだけスクラッチで作る羽目になりました。
選択した場合は背景色を変えます。
<div style={{ backgroundColor: store.getState().target === store.getState().messageSummary[i].target_user ? "#dddddd" : "white", margin: 3, padding: 10, cursor: "pointer", height: 72, whiteSpace:'nowrap' }}
Pull Requestとか出せればいいのだけど、割と独自実装なので無理。