お絵かき配信振り返り21~29
めっちゃ動画細切れになった〜〜〜
↓最初の動画
今回描いた絵.
今回一番こだわったのは顔の輪郭の形.
前回描いた絵の顔の輪郭がなんか違和感があったから,直してみた.
↓前回の輪郭.
↓今回の輪郭.
意識したのは直線と曲線の描き分け.
前回と今回の輪郭の描き方を並べるとこんな感じ.
輪郭には直線の部分と曲線の部分があって,特に顎の部分は直線,頬に近づくにつれて曲線になる感じ.
だから,曲線の部分と直線の部分を分ける感じで描いてみた.
(描いてみた.というよりその場の思いつき?)
なんかいい感じになった.というか絵柄が変わった.
まああんまり一気にいろいろ直そうとすると楽しくなくなりそうだから,気長に.
1枚につき1箇所,前よりよくなってればいいかな.前より良い絵を描く必要もない.
手を描くのをサボり続けている. 気が向いたらやる.
goreturns?
golangにはフォーマット(コードの見た目)を綺麗にするgofmt
という開発支援ツールがあり,
それにimportの整理機能をつけたgoimports
というものもある.
それに似たgoreturns
なるものがあったからどういうものか,goimports
と何が違うのかを調べた.
goreturns
パッケージ説明には
This tool adds zero-value return values to incomplete Go return statements, to save you time when writing Go. It is inspired by and based on goimports.
と書いてある.
"based on goimports"だから,goimports
の機能+αみたいな感じ.
+αの部分は, "adds zero-value return values to incomplete Go return statements"で,
0の返り値をつけるべき時につけるようだ.
0を返す時ってどんな時?
たしかC言語では関数が正しく実行された時に0を返す慣習があるというのを聞いたような聞かなかったような.
それについて述べられた記事が調べたらあった.
main関数が正常終了したことをシェルに伝えるためにreturn 0; をするようだ.
シェルの終了ステータス0が正常終了という意味.
ということはgolangで0をreturnするのもC言語のそれと同じ意味があるのか?
違った
ここに張ってあるgif画像をよくみると,
returnの値の不足をゼロ値で補完していることがわかる.
golangにおけるゼロ値とは単に0のことを指すのではなく,
string であれば ""
int であれば 0
bool であれば false
といった変数の宣言をした時に最初に入っている値のことを指していることがわかった.
結論
goreturns
はgoimports
の機能に加えて,returnの値をゼロ値で補完する機能がある.
(結局githubに書いてある文言と同じになった)
JSON, YAML,,, TOML?
webアプリなどを書くにあたって設定情報の格納に使用するデータ構造の形式がいくつかある.
tomlというのを初めて聞いたから調べてみる.
JSON
{ "hoge": { "hoge1": "hoge", "hoge2": "hogehoge", "hoge3": "hogehogehoge" }, "huga: "huga" }
今のところ一番お世話になっている.
YAML
hoge: - hoge1: "hoge" - hoge2: "hogehoge" - hoge3: "hogehogehoeg" huga: "huga"
1回使ったことあるくらい.
toml
[hoge] hoge1 = "hoge" hoge2 = "hogehoge" hoge3 = "hogehogehoge" huga = "huga"
なんかめちゃ読みやすい.実際人が読みやすいように作られているようだ.
golangでTOMLを扱う時はこれを使うと良いかも.
読みやすいけど書き方はなんかいろいろありそう. github.com
構造体とtomlの結び付けする時にデータの構造を想像しづらいからちょっと慣れが必要かも?
参考:
はやおき
時計を起きた時に見えるところにおかない事に加えて,
やりたいことを寝る前に決めておくことで,最近6時か6時半には起きれるようになった.
1限前(10時くらい)に起きてた自分としてはかなりの進歩.
しかし,起きてからスイッチが入るまでに1時間以上はかかる.
ちょっと前まで10時間くらい寝ていたからそのせいかもしれない(ちょっと鬱っぽかったかも??).
朝にコーヒーを飲んだり,シャワーを浴びたりして,どうにか目を覚ましている感じ.
今,布団に入る時間が0時から1時くらいだから,
もう少し早くした方がいいかも.
リモート講義になったことで自分のだらけ具合が露見した感じがある.
通学している時はなんかやってる気になってたのかも.
睡眠についてもそうだが,リモート講義によって得たもの,気づいたことは結構あって,
良い経験になっている.
YouTube Data APIを叩いてみる(導入)
備忘録
このサイトをみると,YouTubeAPIは大まかに
みたいな5つがあって,
今回はYouTubeから動画のタイトルやLive配信の開始時間(これはLive streamingのほうにあるかも)などのDataをとりたいだけだから,
多分「Add YouTube Data」という API を使えば良いだろう.
上記のサイトから辿れるが次の,
YouTube Data API Overview | Google Developers
を参考に進めていく.
Before your start
YouTube Data API を使うにあたっての事前準備事項があるようだ.
Google アカウントの作成.
Google developers consoleにて,プロジェクトの作成.認証情報の取得.
ユーザー認証を必要としていればOAuth2.0認証の実装.
クライアントライブラリを選択.
JSONをしっかり理解.
まずはこいつらを全部クリアしていく.
1. Googleアカウントの作成
割愛.
2. consoleでプロジェクトの作成と認証情報の取得.
コンソールはここからアクセスできる.
プロジェクト作成
Google APIs と書いてあるところの右隣にある下三角を押すとウィンドウがポップアップするから,そこで新しいプロジェクト
を押す.
そうしたら,そこでプロジェクト名やら組織名やらを入力してプロジェクトを作成する.
(3. )Data API を有効化する
認証情報を作成する前に Data API を有効化しておく.
ダッシュボード
タブを選択して, そこでAPI とサービスを有効化
を押す.
そこでYouTube Data API v3を探して有効化すればよい.
認証情報の作成
今回はOAuth2.0認証を使用するから,まずOAuth同意画面の設定をする.
OAuth同意画面
タブを開いて,質問に答える.
次の画面で必要最低限,アプリケーション名を設定して認証情報の作成に進む.
認証情報
タブを選択して,そこで認証情報を作成
を押す.
OAuth2.0認証を使用するからOAuthクライアントID
を選ぶ.
そこで必要情報を埋めて,作成する.
作成できたら,OAuth2.0 クライアントIDの一覧から作成したものを選択し,
そこでJSONをダウンロード
をクリックしてクライアントの情報が書かれたjsonファイルをダウンロード.
ダウンロードしたものをサーバーの任意の場所に置いておく.
(次のサーバー側のOAuth2.0設定をする時に使う)
4. OAuth2.0認証の実装
ここをメインの参考にOAuth2.0認証のサーバー側の設定やらコードやらを書いた.
Using OAuth 2.0 for Web Server Applications | YouTube Data API
使用したものとしては,
のような感じで,サブで参考にしたサイトはこの辺り.
書いたコードは次のような感じ(一部).
package oauth import ( "encoding/json" "fmt" "io/ioutil" "log" "net/http" "github.com/gin-gonic/gin" // mysql is used for gorm. _ "github.com/go-sql-driver/mysql" "github.com/jinzhu/gorm" "github.com/matac42/LiveShare/database" "golang.org/x/oauth2" ) // Conf wraped oauth2.Config. type Conf struct { oauth2.Config } // CredentialInfo store oauth2 access token etc... type CredentialInfo struct { gorm.Model oauth2.Token } // APIInfo include api info from google. type APIInfo struct { Web struct { ClientID string `json:"client_id"` ProjectID string `json:"project_id"` AuthURI string `json:"auth_uri"` TokenURI string `json:"token_uri"` AuthProviderX509CertURL string `json:"auth_provider_x509_cert_url"` ClientSecret string `json:"client_secret"` RedirectURIs []string `json:"redirect_uris"` JSOrigins []string `json:"javascript_origins"` } } // CreateAPIInfo create APIInfo based on apiinfo.json. func CreateAPIInfo() APIInfo { apiInfo := APIInfo{} raw, err := ioutil.ReadFile("/home/ubuntu/Downloads/apiinfo.json") if err != nil { fmt.Println(err.Error()) } json.Unmarshal(raw, &apiInfo) return apiInfo } // CreateConf create oauth2 config structure. func CreateConf() Conf { apiInfo := CreateAPIInfo() conf := Conf{ oauth2.Config{ ClientID: apiInfo.Web.ClientID, ClientSecret: apiInfo.Web.ClientSecret, Scopes: []string{"https://www.googleapis.com/auth/youtube.readonly"}, Endpoint: oauth2.Endpoint{ AuthURL: apiInfo.Web.AuthURI, TokenURL: apiInfo.Web.TokenURI, }, RedirectURL: apiInfo.Web.RedirectURIs[0], }, } return conf } // Google redirect google oathorized page. func (conf Conf) Google(c *gin.Context) { url := conf.AuthCodeURL("state", oauth2.AccessTypeOffline) c.Redirect(http.StatusMovedPermanently, url) } // CallBack fires fn when there was a connection to /callback. func (conf Conf) CallBack(c *gin.Context) { code := GetAuthCode(c) tok := conf.GetAccessToken(c, code) cre := CredentialInfo{} cre.Token = *tok SaveCredentialInfo(cre) } // GetAuthCode get credential code from google. func GetAuthCode(c *gin.Context) string { code := c.Request.URL.Query().Get("code") err := c.Request.URL.Query().Get("error") if err != "" { fmt.Println(err) } // if _, err := fmt.Scan(&code); err != nil { // log.Fatal(err) // } return code } // GetAccessToken get accesstoken from google. func (conf Conf) GetAccessToken(c *gin.Context, code string) *oauth2.Token { tok, err := conf.Exchange(c, code) if err != nil { log.Fatal(err) } return tok } // SaveCredentialInfo is routines for storing credential info to the database. func SaveCredentialInfo(cre CredentialInfo) { db, err := database.SQLConnect() if err != nil { panic(err.Error()) } defer db.Close() db.AutoMigrate(cre) error := db.Create(&cre).Error if error != nil { fmt.Println(error) } else { fmt.Println("success addition access token to db!!!") } }
上から見ていくと,
Google()は認証ページへのリダイレクトを行い,CallBack()でgoogleからのcallbackを処理する.
GetAuthCode()はcallbackで返ってきた認証コードを処理し,
そのコードをGetAccessToken()に渡してAccess Tokenを取りにいく.
最後に取って来たAccess TokenをSaveCredentialInfo()でデータベースに保存する.
そんな感じの流れになっている.
一応,今後何らかのweb アプリケーションにすることを考えて,データベースに保存する形にしておいた.
5. クライアントライブラリの選択
クライアントライブラリはAPIの実装を簡単にする,パッケージみたいなものだと思う.
Client Libraries | YouTube Data API | Google Developers
ここをみるとGoogle API ClientLibrary for go
なるものがあったから,これを使うのだろう.
使ってみて理解が進んだらまた記事にしようかな.
6. Jsonをしっかり理解
完全に理解した.
APIを叩いてみる.
とりあえず今回は,curl で叩く.
Access Token を使ってYouTubeのチャンネル情報を取得してみる.
$curl -H "Authorization: Bearer Access_token" https://www.googleapis.com/youtube/v3/channels?part=snippet\&mine=true
Access_token
のところにAccess tokenを入れればよい.
得られた結果は次の通り(自分のチャンネルの情報).
{ "kind": "youtube#channelListResponse", "etag": "d1bn9VpVzc_sJex25DypsDa7vYI", "pageInfo": { "totalResults": 1, "resultsPerPage": 1 }, "items": [ { "kind": "youtube#channel", "etag": "qcyx0gNQud0DuE68vPz_b5ljXZ0", "id": "UCOiNaZYE2x6LVisRObnbwMQ", "snippet": { "title": "絵又-enomata", "description": "お絵かき練習の記録を残すために,お絵描き練習ライブや練習動画の投稿をしています.", "publishedAt": "2020-05-07T11:37:27Z", "thumbnails": { "default": { "url": "https://yt3.ggpht.com/a/AATXAJyZ3e7eyylr8gkXlKk4tihkVYwxY8G7FTlByg=s88-c-k-c0xffffffff-no-rj-mo", "width": 88, "height": 88 }, "medium": { "url": "https://yt3.ggpht.com/a/AATXAJyZ3e7eyylr8gkXlKk4tihkVYwxY8G7FTlByg=s240-c-k-c0xffffffff-no-rj-mo", "width": 240, "height": 240 }, "high": { "url": "https://yt3.ggpht.com/a/AATXAJyZ3e7eyylr8gkXlKk4tihkVYwxY8G7FTlByg=s800-c-k-c0xffffffff-no-rj-mo", "width": 800, "height": 800 } }, "localized": { "title": "絵又-enomata", "description": "お絵かき練習の記録を残すために,お絵描き練習ライブや練習動画の投稿をしています." }, "country": "JP" } } ] }
チャンネル名やらチャンネル説明やらがJsonで取得できた.
こんな感じのJsonを処理してフロントに持っていけばなんかwebアプリできそう.
夢が広がる.
後述
以前,githubでOAuth2.0認証実装したときはoauth2パッケージを使わなかったが今回は使ってみた.
めっちゃ便利だった.
なんかAPIたたく話よりOAuth2.0実装の話の方が多くなってしまった.
まあ導入だし良いか.
次は "YouTube APIつかってWebアプリ作ってみた" みたいな感じにする.
YouTubeのAPIはとても要素が多く,使えるようになるのも大変そうだと思ったが,
使いどころもたくさんあるだろうから,楽しく覚えていこうと思う.
GET と POST の違い
以前 github api を利用して,ユーザー情報を取得することをした.
その時にGET と POST の違いがよく分からなくなったから,理解しようと思う.
実体をつかむ
マスタリングTCP/IP入門編によると...
マスタリングTCP/IP入門編によると,HTTP通信の主なコマンドは次のようなものがある.
・OPTION・・・オプションの設定
・GET ・・・指定したURLのデータを取得
・HEAD ・・・メッセージヘッダだけを取得
・POST ・・・指定したURIにデータを登録
・PUT ・・・指定したURIにデータを保存
・DELETE ・・・指定したURIのデータを削除
・TRACE ・・・リクエストメッセージをクライアントに戻す
GETとPOSTくらいしか見たことなかった.
GETとPOSTはHTTPコマンドの一つであることがわかった.
HTTPリクエストの中身をちょっと見てみる.
これはとあるHTTPリクエストをdelveで覗いたものである(golangのnet/http.Requestのフォーマット).
(dlv) p req *net/http.Request { Method: "GET", URL: *net/url.URL { Scheme: "https", Opaque: "", User: *net/url.Userinfo nil, Host: "api.github.com", Path: "/user", RawPath: "", ForceQuery: false, RawQuery: "", Fragment: "",}, Proto: "HTTP/1.1", ProtoMajor: 1, ProtoMinor: 1, Header: net/http.Header [ "Accept": [ "application/json", ], "Authorization": [ "bearer *", ], ], Body: io.ReadCloser nil, GetBody: nil, ContentLength: 0, TransferEncoding: []string len: 0, cap: 0, nil, Close: false, Host: "api.github.com", Form: net/url.Values nil, PostForm: net/url.Values nil, MultipartForm: *mime/multipart.Form nil, Trailer: net/http.Header nil, RemoteAddr: "", RequestURI: "", TLS: *crypto/tls.ConnectionState nil, Cancel: <-chan struct {} {}, Response: *net/http.Response nil, ctx: context.Context(*context.emptyCtx) *0,}
MethodのところがGETになっているからGETコマンドを使い,HTTPリクエスト飛ばそうとしていることがわかる.
POSTだったらMethodのところをPOSTにするはず.
GET と POST の違い
https://wa3.i-3-i.info/diff7method.html
大方このサイトの通りの認識で自分も大体は納得していたのだが,
以前 github API を使用してユーザー情報を取得しようとした時に疑問が出た.
上記のサイトの通りだとaccess token などの機密情報はgetではなくpostで送るべきだと思われるが, developer.github.com
このサイトによると,access tokenをgetで送ることになっているのだ.
これではaccess tokenが漏洩してしまうのではと考えた.
しかし調べてみるとそれでも大丈夫な理由がわかった.
このサイトからするに,GETとPOSTで違うのはリクエストボディの部分であって,
GETのセキュリティを心配するのもボディの部分についてであることがわかった.
github のaccess tokenはボディではなくヘッダに載せているから,問題ないということだろう.
だったら何でもかんでもヘッダーで送れば良いのでは
そう思ったが,ヘッダーに乗せて送ることができる情報は決まっていて,
Authorizationヘッダーもしっかり用意されたものであった.
ここにヘッダー一覧があった.
後述
もやがはれた.
お絵かき振り返り14~20
完成作品と動画
合計所要時間: 264分
14 https://youtu.be/8TgLZrmN4_c
15 https://youtu.be/u6u9FbKT0N4
16 https://youtu.be/qVuXVwL10DQ
17 https://youtu.be/pqemagWxtSc
18 https://youtu.be/aMWofyBkVbI
19 https://youtu.be/uz7afhdyh6E
20 https://youtu.be/U2tUJGJwxOU
完成作品を見て
胸のリボンとか帽子の紐とかを描き忘れているのは,
記憶だけで描いたというのと,
急ぎ目で描いたから(前回321min+動画外作業, 今回264min)というのがある.
まだまだ頭の中に大空スバルの像が構築されてないのがわかった(なんか悔しいな).
髪の毛の表面質は今までと比べて,だんだんいい感じになってきてる?
髪全体で見ると少し重たい印象がある.
顔の輪郭はもうちょい丸みを持たせた方がいいかも?
ここで本家のスバルをちょっと見てみる.
スバルって思ったよりまんじゅうみたいな顔してるな.
やっぱり本家は神.めっちゃ可愛い.
次はまんじゅうっぽく描いてみよう.
後述
以前の記事で動画の長さをなるべく短くしていこう,みたいなことを言ったが,難しい.
やっぱり30分以上は描いていたい.
以前の記事.
お絵かきは人生を豊かにする.