はじめに ※※※信頼されたドメインは動的に作成できるようになるらしいのでAWS部分内容を割愛しました※※※ ※※※上記機能実装後AWSを挟まない形で実装しなおす予定※※※
本記事はVRChat内の動画プレイリストの内容をスプレッドシートで管理する方法についての解説です。 対象のVideoPlayerはKineL式VideoPlayerです。
スプレッドシートの内容はAPIを通じて公開されることになります。 また、スプレッドシートのみでは解決できない部分があるため、サーバサイドとしてAWSを利用しています。
アーキテクチャ図スプレッドシートイメージ
このようなスプレッドシートがスプレッドシートイメージ
↓
こんな感じでVRChat内で表示されるようになります。VRChatイメージ
利用ツール、技術など
言語
バックエンド
その他
Unity、Serverless Framework
概念さえ理解できてれば、PythonやAWSの知識は必要なく他のもので代用は利くので必須じゃないです。
手順 1. スプレッドシートの作成 以下をAppsScriptで作成します。 デプロイしてURLを取得しておきます。https://script.google.com/macros/s/AKhogehohehogehohehogehohehogehohe/exec のAKhogehohehogehohehogehohehogehohe部分が分かれば大丈夫です。 詳細なスプレッドシートの内容は本記事では割愛します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 function doGet (e ) { const mode = (typeof e === "undefined" || typeof e.parameter .mode === "undefined" )?"NONE" :e.parameter .mode ; const sheet = SpreadsheetApp .getActive ().getSheetByName ("main" ); var res; if (mode == "titles" ) res = getAllTitles (sheet); if (mode == "url" ) res = getURL (sheet, e.parameter .id ); if (mode == "NONE" ) res = JSON .stringify (getAll (sheet), null , 2 ); console .log (res); return ContentService .createTextOutput (res).setMimeType (ContentService .MimeType .JSON ); } function getAllTitles (sheet ){ console .log ("getaAllTitles!!" ); const start_row = 2 ,start_col = 1 const last_col = 1 ; const last_row = 21 ; const datas = sheet.getRange (start_row, start_col, last_row, last_col).getValues (); var list = "" ; for (let a of datas){ console .log (a); for (let b of a){ if (b != "" ){ if (list != "" ) list += "," ; list += b; } } } return list; } function getURL (sheet, id ){ console .log ("getTitleForID!!" ); values = sheet.getDataRange ().getValues (); return values[id][1 ] } function getAll (sheet ) { console .log ("getTitleForID!!" ); const rows = sheet.getDataRange ().getValues (); const keys = rows.splice (0 , 1 )[0 ]; return rows.map (row => { const obj = {}; row.map ((item, index ) => { obj[String (keys[index])] = String (item); }); return obj; }); }
「はじめに」の画像にあるようなスプレッドシートを入力します。 A2からA11までに動画のタイトルを入力します。 B2からB11までに動画のURLを入力します。
2. AWSリソースの作成 以下の2つのLambdaを作成しています。作成済みで利用できるものを用意してるため割愛して大丈夫です。https://github.com/aki-lua87/vrc_video_playlist_server/blob/master/src/lambda/get_ss_video/handler.py https://github.com/aki-lua87/vrc_video_playlist_server/blob/master/src/lambda/get_ss_video_titles/handler.py
3. Unity側の実装 Unityでスクリプトを作成
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 using System.Globalization;using UdonSharp;using UnityEngine;using UnityEngine.UI;using VRC.SDKBase;using VRC.Udon;using VRC.Udon.Common.Interfaces;using VRC.SDK3.StringLoading;public class VideoTitleLoader : UdonSharpBehaviour { [SerializeField ] private GameObject targetPlaylist; [SerializeField ] private VRCUrl stringURL; public void LoadString () { VRCStringDownloader.LoadUrl(stringURL, (IUdonEventReceiver)this ); } public override void OnStringLoadSuccess (IVRCStringDownload download ) { Debug.Log("VideoTitleLoader: OnstringLoadSuccess" ); var titlesString = download.Result; var titles = titlesString.Split(',' ); var content = targetPlaylist.transform.Find("KVPPlaylist/Canvas/PlaylistImpl/Scroll View/Viewport/Content" ); var videos = GetChildren(content); Debug.Log("titlesString" + titlesString); for (var i = 0 ; i < videos.Length; i++) { if (titles.Length < i) { break ; } var descriptionText = videos[i].Find("Description" ).gameObject.GetComponent<Text>(); descriptionText.text = titles[i]; Debug.Log(videos[i].name + " => " + titles[i]); if (titles[i].Length < 25 ) { descriptionText.fontSize = 40 ; } else { descriptionText.fontSize = 23 ; } } } public override void OnStringLoadError (IVRCStringDownload result ) { Debug.Log($"VideoTitleLoader: OnStringLoadError {result.ErrorCode} {result.Url} {result.Error} " ); } private Transform[] GetChildren (Transform parent ) { var children = new Transform[parent.childCount]; for (var i = 0 ; i < children.Length; ++i) { children[i] = parent.GetChild(i); } return children; } }
GameObjectにVideoTitleLoaderをアタッチ、targetPlaylistにはプレイリストのGameObjectをアタッチします。 URL欄には以下を入力します。AKhogehohehogehohehogehohehogehoheはデプロイしたスプレッドシートのURLの一部です。https://vrc.akakitune87.net/ss/titles?ssid=AKhogehohehogehohehogehohehogehohe
Unityイメージ
プレイリストのURLを入力 Unityイメージ
タイトルは何でもいいですhttps://vrc.akakitune87.net/ss/video?ssid=AKhogehohehogehohehogehohehogehohe&n=1 https://vrc.akakitune87.net/ss/video?ssid=AKhogehohehogehohehogehohehogehohe&n=2 https://vrc.akakitune87.net/ss/video?ssid=AKhogehohehogehohehogehohehogehohe&n=3 https://vrc.akakitune87.net/ss/video?ssid=AKhogehohehogehohehogehohehogehohe&n=4 https://vrc.akakitune87.net/ss/video?ssid=AKhogehohehogehohehogehohehogehohe&n=5 https://vrc.akakitune87.net/ss/video?ssid=AKhogehohehogehohehogehohehogehohe&n=6 https://vrc.akakitune87.net/ss/video?ssid=AKhogehohehogehohehogehohehogehohe&n=7 https://vrc.akakitune87.net/ss/video?ssid=AKhogehohehogehohehogehohehogehohe&n=8 https://vrc.akakitune87.net/ss/video?ssid=AKhogehohehogehohehogehohehogehohe&n=9 https://vrc.akakitune87.net/ss/video?ssid=AKhogehohehogehohehogehohehogehohe&n=10
プレイリストのタブを修正 Unityイメージ
KineLVP Playlist(tab)/KinelVP TabList Impl/Tablist/Scroll View/Viewport/Content[プレイリスト名]/Dummy のインスペクタよりOnValueChangedに画像のようにスクリプトをアタッチします。
Unityイメージ
アタッチするスクリプトは「 Unityでスクリプトを作成」で作成したものです。
4. VRChat内で確認
当該のタブを選択すると、スプレッドシートの内容が表示されることを確認
プレイリスト押下でスプレッドシートで入力した動画が再生されることを確認
おわりに 弊環境では問題なく動いてますが複数環境での動作確認はしていません、問題などありましたらご報告いただけると助かります。 上記システムを利用する際は自己責任でお願いします。