Skip to content

Instantly share code, notes, and snippets.

@aki-lua87
Created August 1, 2022 01:19
Show Gist options
  • Save aki-lua87/3abfa67b4769f545cad1deb633593ca7 to your computer and use it in GitHub Desktop.
Save aki-lua87/3abfa67b4769f545cad1deb633593ca7 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 Kinel.VideoPlayer.Scripts;
using Kinel.VideoPlayer.Scripts.Parameter;
using Kinel.VideoPlayer.Udon;
using Kinel.VideoPlayer.Udon.Playlist;
using UdonSharpEditor;
using UnityEditor;
using UnityEngine;
using UnityEngine.UI;
using VRC.Udon;
namespace aki_lua87.Editor.KineLPlaylist
{
public class KineLPlaylistV2Editor : EditorWindow
{
private readonly string logPrefix = "[aki_lua87] ";
[SerializeField] private GameObject playList;
[SerializeField] private string channelID = "";
[SerializeField] private string searchWord = "";
[SerializeField] private string urlprefix = "";
[SerializeField] private bool isLiveInsert = false;
[SerializeField] private bool isDynamicLink = true;
private KinelPlaylistScript _playlist;
[MenuItem("Tools/aki_lua87/KineLPlaylistV2Editor")]
private static void Init()
{
EditorWindow.GetWindow(typeof(KineLPlaylistV2Editor));
}
private void OnGUI()
{
using (new GUILayout.VerticalScope())
{
EditorGUILayout.Space();
this.playList = (GameObject)EditorGUILayout.ObjectField("KineLPlaylist", this.playList, typeof(GameObject), true);
this.urlprefix = EditorGUILayout.TextField("URLプレフィックス", this.urlprefix);
EditorGUILayout.Space();
this.channelID = EditorGUILayout.TextField("YoutubeチャンネルID", this.channelID);
EditorGUILayout.Space();
this.isDynamicLink = EditorGUILayout.Toggle("動的URLを発行するか", this.isDynamicLink);
if(this.isDynamicLink)
this.isLiveInsert = EditorGUILayout.Toggle("ライブを含めるか(β)", this.isLiveInsert);
else
EditorGUILayout.Space();
if (GUILayout.Button("プレイリスト追加"))
{
if(this.isDynamicLink)
{
CreatePlaylistForAkiSyatemC();
}else{
CreatePlaylistForYoutubeChannel();
}
}
EditorGUILayout.Space();
EditorGUILayout.Space();
this.searchWord = EditorGUILayout.TextField("検索ワード", this.searchWord);
using (new GUILayout.HorizontalScope())
{
if (GUILayout.Button("検索ワードで追加"))
{
CreatePlaylistForAkiSyatemQ(this.searchWord);
}
}
EditorGUILayout.Space();
GUILayout.Label("※追加後にGanelate playlistの押下を忘れないこと");
}
}
[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 videoDatas = new List<VideoData>();
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 videoData = new VideoData
{
title = $"{videoTitle}",
url = targetURL,
description = $"",
mode = 0
};
videoDatas.Add(videoData);
}
CreatePlaylist(auther.Value, videoDatas);
}
}
catch (Exception e)
{
Debug.Log($"{logPrefix}プレイリスト作成に失敗しました: {e.Message}");
}
return;
}
public async void CreatePlaylistForAkiSyatemC()
{
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 liveURL = $"{urlprefix}https://vrc.akakitune87.net/videos/ytlive/ch/{channel}";
var urlleft = $"{urlprefix}https://vrc.akakitune87.net/videos/yt/ch/{channel}?n=";
var tagTitle = "" + resData.auther;
var videoDatas = new List<VideoData>();
var videoData = new VideoData
{
title = $"目次",
url = indexURL,
description = $"",
mode = 0
};
videoDatas.Add(videoData);
if (isLiveInsert)
{
var liveData = new VideoData
{
title = $"LIVE",
url = liveURL,
description = $"",
mode = 1
};
videoDatas.Add(liveData);
}
for (int i = 0; i < 20; i++)
{
var targetURL = $"{urlleft}{i}";
videoData = new VideoData
{
title = $"{i + 1}",
url = targetURL,
description = $"",
mode = 0
};
videoDatas.Add(videoData);
}
CreatePlaylist(tagTitle, videoDatas);
}
catch (Exception e)
{
Debug.Log($"{logPrefix}プレイリスト作成に失敗しました: {e}");
}
}
public void CreatePlaylist(string tagTitle, List<VideoData> videoDatas)
{
// Video listにURLを挿入
var serializedProperty = this.playList.GetComponent<KinelPlaylistScript>();
var serializedObject = new SerializedObject(serializedProperty);
var videoDatasProperty = serializedObject.FindProperty("videoDatas");
videoDatasProperty.arraySize = videoDatas.Count;
// タグに名前を挿入
// 未実装、というかもっと上のレイヤで実装
for (var i = 0; i < videoDatasProperty.arraySize; i++)
{
var videoDataProperty = videoDatasProperty.GetArrayElementAtIndex(i);
videoDataProperty.FindPropertyRelative("title").stringValue = videoDatas[i].title;
videoDataProperty.FindPropertyRelative("url").stringValue = videoDatas[i].url;
}
if (playList)
{
serializedObject.ApplyModifiedProperties();
}
}
public async void CreatePlaylistForAkiSyatemQ(string q)
{
Debug.Log($"{logPrefix}Call CreatePlaylistForAkiSyatemQ");
try
{
var urlleft = $"{urlprefix}https://vrc.akakitune87.net/videos/yt/query?q={q}&n=";
var videoDatas = new List<VideoData>();
for (int i = 0; i < 20; i++)
{
var targetURL = $"{urlleft}{i}";
var videoData = new VideoData
{
title = $"{i + 1}",
url = targetURL,
description = $"",
mode = 0
};
videoDatas.Add(videoData);
}
CreatePlaylist("", videoDatas);
}
catch (Exception e)
{
Debug.Log($"{logPrefix}プレイリスト作成に失敗しました: {e}");
}
}
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