SteamDeck疑似環境の構築方法

(2022/08/04追記:一番後ろに、SteamDeck用LinuxのSteam OSとそれを他機種でも使えるように細工したものの紹介を追加)

Steam Deckという手持ちゲーミング端末がリリースされる予定になっている。

現状は一部の開発者向けに実機の提供が行われているが、それ以外のPCでもSteam Deckで使われるManjaro Linux OSをインストールすることで検証ができるように公式の手順が公開されていた。

Developing for Steam Deck without a Dev-Kit

書いてある内容を要約すると・・・

ハードウェア構成

本体:MINISFORUM Elite Mini UM700 (日本代理店 Linksの製品紹介)の Ryzen 7 3750H 搭載モデル

AmazonのMINIFORUM直販より、日本代理店Links直販が安い場合も・・・


ディスプレイ:7インチで1280*800のカーナビ液晶を流用しているものを適当に調達

コントローラ: PS4コントローラかPS5コントローラが最適。XBOXやスイッチ用も使えなくは無いが、トラックパッドがないためフル機能が使えないことに注意。

以前売ってたSteam純正コントローラについては触れられてない・・・

OS設定について

Manjaro LinuxのKDE Plasmaエディションをインストールする。

注:実際にはGPD Pocketでインストールしてみたが、画面キャプチャが面倒だったので、以降の手順は仮想環境で行ったもので代用している。

インストーラで起動すると、下記の様に表示される

環境に合わせて「tz(タイムゾーン)」「keytable(キーボード配列)」「lang(表示言語)」を選び、「Boot with ~」を選ぶ。どっちがいいかは環境による?

しばらく待つとKDEデスクトップが表示される。

この状態でsteam導入もできなくはないのだが、起動ごとに毎回設定がやり直しになるので推奨しない。(OSアップデートがあると警告が表示されたりするが、再起動すると消えるので毎回表示される)

内蔵ディスクや、さらに別途用意したUSBメモリなどへインストールをした方が良い。

インストールはデスクトップ上の「Install Manjaro Linux」をクリックして、インストーラを進めていく。

標準では「スワップを使用しない」が設定されているが、どちらの方がいいんだろうか?(使用しないで進めた)

ゲーミング用途なら、パスワードなしの自動ログイン想定かなぁ?と

インストールを開始します。

…?

FAT32パーテーションを作成した後のLinuxパーテーション作成に失敗している?

パーテーション容量を最大サイズから少し減らしたらインストールが始まった・・・(パーテーション設定のキャプチャなし)

インストール完了

内蔵ディスクから起動しているのでデスクトップ上にInstallのアイコンが消えています。

つづいて、steamのセットアップを実施

左下の「m」メニューから「ゲーム」の「Steam (Runtime)」を選択するか

デスクトップ上で右クリックメニューにある「Show KRunnner」を選択

表示されるウィンドウに「steam」と入力して「アプリケーション Steam(Runtime)」を選択します。

そうするとデスクトップ上に「Steam (Runtime)」アイコンが追加され、Steam setupが開始されます。

セットアップではいろいろダウンロードが行われていきます。

いろいろ処理しているウィンドウが表示されなくなったらダウンロードが終わりなようで、改めてデスクトップ上の「Steam (Runtime)」をクリックすると、Steamのログイン画面が表示されます。

steamにログインすると、まあ、普通に表示されます。

最初に「Steam」の「Settings」を開きます。

「Interface」のlanguageを「日本語(Japanese)」に変更

「Steam Play」の「Enable Steam Play for all other titles」にチェックを入れて、Windowsエミュレーション機能を有効にします。

この設定でいろんなゲームがインストール可能な状態となります。

インストールを選ぶと選択したゲームの他に「Proton(Windowsエミュレーション機能)」と「Steamworks Common Redistributables」のダウンロードが始まります。

ダウンロードが終わり「プレイ」を選択します。

そうすると、「プラットフォーム互換ツールを使用して、このゲームをSteam Playで起動します」というメッセージが表示されます。

ゲームによっては起動前に Microsoft VC Redist Packageインストールなどの処理も実行されます。

やっかいな事に、こういった共有ライブラリが必須であるにも関わらず、特に設定されていないゲームの場合は、プレイボタンを押しても開始に失敗してしまいます。(そういうゲームで起動失敗した場合は何も表示されず、ただゲーム一覧のプレイボタンが再度押せるように戻っていることで察する、という感じ)

なお、仮想環境上での検証は下記の様な感じでDirectX11が上手く動かずに失敗となりました。

GPD Pocket 1で実験した所、FF3は実用的な速度で動作

A列車でいこう9は、かなり遅いものの動く

ライザのアトリエについては、タイトル画面までは出たものの、それ以後の画面は表示できず、という状態でした。


2022/08/04追記

SteamOSとその類似OS

Steam公式にある「自分だけのSteam Machineを組み立てる」はDebian 8ベースの古いSteam OSを使った説明

SteamOS 2.195 リリースノート(2019/07/18)

SteamDeck用のSteamOS 3.xはリカバリイメージとしての提供となっており「Steam Deckリカバリー手順」から入手可能

SteamOS 3.2リリースノート(2022/05/27)
SteamOS 3.3リリースノート(2022/08/03)

Steam Deckリカバリイメージは8GBのUSBメモリに書き込む形式のものとなっているが、vSphere環境上で起動してみようとしたが、うまくいかなかった。

Steam OSのバグについては https://github.com/ValveSoftware/SteamOS/issues から行える。

Steam Deckの内部構造について「Steam Deck Guide」にまとまっている。また、SteamOS相当の機能を他機種でも使えるようにしたLinuxについても紹介されている。

HoloISO

公式: https://github.com/theVakhovskeIsTaken/holoiso

Steam OS 3.xと同じArch Linuxをベースに作られているもの。

SteamDeckと同じAMD系GPUだけではなく、Intel UHD 630+ iGPUや、NVIDIA GTX 9xx GPUでも動く

Nobara Project

公式: https://gitlab.com/GloriousEggroll/nobara-images

こちらはFedora をベースにSteam OS的な機能を盛り込んだもの

ISO生成スクリプトを配布しているだけであるため、ISOファイルをつくるのは別のFedora OSが起動しているサーバで必要なパッケージをインストールした上でスクリプトを実行する必要がある。

winesapOS

公式: https://github.com/LukeShortCloud/winesapOS

USBメモリで起動して使うことを想定したもので、Intel Macでの動作もするらしい。

PlayStation4でLinuxを起動するプロジェクトと組んでPS4上でSteamゲームで遊ぶなんてこともできるらしい。→「WinesapOS 3, based on SteamOS 3 for PS4 with Mesa 22.0.3: PS4 Distro Release

USBメモリから起動する、というあたりはBatocera Linux を使っているようだ

会津バスのスマートバス停を見てきた(PAPERCAST製品利用例

2018年2月に会津バスでスマートバス停が実証試験を始めるというニュースがあった。

(注: 2022年5月時点では物理的に設置はされているものの稼働していませんでした。詳しくは後述)

インプレス:「会津バスに「スマートバス停」、KDDIなど導入支援――LPWA・電子ペーパー活用で外部電源不要
みちのりホールディングズ:「みちのりホールディングス(会津バス)など会津若松市内で国内初となる次世代スマートバス停の実証実験を開始
会津バス:「会津若松市内で国内初となる次世代スマートバス停の実証実験を開始します。

2018年2月17日より運用を始め、設置した2種類をベースに新しいものを2018年4月から1年間で開発する、的なリリースになっていた。

さすがにもう無くなったかな?と会津バスのtwitterアカウントに聞いて見たところ、実用化に課題があるため実証期間を延長し、まだ運用されているとの回答をもらったので見に行ってみた。

まず、見に行ったのは神明通りバス停。

ちょっと離れたところから、会津若松駅方面のバス停をみたところ、なさそうに見えたので、TSUTAYA前の鶴ヶ城方面のバス停を見てみる。

めっちゃ普通のバス停しかない。

おやー?と思ってもう1回会津若松駅方面のバス停の方を見てみると・・・

おや?奥にもう1つバス停がある?

ありました。

2連タイプのバス停です。

ただし、バスロケーションシステムは稼働していませんでした。

まず、時刻表の表示位置が低すぎるのと、文字が細すぎるの2点があるため、バス停の前でしゃがまないと時刻表を読むのが困難でした。

そして、しゃがんでもなお、注意書きとか細かな経路違い表示とかの文字が小さすぎるし、文字の濃淡が薄すぎて読めない・・・

スマートバス停の後ろ側に普通の時刻表がありましたが、こっちのがハッキリしてて見やすいですね。

横に出てるのはLWPAのアンテナなのかな?

ここについているカメラは何の役割なのかな?

バス停の前に立ったらE-Ink表示のリフレッシュが走ったので人感センサーを兼ねてたりするのかな?

時刻表の下にある銀色の丸スイッチを押すと画面のリフレッシュ処理が実行されました。

続いて、鶴ヶ城入口のバス停まで移動・・・

こちらは会津若松駅から来るバスが止まるバス停にありました。

こちらの1画面タイプは、時刻表の表示位置も適切で、表示内容も比較的見やすい感じでした。

よこからみるとこれくらいの大きさで、まぁ、実際に設置するならこれくらいがいいんじゃないかなぁ、と感じました。

こちらのバス停は「PAPERCAST」というロゴが入っていました。

調べて見ると「PAPERCAST E-Paper Bus Stop Passenger Information Display」という既存製品でした。

2画面タイプのもとになっているのでは?というものもありました。

元々WiFi/3G/LTEモジュールを組み込む前提の製品なようで、会津バスで導入するにあたり、LWPAモジュール連動と日本語表示カスタマイズを行ったようです。

PAPERCAST掲載のサンプル例には、日本のマス目レイアウトの1日の全体を表示するような時刻表は無く、次のバスまで何分、というものばかりでした。

顧客が必要なのは「次のバスまで何分」という表示を実現するには液晶だと電力消費が大きいので、E-Inkにする、という感じなのが、もともとのPAPERCAST製品のありかたであるようです。

日本みたいな1日全体の時刻表示のニーズがあまりないんでしょうかねぇ?

1日全体を表示するにはスペースがキツイ、という感じですね。

ちなみにPAPERCAST製品としては、使用するE-Inkディスプレイも、9.7インチ、13.3インチ、23インチ、32インチ、42インチ、57インチが選択できるようです。

このうち32インチモデルはカラー表示も可能なようです。

ハードウェアとしては問題なさそうですが、ソフトウェア面の課題が大きそうです。

はたして本格稼働はいつになることやら?


2022年5月時点の状況について

2022年5月4日に会津若松を訪れた際に現況を確認したところ、どちらのバス停も稼働していませんでした。

鶴ヶ城入口 バス停

神明通り バス停

何も考えずにASUS PRIME B450M-Aで安いDDR4 DIMMを4枚指ししようとしたら認識しなかった件

そろそろ値上がるという評判なので、2月に導入したRyzen 3環境のメモリを増やそうとした。

クロックアップしないし、8GBだから大丈夫だろう、となんも考えずに安く売ってたKLEVV IM48GU88N26-GIIHA0(2枚で5333円)を購入。

いままで使っていたpanram W4U2666PS-8GC19と並べて見る。

基板は一緒。RAMチップが違うだけ、という感じ。

これはいけるな、と4枚指ししてみると、起動しない。

メモリ速度を2400MHz固定にしたり、いろんな組み合わせを試してみたりした結果、3枚までは起動した。4枚がどうしても起動できない。

(元々はA1とB1がPanramの2枚指しで、上記以外にもA1とB1:Panram/A2とB2:KLEVVとか全組み合わせをやってます)

ASUS PRIME B450M-A メモリ対応リスト」を確認してみて原因判明・・・

PANRAMの方は4DIMM対応になっているが、KLEVVの方は型番の下の方がちょっと違うので同じとは言いがたいが2DIMM対応までになっている。

というわけで、駄目そうなので、他に転用しました・・・

Steam版Blenderをインストールしたけど拡張子.blendの関連付けが行われない

Steam版Blender」が無料になっていたので入手してインストールした。

従来のBlenderもインストールしていたので、アプリケーション一覧だと以下のような感じになっていた。(上がSteam版)

デスクトップ上のアイコンだと下側の「Blender」がSteam版。

Blenderアプリのバージョンアップを自動で行いたいからSteam版Blenderをインストールしたので、従来版Blenderのアンインストールをしたところ問題が発生。

拡張子.blendの関連付けがなくなってしまった。Steam版Blenderもアンインストールし、Steam版Blenderだけを再インストールしてみても関連付けを行ってくれない。

検索したところ「.blend file association」にて対処方法を発見。

1. Library -> Software
2. Right Click “Blender” -> Properties -> Set Launch Options
3. Add “-R” without quotes
4. Hit OK
5. Launch Blender
6. You should see a command prompt window and a message saying “File extension registered for the current user. To register for all users, run as an administrator.”
7. Hit OK
8. Right Click “Blender” -> Properties -> Set Launch Options
9. Remove “-R”
10. Double click any .blend file and it should open with the Steam Blender version

Steamアプリの中からSteam版Blenderを起動する際、1回だけ「-R」オプションをつけて起動することで関連付け処理が行われる、とのこと。

これを実行してみたら問題なく動作するようになった。

コマンド(python)でyoutube動画をアップロードする手法

YouTube Data API(v3)の「Videos: insert」に記載されているJava/.Net/PHP/Python/Rubyのサンプルから、とりあえずPythonを選択。

ちょっと前のWeb記述を見ると、10分以上の動画がアップロードできない、的なことを書いているものもあるけれど、このWebの冒頭に「最大ファイルサイズ: 64 GB」とのことなので、大丈夫だろうと判断。

とりあえずそのままコピー(2021/04/07に確認したところ、”Developer Console”が”API Console”に名称変更してたり、エラー処理手法が若干追加された程度の差異がありましたが根本は同じでした)

#!/usr/bin/python

import httplib
import httplib2
import os
import random
import sys
import time

from apiclient.discovery import build
from apiclient.errors import HttpError
from apiclient.http import MediaFileUpload
from oauth2client.client import flow_from_clientsecrets
from oauth2client.file import Storage
from oauth2client.tools import argparser, run_flow


# Explicitly tell the underlying HTTP transport library not to retry, since
# we are handling retry logic ourselves.
httplib2.RETRIES = 1

# Maximum number of times to retry before giving up.
MAX_RETRIES = 10

# Always retry when these exceptions are raised.
RETRIABLE_EXCEPTIONS = (httplib2.HttpLib2Error, IOError, httplib.NotConnected,
  httplib.IncompleteRead, httplib.ImproperConnectionState,
  httplib.CannotSendRequest, httplib.CannotSendHeader,
  httplib.ResponseNotReady, httplib.BadStatusLine)

# Always retry when an apiclient.errors.HttpError with one of these status
# codes is raised.
RETRIABLE_STATUS_CODES = [500, 502, 503, 504]

# The CLIENT_SECRETS_FILE variable specifies the name of a file that contains
# the OAuth 2.0 information for this application, including its client_id and
# client_secret. You can acquire an OAuth 2.0 client ID and client secret from
# the Google Developers Console at
# https://console.developers.google.com/.
# Please ensure that you have enabled the YouTube Data API for your project.
# For more information about using OAuth2 to access the YouTube Data API, see:
#   https://developers.google.com/youtube/v3/guides/authentication
# For more information about the client_secrets.json file format, see:
#   https://developers.google.com/api-client-library/python/guide/aaa_client_secrets
CLIENT_SECRETS_FILE = "client_secrets.json"

# This OAuth 2.0 access scope allows an application to upload files to the
# authenticated user's YouTube channel, but doesn't allow other types of access.
YOUTUBE_UPLOAD_SCOPE = "https://www.googleapis.com/auth/youtube.upload"
YOUTUBE_API_SERVICE_NAME = "youtube"
YOUTUBE_API_VERSION = "v3"

# This variable defines a message to display if the CLIENT_SECRETS_FILE is
# missing.
MISSING_CLIENT_SECRETS_MESSAGE = """
WARNING: Please configure OAuth 2.0

To make this sample run you will need to populate the client_secrets.json file
found at:

   %s

with information from the Developers Console
https://console.developers.google.com/

For more information about the client_secrets.json file format, please visit:
https://developers.google.com/api-client-library/python/guide/aaa_client_secrets
""" % os.path.abspath(os.path.join(os.path.dirname(__file__),
                                   CLIENT_SECRETS_FILE))

VALID_PRIVACY_STATUSES = ("public", "private", "unlisted")


def get_authenticated_service(args):
  flow = flow_from_clientsecrets(CLIENT_SECRETS_FILE,
    scope=YOUTUBE_UPLOAD_SCOPE,
    message=MISSING_CLIENT_SECRETS_MESSAGE)

  storage = Storage("%s-oauth2.json" % sys.argv[0])
  credentials = storage.get()

  if credentials is None or credentials.invalid:
    credentials = run_flow(flow, storage, args)

  return build(YOUTUBE_API_SERVICE_NAME, YOUTUBE_API_VERSION,
    http=credentials.authorize(httplib2.Http()))

def initialize_upload(youtube, options):
  tags = None
  if options.keywords:
    tags = options.keywords.split(",")

  body=dict(
    snippet=dict(
      title=options.title,
      description=options.description,
      tags=tags,
      categoryId=options.category
    ),
    status=dict(
      privacyStatus=options.privacyStatus
    )
  )

  # Call the API's videos.insert method to create and upload the video.
  insert_request = youtube.videos().insert(
    part=",".join(body.keys()),
    body=body,
    # The chunksize parameter specifies the size of each chunk of data, in
    # bytes, that will be uploaded at a time. Set a higher value for
    # reliable connections as fewer chunks lead to faster uploads. Set a lower
    # value for better recovery on less reliable connections.
    #
    # Setting "chunksize" equal to -1 in the code below means that the entire
    # file will be uploaded in a single HTTP request. (If the upload fails,
    # it will still be retried where it left off.) This is usually a best
    # practice, but if you're using Python older than 2.6 or if you're
    # running on App Engine, you should set the chunksize to something like
    # 1024 * 1024 (1 megabyte).
    media_body=MediaFileUpload(options.file, chunksize=-1, resumable=True)
  )

  resumable_upload(insert_request)

# This method implements an exponential backoff strategy to resume a
# failed upload.
def resumable_upload(insert_request):
  response = None
  error = None
  retry = 0
  while response is None:
    try:
      print "Uploading file..."
      status, response = insert_request.next_chunk()
      if 'id' in response:
        print "Video id '%s' was successfully uploaded." % response['id']
      else:
        exit("The upload failed with an unexpected response: %s" % response)
    except HttpError, e:
      if e.resp.status in RETRIABLE_STATUS_CODES:
        error = "A retriable HTTP error %d occurred:\n%s" % (e.resp.status,
                                                             e.content)
      else:
        raise
    except RETRIABLE_EXCEPTIONS, e:
      error = "A retriable error occurred: %s" % e

    if error is not None:
      print error
      retry += 1
      if retry > MAX_RETRIES:
        exit("No longer attempting to retry.")

      max_sleep = 2 ** retry
      sleep_seconds = random.random() * max_sleep
      print "Sleeping %f seconds and then retrying..." % sleep_seconds
      time.sleep(sleep_seconds)

if __name__ == '__main__':
  argparser.add_argument("--file", required=True, help="Video file to upload")
  argparser.add_argument("--title", help="Video title", default="Test Title")
  argparser.add_argument("--description", help="Video description",
    default="Test Description")
  argparser.add_argument("--category", default="22",
    help="Numeric video category. " +
      "See https://developers.google.com/youtube/v3/docs/videoCategories/list")
  argparser.add_argument("--keywords", help="Video keywords, comma separated",
    default="")
  argparser.add_argument("--privacyStatus", choices=VALID_PRIVACY_STATUSES,
    default=VALID_PRIVACY_STATUSES[0], help="Video privacy status.")
  args = argparser.parse_args()

  if not os.path.exists(args.file):
    exit("Please specify a valid file using the --file= parameter.")

  youtube = get_authenticated_service(args)
  try:
    initialize_upload(youtube, args)
  except HttpError, e:
    print "An HTTP error %d occurred:\n%s" % (e.resp.status, e.content)

そして実行!

-bash-4.2$ ./youtube-upload
Traceback (most recent call last):
  File "./youtube-upload", line 4, in <module>
    import httplib2
ImportError: No module named httplib2
-bash-4.2$

CentOS7に必要なPythonモジュールが入っていませんでした。もう1つエラーになったoauth2clientとともに「yum install python-httplib2 python2-oauth2client」でインストールして再実行。

-bash-4.2$ ./youtube-upload
Traceback (most recent call last):
  File "./youtube-upload", line 10, in <module>
    from apiclient.discovery import build
ImportError: No module named apiclient.discovery
-bash-4.2$

今度のエラーのapiclientは「YouTube API: Client Libraries」に含まれるもの。

Python用は「https://github.com/googleapis/google-api-python-client」にある手順に従いインストールする。

ドキュメントには「pip install –upgrade google-api-python-client」とあるけど、「pip install google-api-python-client」で実行した。

[root@server ~]# pip install google-api-python-client
Collecting google-api-python-client
  Downloading https://files.pythonhosted.org/packages/5b/ba/c4e47e2fdd945145ddb10db06dd29af19b01f6e6d7452348b9bf10375ee9/google-api-python-client-1.7.9.tar.gz (142kB)
Installing collected packages: pyasn1, pyasn1-modules, cachetools, rsa, google-auth, google-auth-httplib2, uritemplate, google-api-python-client
  Running setup.py install for google-api-python-client ... done
Successfully installed cachetools-3.1.1 google-api-python-client-1.7.9 google-auth-1.6.3 google-auth-httplib2-0.0.3 pyasn1-0.4.5 pyasn1-modules-0.2.5 rsa-4.0 uritemplate-3.0.0
You are using pip version 8.1.2, however version 19.1.1 is available.
You should consider upgrading via the 'pip install --upgrade pip' command.
[root@server ~]#

で、改めてスクリプトを実行してみる。

-bash-4.2$ ./youtube-upload --file /mnt/work/fuuka/223779_20190618-0013_best.mpg
The client secrets were invalid:
('Error opening file', 'client_secrets.json', 'No such file or directory', 2)

WARNING: Please configure OAuth 2.0

To make this sample run you will need to populate the client_secrets.json file
found at:

   /mnt/work/youtube/client_secrets.json

with information from the Developers Console
https://console.developers.google.com/

For more information about the client_secrets.json file format, please visit:
https://developers.google.com/api-client-library/python/guide/aaa_client_secrets

-bash-4.2$

当然のエラー。

client_secrets.json というファイルに認証情報を記載しなければならないようだ。

Google API Console」にアクセスして、新規プロジェクトを作成。
認証情報タブから「OauthクライアントIDの作成」を選び、「アプリケーションの種類:その他」で作成します。
作成すると、jsonファイルがダウンロードできようになりますので、それをダウンロードし、client_secrets.json という名前で保存します。

「./youtube-upload –file ファイル名 –noauth_local_webserver」と実行すると、URLが表示されます。このURLをブラウザに入力すると、Googleの認証が要求されますので、パスワードを入力します。( –noauth_local_webserver を指定しない場合、そのLinux上でブラウザが開かれます。Oauth認証にはJavaScript対応ブラウザを使う必要があるため、CLIだと無理です。)


認証が完了するとVerification codeがブラウザ上に表示されますので、それをコピーし、コマンドに入力します。

また、下記の様なメールがGoogleアカウントのメールに届きます。(「youtube upload by osakanataro」という文字列は、Google API Consoleで設定したものです)

これで認証が終わると、ファイルアップロードが出来るようになります。

-bash-4.2$ ./youtube-upload --file /mnt/work/fuuka/223779_20190618-0013_best.mpg  --noauth_local_webserver
Uploading file...
Video id 'IAHhZlSXoDk' was successfully uploaded.
-bash-4.2$

Youtube studioにアクセスして状態を確認。

何も設定してなかったので「Test Title」「Test Description」となっていますね。

続いて指定した場合

-bash: ./youtube-upload --file: そのようなファイルやディレクトリはありません
-bash-4.2$ ./youtube-upload --file /mnt/work/fuuka/223779_20190617-1738_best.mpg --title "紫吹ふうか 2019年06月17日 17:38開始配信" --description "紫吹ふうか さ んによる 2019年06月17日 17:38 に開始された配信の転載です。" --keywords "AVATAR2.0","紫吹ふうか"
Uploading file...
Video id '5-Z0YDv5YCk' was successfully uploaded.
-bash-4.2$

Youtube Studioを確認すると、指定したタイトル、説明、タグ(Keywords)が設定されていることがわかります。

あとはサムネ調整とかが必要という感じですね。

つまりは、これで、配信終わったら即座にyoutubeにアップロードするスクリプトが組めたわけでして・・・


2019/06/20追記

まとめて動画をいくつかアップロードしてみたところ、Youtube側のエラーとなりました。

$ ./youtube-upload --file /mnt/work/ramyon/223697_20190614-2028_best.mpg --title 'とみじroooom!!!!!! 2019年06月14日 20:28開始配信' --description "都三代らみょん さんによる showroomにて 2019年06月14日 20:28 に開始された配信の転載です。" --keywords "AVATAR2.0","都三代らみょん"
Uploading file...
An HTTP error 403 occurred:
{
 "error": {
  "errors": [
   {
    "domain": "youtube.quota",
    "reason": "quotaExceeded",
    "message": "The request cannot be completed because you have exceeded your \u003ca href=\"/youtube/v3/getting-started#quota\"\u003equota\u003c/a\u003e."
   }
  ],
  "code": 403,
  "message": "The request cannot be completed because you have exceeded your \u003ca href=\"/youtube/v3/getting-started#quota\"\u003equota\u003c/a\u003e."
 }
}

$ echo $?
0
$

YouTube DATA APIのquota」を見てみると、Developer Consoleで確認する必要があるようです・・・

スクリプト的には5回実行して、合計で4時間半ぐらいの動画をアップロードしただけなのですが、1回あたり結構な数のAPIが発行されているようです。

1日あたり10000回以上に増やすには申請する必要があるようです。