Youtubeの最近のオーディオコーデックがOPUSになっている件について

Youtubeの音楽をローカルに保存して聞いてる人は今時いるのでしょうか?
スマホで常時接続の時代になってローカル保存の概念が無くなると思いきや、動画というのはやはりサイズが大きく、大変なパケットを消費します(今風だと「ギガが減る」)。
定額音楽配信も増えてきたとは言え、無い曲ばかりです。

というわけで、Youtubeからのダウンロードは今でも必要なテクニックだと思います。

ブラウザのアドオン、例えばyoutube-dlとか使うのは以前と変わらないのですが、最近になってオーディオコーデックがopusという聞きなれないものになりました。
どうやらその流れは2016年頃からのものらしい。
yuichiro-s.hatenablog.com

youtubeからダウンロードしてるような人達は手慣れたものだと思いますが、まず動画をダウンロードします。
ダウンロードするとwebmやmkv何かの拡張子がついた動画ファイルになります。

大まかな流れはこんな感じ
f:id:miz999:20170812084041p:plain

今回、問題なのは、音声ファイルを再エンコードしないで取り出すパターン。再エンコードのたびに音質が劣化するのでできるだけ再エンコードはしたくない、その結果、youtubeの動画ファイルに使われてる(使われだした)opusという形式の音声ファイルが取り出される。

Opus (音声圧縮) - Wikipedia

で、このopus、新しいファイル形式なのか対応環境が少ない。ウチは普段iTunes(windows)を常用してるのですが、iTunesはダメ(そもそもiTunesはファイル形式にうるさいのだが)、androidiPhoneも対応していることは対応しているという話もあるのだが、何か曖昧。
つまり、使いづらいフォーマットなのである。ちなみにウチではvlcでテスト再生しています。vlcはライブラリ管理としてイマイチなので、あくまでテストのみ。

まぁ、mp3なりaacなりに再エンコードしてやれば、どんな環境でも再生できるのですが、上述のとおりできるだけ再エンコードしたくないのです。
もうiPodも使ってないし、iPhoneは持っていないのでiTunesを捨てる時期なのかもしれません。

windows用の環境を色々探し回って、MusicBeeというのがopusも再生できるのですが、乗り換えに関してはおいおい考えるとして、opusを使う上でのもう一つの問題を。
ここ数ヶ月でGoogle Play Musicを使うようになったのですが、スマホで音楽を聴く環境としてはすこぶる便利であり、最早これなしでは生きていけないほどです。
そんな現在の状況を踏まえて上記の図に追加したのがこれ
f:id:miz999:20170812091237p:plain
これを最終型としてできるだけ再エンコードしないようにしたいのです。
Google側の音声フォーマット対応状況としてはこれ
support.google.com
これを読む限り、どんなファイルもスマホに行き着くまでにmp3になってしまうようです。

ということは、youtubeから手持ちのスマホまで全てopusで通過することは不可能であり、どこかでopus -> mp3の再エンコードを一度に限り入れてやるのが現状のベストのようです。

というわけで、最終的にはこんな感じの流れになりました
f:id:miz999:20170812094123p:plain

youtubegoogle傘下なんだから、Google PlayMusicもopusに対応してほしいものです。

Google App Engine のdatastore readコストを極力まで減らす

だいたいgaeのdatastore関連の問題ってのはwriteのコストに起因することで、そこをイカに減らすかがノウハウ(あるいはバッドノウハウ)なんですが、今作ってるサービスでは珍しくreadのコストが問題になってきました。

で、readのコストを減らす定番が「keyを活用する」ということで、key読み込みだけならばコストは発生しない、ということ。

qiita.comこのあたりを参考にすると、なるほどcountでも1read単位で済むらしい。

q = act_db.query()
logging.info("actress_db count:%s" % q.count())
for a in q.fetch(keys_only=True):
logging.error("id -> %s" % a.id())

このコードのコストは管理コンソールの割当ページで見るところの「Datastore読み取り操作」で1件分である(もしかしたらcountでもう1件で2件かも)。forループのfetchもkeys_onlyなら0件である。当然ループの中でa.get()してしまうとこのループの件数だけreadが発生して大爆発になる。a.id()だけならkey(あるいはIDと言い方もある)を読むだけなので0コスト。

そこでdatastore writeの時にid(key)に意味を持たせてやれば最小コストに近づくというわけである。

keyに意味をもたせるノウハウはこの辺から↓

Google App Engine / Python 上での開発で最初から知ってればよかった、ってことをいくつか - Masatomo Nakano Blog

writeはこれで

act_db(id=nanika_uniq, name=nanika_name).put()

readはこんな

q = act_db.get_by_id(url)

これはentityを返すのでget()も兼ねている。

gqlを使うなら

gql_q = ndb.gql("select __key__ from act_db where __key__ = KEY('act_db', :1)", nanika_uniq)

これはkeyだけ返す。どちらもread1件である。keyだけを返すgqlもreadを食うのが謎であるが、そういうものなんだろう。

で、ここまでが調べればすぐに分かる話である。

今回ハマったのが「readの1件すら惜しい」ケース。keyだけで済むケース、例えば存在確認なんかの場合。

url = "yahoo.co.jp"
q = act_db.query()
for a in q.fetch(keys_only=True):
q = url_db.get_by_id(url) # q is entity
# or q = ndb.gql("select __key__ from url_db where __key__ = KEY('url_db', :1)", url).fetch(keys_only=True) #q is key
# or q = url_db.query(url_db.url == url).fetch(keys_only=True) #q is key
# 上記全てread1件であるのでどれを使っても同じ。keyかentityかの違いはあるが今回はkeyだけ欲しい状況
if q:
shori()

forループの中のget_by_id()はread1件ではあるが、ループの回数だけ塵も積もれば山となる。何しろ無料でreadできるのは5万件しか無い。これを十分と取るか少ないと取るか。

最終的にどうしたかというと、やっぱりmemcacheである。

#全部リードでread1件
q = url_db.query()
for a in q.fetch(keys_only=True):
memcache.set(a.id(), True)
 
url = "yahoo.co.jp"
 
#ここでもread1件
q = act_db.query()
for a in q.fetch(keys_only=True):
if memcache.get(url):
shori()

全部でread2件で済む。

いざ書いてみると、当たり前の話だが、key利用だけではコストが安くならない場合もあるということで、もうひと工夫必要なこともあるということで。

 

#追記

記事公開したら、ソース部分のインデントと改行がおかしくなった。if、forは適宜対応でお願いします。

node.jsのhttpモジュールでutf-8以外のデータをもってくる場合

それくらい標準でやってくれよと思うところもあるのですが外部モジュールでやるもののようです

qiita.com

info-i.net

今回は後者の iconv-liteを使いました。liteのほうが他の依存モジュールが無いので楽。

var iconvLite = require('iconv-lite')
var title = iconvLite.decode(actress_name, "EUC-jp")
console.log(title)

ソースはこんなものですが上手く行きません。文字化けしたままです。

いろいろ調べてみるとどうやらサンプル持ってきたそのままで、今まではutf-8のページばっかり扱ったので上手く行ってただけのsetEncodingがutf8決め打ちがまずいらしい。

var client = http.get(url, function (res) {
var data = ''
if (res.statusCode === 200) {
res.setEncoding('utf8');
res.on('data', function (chunk) {
data += chunk
})
res.on('end', function () {
f(url, data)
})
}

 

 ここを元データの文字コードであるEUC-JPにすると詳しいことはメモらなかったが「知らない文字コード」という類のエラーがでる。

 最終的に上手く行ったのはバイナリを扱うように生データで持ってくるのがいいらしい

res.setEncoding('binary');

その辺の経緯はここのページが参考になる。やっぱり勝手なことしてくれてるのね

qiita.com

それにしても、はてなブログになってから初めてソースコード貼り付けしたが使いにくいことこの上ないな、この「見たまま編集」。貼り付けたソースは色付けとかタブとか修正しようがないみたいなので参考程度に。変な改行とか入ってるし。

便利なようで勝手なことやってくれてるというのは、今回のトラブルと同じか。

markdown記法でも覚えるかな。

 

 

Google Apps Scriptで久々にハマったら、以前のところと同じところでハマってた

ウェブアプリケーションとして公開する場合、修正するたびにバージョンを新規作成しなければ修正が反映されないというのをすっかり忘れてて数時間無駄にした。

気付くきっかけになったのがこのページ

eye4brain.sakura.ne.jp

コードを変更した場合、execのURLに反映させる為には、プロジェクトバージョンを変更し新規作成にしなければコードが反映しません。

 

今後の戒めとしてメモしておく。

 

しかし上記の参考サイトの「嵌まるポイント」の多さからも分かる、Googleサービスの謎の多さというか初見殺しポイントの多さよ。

この辺は日本語ドキュメントや利用者が少ないのか参考ページの少なさよ。

Google App Scriptの保存可能なプロパティ的なもの

Google App Script (以下GAS)で困るのがデータ保存をどうするかということ。

スプレッドシートならデータ用のシートを別に作成して、そこをデータベース代わりに使うらしい。ちなみにログも保存されないので、ログを残したければそういう形式を取るしか無い、不便。せめてログくらい何とかならないものかと思う。スクリプトの手動実行や、トリガー起動でもそのスクリプトのページ開いてて、実行してすぐなら見られるが。

で、使える保存領域としてあるのが、PropertiesService。これを使えばユーザー名何かのちょっとしたものは保存できる。

developabout0309.blogspot.jp

で、このページに書いてあるように

  • getDocumentProperties()
  • getScriptProperties()
  • getUserProperties()

の3つを使い分けるらしい。

自分だけしか見ないし、1番データ漏洩が少なそうなUserProperiesを使いたかったのだが、何故かこれがスクリプト編集画面のファイル->プロパティから編集できなくて不便。

ググっても対処法は見つからず、ダメだよーって情報しか出てこない。それも3年前の。

old-horizon.hateblo.jp

しかしPropertiesService.getUserProperties()で取得できるユーザープロパティはスクリプトエディタのUIからは編集できない、一方でスクリプトプロパティは編集できるという仕様 

 

で、結局、getScriptProperties()を使うことにした。

ちなみに、プロパティに数字(整数)を保存すると浮動小数点つき(小数点以下.0が付く)になるので、それをそのまま取り出して文字列と結合すると.0が残ってしまう。整数と演算すると消える。

この辺はjavascript的に仕方ないのだろうがね。

 

しかしGoogle関連のサービスはほんと日本語の情報が少ない。ただで使えて便利なのに。

 

eスポーツの協会が色々あるのを調べて考える

www.itmedia.co.jp

こんな記事を読み、そういえばeスポーツの団体ってボクシングみたいに色々あった気がして、今回改めて調べてみると色々と面白いことがわかったのでまとめてみると、思わぬ分量になってしまった。まとめサイトとかでやる仕事だった。

 

まず協会は大きくわけて3つある

これら3つを個別に見ていく

 

一般社団法人 日本eスポーツ協会

jespa.org

協会概要 | JeSPA(一般社団法人 日本eスポーツ協会)

役員名簿

会長
西村 康稔(衆議院議員
理事
中村 伊知哉(慶應義塾大学 教授)
理事
馬場 章(元東京大学大学院 教授)
理事
浜村 弘一(カドカワ 株式会社 取締役)
理事
平方 彰(スポーツビジネス・コンサルタント
理事
丸山 茂雄(株式会社 トゥー・フォー・セブン 取締役)
理事
宮澤 栄一(株式会社 ハーツユナイテッドグループ 代表取締役
理事
[新任]尾崎 健介(株式会社 サードウェーブ 代表取締役社長)

 

賛助会員企業

イオンエンターテイメント株式会社
Wikia Japan株式会社
株式会社 エヌ・ティ・ティ・データ
株式会社 カジ・コーポレーション
カドカワ 株式会社
株式会社 テー・オー・ダブリュー
株式会社 電通
東京メトロポリタンテレビジョン 株式会社
株式会社 ハーツユナイテッドグループ
株式会社 博報堂
ぴあ 株式会社
株式会社 フロンティアインターナショナル
株式会社 文化工房
北海道ハイテクノロジー専門学校

最も大きな団体。電通博報堂が協賛しているのが大きい。

 

e-sports促進機構

代表理事 高橋 利幸
理事 浜村 弘一
平  信一
松永 眞理
筧 誠一郎
監事 宗像 紀夫

 

 

fpsjp.net

カドカワははこれにも関わっているしようなので別組織のような下部組織のような感じなのだろう。eスポーツ当事者が語る分裂理由に再三出てくる「目的が別の組織」そのものなのかもしれない。

にしても松永真理って久々に名前聞いたな。調べてみるとまだ昔の名前で業界ゴロで食えてる雰囲気がして何よりです。

 

 日本プロeスポーツ連盟(Japan Pro eSports Federation / JPeF)

日本プロeスポーツ連盟 JPeF

発起人

理事(共同代表)

eスポーツオーガナイザー

  • 鈴木 文雄(株式会社SANKO 代表取締役
  • 松本 順一(ジャパンコンペティティブゲーミング代表)

eスポーツチームオーナー

  • 梅崎 伸幸(株式会社Sun-Gence 代表取締役社長 / DetonatioN Gaming CEO)

監事

 

さて、これが混乱の大本というか、謎の多い組織。組織的にはネームバリュー、資金力ともに弱いが、プレゼンスがあるのは何故か。

 

www.gamespark.jp

組織はSANKOの鈴木文雄代表取締役、Sun-Greenの梅崎伸幸代表取締役マイルストーンJGCの松本順一代表が発起人かつ共同代表理事となり、 ニチカレの小林泰平代表取締役が事務局長に。そしてロジクールの古澤明仁氏が監事を務めます。また、東京アニメ・声優専門学校NVIDIA Japan、テクノブラッドライフカードなども賛同企業として集まり、国会議員のバックアップもあるため、普通の団体ではないことが一目瞭然です。

 

発表会には議員連盟から、公明党の漆原良夫議員と、民進党の松原修平議員が応援に駆けつけました。「若者のこの情熱は政治も受け止めなければならない。この業界が健全に発展するためにもしっかりと応援したい」と漆原議員。 

 

ascii.jp

このビザや景表法といった問題については、行政との連携が不可欠だ。発表会には、今回のビザ取得にも貢献したという、50人以上の議員による超党派の議員 連盟、“オンラインゲーム議員連盟”の代表代行 公明党漆原良夫衆議院議員と、民主党(3月27日より民進党)の松原仁衆議院議員が参列した(会長は自由民主党 河村建夫衆議院議員)。

 

質疑応答の中では、すでにeスポーツ関連の業界団体として発足している、一般社団法人 e-sports促進機構と、一般社団法人 日本eスポーツ協会(JeSPA)との違いについて語られた。 新たに違う団体として発足した理由について、古澤氏によると「お互いスタートの時点でやり たいことが違った」のだという。そのやりたいこととは、e-sports促進機構は「賞金問題の解決」、JeSPAは「JOC加入」だ。とし、「競合する わけではないし、遠回りしていずれいっしょに活動することもあるだろう」と付け加えた。

ビザの取得から見えてくる、政治家との大きな関わりこそがこの組織最大の強みなのだろうか。とはいえ、この「オンラインゲーム議員連盟」とやらの実態がいくら調べても見えてこない。断片的な参加議員はいるのだが、議事録も何もなし。

 

以下、各団体に付いて書かれた記事まとめ

この記事は話題になった、JeSPA主催大会の運営の酷さを糾弾したもの

第1回

note.mu

第2回

note.mu

政治がらみの話も出て来るが、ここで糾弾されているのがJeSPA会長の西村康稔衆議院議員

www.yasutoshi.jpオフィシャルサイトの役職欄には件の「オンラインゲーム議員連盟」は存在しない。どうやら50人を超える超党派議員連盟に参加していないようである。

もちろん「オンラインゲーム議員連盟」というものが存在すればの話だが。

このあたりのことからどうやら政治も一本化されてないんじゃないかと思えてくる。

 

JeSPA設立時の記事、ここで注目すべきは理事に日本のスポーツビジネスを取り仕切る電通スポーツ局の人間がいるところ

理事: 平方 彰(株式会社 電通 スポーツ局 次長)

www.negitaku.org

しかし、現在の理事には名前がない。電通が関わりを薄くしたのか、電通嫌いのネットの感情に配慮したのか。

 

2年前のJeSPAへのインタビュー記事だが、苦労は伺える

「一般社団法人 日本eスポーツ協会(JeSPA)」への質問と回答 | Negitaku.org esports

 

以上、断片的で雑多な羅列になってしまったが、この分裂問題の内部には政治問題(あるいは政治家問題)があって、そこを解決すれば全て上手くいくような気がしてなりません。

今後の流れとしては、どう考えても広告代理店を押さえたJeSPAに一本化されていくのは避けられないでしょう。最初の記事にあるようにスポーツのオフィシャルな大会に食い込むのは2022年からなので東京五輪利権には誰もあやかれないようですが。

 

にしてもオンラインゲーム議員連盟が気になって仕方ない。

 

スマホのイヤホン端子に刺すアレを今更ながら買ってみたが

突如として何となくスマホの水没とかが気になって、イヤホンジャックに刺すフタみたいなのを見てたら、そう言えばちょっと前にイヤホンジャックにハードウェアキーを追加する機能みたいなのあったなと思い出す。

こういうの

実際はAmazonで買わずにebayで買った。ebayで買ったのも、2個100円位の投げ売りしてたからだったりす衝動買いだったりするわけで前後関係はかなりこじれる。

衝動買いというのも、上記のAmazonのレビュー見ても賛否両論だったりするのを読んだからであり、この賛否両論は後から身をもって体験することになる。

ebayからは30日位かかって届く。ebayにしてはまぁ遅いほうだとは思う。ちょっと不安だったけど100円だしね。

 

さてここからが実際に使えるようになるまでの苦闘。

使用機種はHTC J One(HTL22)、古い、OSは4.4だし

まずアプリをgoogle playからインストールしなければならないので、とりあえず一番人気のを入れてみる。

play.google.com

入れたはいいが、どうやらクリックイベントをOS側(?)が受け取っているらしく、ヘッドセットのクリックイベント(再生停止早送りなど)に回されてしまっているようだ。この装置を刺した時に「これはイヤホンですか?」みたいな質問をされるのだが、それに「違います、ボタンです」とキチンと答えてもイヤホンだと認識されてしまっているようだ。

アプリ内部的にはクリックイベントの発生をOSからフックして横取りしてOS側(OSと言うかイベント処理レイヤー?)には渡さないようにしたいのだろうが、それが上手く行ってない感じ。

このアプリはダメだということで、次に人気の

play.google.com

を入れてみるも同じ不具合。シングルクリックで音楽アプリが再生されてしまう。

Amazonのレビューの不満の通りにそういうものなのかと諦めていたが

play.google.com

これを入れたら希望通りの動作をした。

こういう中華系アプリってみんなが同じようなソースで同じように作っているのかと思ってたが、はて、これは相性とかテストとかの問題なのだろうか。

さらなるテストでわかったのだが、ヘッドセットの再生や停止を感知するような音楽系アプリが前面に来ている場合、クリックイベントが音楽アプリに渡ってしまい、再生停止の動作をしてしまうようだ。この辺もフックが上手く行ったり行かなかったりなんだろうな。

 

まぁ総括としては、買わないほうがいいと思います。クリック時の動作もダブルクリックですら上手く拾わない不安定さも有りますし。しかしながら、イヤホンジャックのフタとしては有能だと思います。