自作物第4段はゲームではありませんが、今度のはブログをやってる人の中では思った事があるんじゃないでしょうか?
簡単に自分で好きなYouTubeの動画が再生できたらなー…と。
私もたまにそういう事を思った事がありますので、今回はラジオ感覚で自分で好きな動画のリストを順々に再生出来ちゃうブログツールみたいなものを作ってみました!
見た目は凄くシンプルでこんな感じ!
どうでしょう、この「手のひらサイズ」の佇まい。
この小ささならサイドバーに設置しておいても邪魔になりません。
もはやこれは単なる動画プレーヤーではない。ブログの隅っこに開局した、自分専用の「ミニチュアラジオ放送局」!!
これを設置して自分で発信したいメッセージを使ってもいいかもしれない!
使い方も凄く簡単、このディスプレイの上にあるプルダウンメニューから再生したいリストを選び、再生ボタンを押すだけ!
これだけで好きな動画の音声が再生されます。
HTMLのコードも以下に載せておきますので、自分で好きなように改造して使っちゃってOKです。
なお、コードの中の「制作者:Gスカ」と記述してあるところは削除しないようお願いしますヽ(T∇T )ノ(極端に小さくする等も)
AIにプログラムを頼んだとは言え、このラジオツールのUIや配置等のアイデアは私が出したものなので(^^;
下記コードで自分の動画、もしくは気に入ってる動画のリストを載せたい!という人は次の部分を書き換えてください。
<select id="list-selector" onchange="changePlaylist(this.value)">
↑この下にある <option value=" の後に動画IDを入れ、 "> のあとにリスト名
<option value="PLExqHFrEYm9FJld2YNZWG6k5tfYN-Po8u">ショート怪談</option>
リストを増やしたい場合は
<option value="ここに新しいリストのIDを入れる">リスト名</option>
をリストの下に追加
外見を変えたい!って人は注釈を入れてありますのでそこを変更して下さい。
以下コード
<style>
/* 外観 */
#mini-player {
width: 150px;
background: #222;
padding: 10px;
border-radius: 8px;
box-shadow: 0 4px 15px rgba(0,0,0,0.8);
font-family: sans-serif;
}
/* プルダウンメニュー */
#list-selector {
width: 100%;
font-size: 10px;
background: #444;
color: #fff;
border: 1px solid #666;
margin-bottom: 8px;
cursor: pointer;
}
/* 液晶画面 */
#lcd-screen {
background: #000;
color: #fff;
border: 1px solid #444;
height: 24px;
margin-bottom: 10px;
position: relative;
overflow: hidden;
display: flex;
align-items: center;
}
/* 流れる文字 */
#scroll-text {
position: absolute;
white-space: nowrap;
padding-left: 100%;
font-size: 11px;
line-height: 24px;
will-change: transform;
}
/* 操作ボタン */
.mini-controls {
display: flex;
justify-content: space-between;
gap: 4px;
}
.mini-controls button {
background: #333;
border: 1px solid #555;
flex: 1;
height: 28px;
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
border-radius: 4px;
}
.mini-controls svg { fill: #fff; width: 14px; height: 14px; }
#yt-hidden-node { display: none; }
</style>
<div id="mini-player">
<select id="list-selector" onchange="changePlaylist(this.value)">
<option value="PLExqHFrEYm9FJld2YNZWG6k5tfYN-Po8u">ショート怪談</option>
<option value="PLExqHFrEYm9HscLj4r7I4nu6kgdfFlCtP">中国うさぎ</option>
<option value="PLExqHFrEYm9Fx18H919CRvs8Q1lK04IEe">VOICEVOX朗読怪談</option>
</select>
<div id="lcd-screen">
<div id="scroll-text">Ready...</div>
</div>
<div class="mini-controls">
<button onclick="prevVideo()"><svg viewbox="0 0 24 24"><path d="M6 6h2v12H6zm3.5 6l8.5 6V6z"></path></svg></button>
<button id="p-p-btn" onclick="togglePlay()"><svg viewbox="0 0 24 24"><path d="M8 5v14l11-7z"></path></svg></button>
<button onclick="nextVideo()"><svg viewbox="0 0 24 24"><path d="M6 18l8.5-6L6 6zm9-12h2v12h-2z"></path></svg></button>
</div>
<div style="font-size: 10px; color: #99f; text-align: right; transform: scale(0.6); transform-origin: right top; margin-bottom: -5px;">制作者:Gスカ</div>
</div>
<div id="yt-hidden-node"></div>
<script>
var tag = document.createElement('script');
tag.src = "https://www.youtube.com/iframe_api";
document.body.appendChild(tag);
var player;
var scrollInterval;
var checkTitleInterval;
var retryLoadInterval; // リスト読み込みの再試行用
function onYouTubeIframeAPIReady() {
var firstList = document.getElementById('list-selector').value;
player = new YT.Player('yt-hidden-node', {
height: '0', width: '0',
playerVars: { 'listType': 'playlist', 'list': firstList, 'loop': 1, 'index': 0 },
events: { 'onReady': onPlayerReady, 'onStateChange': onPlayerStateChange }
});
}
function onPlayerReady(event) {
updateDisplay("Ready to Play >>> ");
startScroll();
}
function onPlayerStateChange(event) {
var btn = document.getElementById('p-p-btn');
if (event.data == YT.PlayerState.PLAYING) {
btn.innerHTML = '<svg viewBox="0 0 24 24"><path d="M6 19h4V5H6v14zm8-14v14h4V5h-4z"/></svg>';
updateDisplay();
} else {
btn.innerHTML = '<svg viewBox="0 0 24 24"><path d="M8 5v14l11-7z"/></svg>';
}
}
function updateDisplay(isForcedText) {
var screenText = document.getElementById('scroll-text');
clearInterval(checkTitleInterval);
if (isForcedText) { screenText.innerText = isForcedText; return; }
screenText.innerText = "Now Loading Video Title >>> ";
checkTitleInterval = setInterval(() => {
if (player && player.getVideoData) {
var title = player.getVideoData().title;
if (title && title.trim() !== "" && title !== "undefined") {
screenText.innerText = title;
clearInterval(checkTitleInterval);
}
}
}, 500);
}
// ★ここを修正!確実にリストを切り替える執念の処理
function changePlaylist(listId) {
clearInterval(retryLoadInterval);
// まずは「Loading」を出す
updateDisplay("Loading New Playlist >>> ");
// プレイヤーが準備できていればロード
if (player && player.loadPlaylist) {
player.loadPlaylist({list: listId, listType: 'playlist', index: 0});
// もし一度で反映されなかった時のために、ちょっとだけ遅れてもう一度命令を出す
retryLoadInterval = setTimeout(() => {
player.loadPlaylist({list: listId, listType: 'playlist', index: 0});
}, 800);
}
}
let pos = 150;
function startScroll() {
clearInterval(scrollInterval);
scrollInterval = setInterval(() => {
const el = document.getElementById('scroll-text');
pos -= 1;
if (pos < -el.offsetWidth) pos = 150;
el.style.transform = `translateX(${pos}px)`;
}, 25);
}
function togglePlay() {
if (player.getPlayerState() == 1) player.pauseVideo();
else player.playVideo();
}
function nextVideo() { player.nextVideo(); }
function prevVideo() { player.previousVideo(); }
</script>
0 件のコメント:
コメントを投稿
I'm sorry, Japanese text only.
荒らし目的と思われるコメントは気づき次第対処します。