Skip to content

Instantly share code, notes, and snippets.

@aki-lua87
Created August 1, 2022 01:28
Show Gist options
  • Save aki-lua87/4fe8ddb88aaddc643db8f57e67be4bc4 to your computer and use it in GitHub Desktop.
Save aki-lua87/4fe8ddb88aaddc643db8f57e67be4bc4 to your computer and use it in GitHub Desktop.
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net.Http;
using System.Text;
using System.Xml.Linq;
using HoshinoLabs.IwaSync3;
using UdonSharpEditor;
using UnityEditor;
using UnityEngine;
using UnityEngine.UI;
using VRC.Udon;
namespace aki_lua87.Editor.iwaSyncPlaylist
{
public class iwaSyncPlaylistEditor : EditorWindow
{
private readonly string logPrefix = "[aki_lua87] ";
[SerializeField] private GameObject playList;
[SerializeField] private string channelID = "";
[SerializeField] private string urlprefix = "";
[SerializeField] private bool isLiveInsert = false;
[MenuItem("Tools/aki_lua87/iwaSyncPlaylistEditor")]
private static void Init()
{
EditorWindow.GetWindow(typeof(iwaSyncPlaylistEditor));
}
private void OnGUI()
{
using (new GUILayout.VerticalScope())
{
EditorGUILayout.Space();
this.playList = (GameObject)EditorGUILayout.ObjectField("iwaSync3 PlayList", this.playList, typeof(GameObject), true);
this.urlprefix = EditorGUILayout.TextField("URLプレフィックス", this.urlprefix);
EditorGUILayout.Space();
this.channelID = EditorGUILayout.TextField("YoutubeチャンネルID", this.channelID);
EditorGUILayout.Space();
if (GUILayout.Button("現在の最新15動画を追加"))
{
CreatePlaylistForYoutubeChannel();
}
this.isLiveInsert = EditorGUILayout.Toggle("ライブを含めるか(β)", this.isLiveInsert);
if (GUILayout.Button("チャンネルを追加(β)"))
{
CreatePlaylistForAkiSyatem();
}
}
}
[Serializable]
public class akiWebResponse
{
public string result;
public string auther;
}
public void CreatePlaylistForYoutubeChannel()
{
Debug.Log($"{logPrefix}Call CreatePlaylistForYoutubeChannel");
try
{
var channel = extractChannelID(channelID);
string URL = $"https://www.youtube.com/feeds/videos.xml?channel_id={channel}";
var xml = XDocument.Load(URL);
var root = xml.Root;
var auther = root.Elements().Where(p => p.Name.LocalName == "title").FirstOrDefault();
Debug.Log($"{logPrefix}auther => " + auther.Value);
var entrys = root.Elements().Where(p => p.Name.LocalName == "entry");
if (entrys != null)
{
var tracks = new List<Track>();
foreach (var entry in entrys)
{
var mediaGroup = entry.Elements().Where(p => p.Name.LocalName == "group").FirstOrDefault();
var videoTitle = mediaGroup.Elements().Where(p => p.Name.LocalName == "title").Select(p => p.Value).FirstOrDefault();
var description = mediaGroup.Elements().Where(p => p.Name.LocalName == "description").Select(p => p.Value).FirstOrDefault();
var url = entry.Elements().Where(p => p.Name.LocalName == "link").Select(p => p.Attribute("href").Value).FirstOrDefault();
Debug.Log($"videoTitle:{videoTitle} description:{description} url:{url}");
var targetURL = $"{urlprefix}{url}";
var track = new Track
{
title = $"{videoTitle}",
url = targetURL
};
tracks.Add(track);
}
CreatePlaylist(auther.Value, tracks);
}
}
catch (Exception e)
{
Debug.Log($"{logPrefix}プレイリスト作成に失敗しました: {e.Message}");
}
return;
}
public async void CreatePlaylistForAkiSyatem()
{
Debug.Log($"{logPrefix}Call CreatePlaylistForAkiSyatem");
try
{
var channel = extractChannelID(channelID);
string URL = $"https://vrc.akakitune87.net/video/yt/channel/regist";
// TODO: 手書きじゃないいい方法
var reqJson = "{ \"channel_id\" : \"" + channel + "\"}";
var content = new StringContent(reqJson, Encoding.UTF8, "application/json");
var client = new System.Net.Http.HttpClient();
var res = await client.PostAsync(URL, content);
var resJson = await res.Content.ReadAsStringAsync();
Debug.Log($"{logPrefix}response json:" + resJson);
var resData = JsonUtility.FromJson<akiWebResponse>(resJson);
Debug.Log($"{logPrefix}data:" + JsonUtility.ToJson(resData));
if (!(resData.result == "OK"))
{
Debug.Log($"{logPrefix}API実行に失敗しました");
return;
}
var indexURL = $"{urlprefix}https://vrc.akakitune87.net/videos/yt/chlist/{channel}";
var urlleft = $"{urlprefix}https://vrc.akakitune87.net/videos/yt/ch/{channel}?n=";
var tagTitle = "" + resData.auther;
var liveURL = $"{urlprefix}https://vrc.akakitune87.net/videos/ytlive/ch/{channel}";
var tracks = new List<Track>();
var track = new Track
{
title = $"目次",
url = indexURL
};
tracks.Add(track);
if (isLiveInsert)
{
var track2 = new Track
{
title = $"LIVE",
url = liveURL,
mode = TrackMode.Live
};
tracks.Add(track2);
}
for (int i = 0; i < 20; i++)
{
var targetURL = $"{urlleft}{i}";
track = new Track
{
title = $"{i + 1}",
url = targetURL
};
tracks.Add(track);
}
CreatePlaylist(tagTitle, tracks);
}
catch (Exception e)
{
Debug.Log($"{logPrefix}プレイリスト作成に失敗しました: {e}");
}
}
private void CreatePlaylist(string tagTitle, List<Track> tracks)
{
// プレイリスト中身
var serializedProperty = this.playList.GetComponent<Playlist>();
var serializedObject = new SerializedObject(serializedProperty);
var tracksProperty = serializedObject.FindProperty("tracks");
tracksProperty.arraySize = tracks.Count;
// プレイリストのタイトル
var tittle = this.playList.transform.Find("Udon (Playlist)/Canvas/Panel/Header/Version/Text").gameObject;
var titleText = tittle.GetComponent<Text>();
titleText.text = tagTitle;
for (var i = 0; i < tracksProperty.arraySize; i++)
{
var trackProperty = tracksProperty.GetArrayElementAtIndex(i);
trackProperty.FindPropertyRelative("title").stringValue = tracks[i].title;
trackProperty.FindPropertyRelative("url").stringValue = tracks[i].url;
}
if (playList)
{
serializedObject.ApplyModifiedProperties();
}
}
private string extractChannelID(string str)
{
if (str.Contains("https://www.youtube.com/channel/"))
{
Debug.Log($"{logPrefix} 想定外の引数: 抽出処理を実施 {str}");
return str.Replace("https://www.youtube.com/channel/", "");
}
return str;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment