| @@ -3,14 +3,18 @@ let videoId; | |||
| let lastVideoId; | |||
| let comments = []; | |||
| const noon = new Audio ('//nizika.tv/assets/noon.wav'); | |||
| function time2second (time) | |||
| { | |||
| return (([m, s]) => m * 60 + (+s)) (time.split (':')); | |||
| } | |||
| setInterval (() => { | |||
| const sendBtn = document.getElementById ('niconico-comment-send'); | |||
| const comBox = document.getElementById ('niconico-comment-input'); | |||
| if (sendBtn == null) | |||
| return; | |||
| sendBtn.addEventListener ('click', () => | |||
| const sendComment = () => | |||
| { | |||
| const lang = document.querySelector ('html').lang; | |||
| @@ -28,9 +32,22 @@ document.querySelector ('textarea').dispatchEvent (new InputEvent('input', { | |||
| })); | |||
| setTimeout (() => { | |||
| document.querySelector ('button.peertube-button.orange-button.ng-star-inserted').click (); | |||
| comments.push ({time: time2second (time), lang, style, content: comBox.value}); | |||
| comBox.value = ''; | |||
| noon.play (); | |||
| }, 100); | |||
| }); | |||
| }; | |||
| if (sendBtn == null || comBox == null) | |||
| return; | |||
| comBox.addEventListener ('keydown', | |||
| function (e) | |||
| { | |||
| if (e.key === 'Enter') | |||
| sendComment (); | |||
| }); | |||
| sendBtn.addEventListener ('click', sendComment); | |||
| }, 1000); | |||
| setInterval (async () => | |||
| @@ -43,13 +60,37 @@ lastVideoId = videoId; | |||
| if (videoId) | |||
| { | |||
| console.log (comments = (await fetch(`/api/v1/videos/${videoId}/comment-threads?count=100&sort=-createdAt`) | |||
| .then(response => response.ok && response.json ())).data.map (e => e.text).filter (e => (0 <= +e[0]) && (+e[0] <= 9) && ((e.match (/\//g) || []).length >= 3)).map (e => (([time, lang, style, ...contentParts]) => ({time: (([m, s]) => m * 60 + (+s)) (time.split (':')), lang, style, content: contentParts.join ('/')})) (e.split ('/'))).sort ((a, b) => a.time < b.time ? -1 : 1) ); | |||
| comments = (await fetch(`/api/v1/videos/${videoId}/comment-threads?count=100&sort=-createdAt`) | |||
| .then(response => response.ok && response.json ())).data.map (e => e.text).filter (e => (0 <= +e[0]) && (+e[0] <= 9) && ((e.match (/\//g) || []).length >= 3)).map (e => (([time, lang, style, ...contentParts]) => ({time: time2second (time), lang, style, content: contentParts.join ('/')})) (e.split ('/'))).sort ((a, b) => a.time < b.time ? -1 : 1) ; | |||
| } | |||
| } | |||
| const canvas = document.querySelector ('#comment-canvas'); | |||
| if (canvas) | |||
| { | |||
| canvas.width = 1280; | |||
| canvas.height = 720; | |||
| } | |||
| const ctx = canvas?.getContext ('2d'); | |||
| if (ctx) | |||
| { | |||
| ctx.font = '48px Arial'; // フォントサイズとフォントタイプを設定 | |||
| ctx.textBaseline = 'top' | |||
| ctx.clearRect(0, 0, canvas.width, canvas.height); | |||
| ctx.lineWidth = 4; | |||
| const curTime = document.querySelector ('video').currentTime | |||
| comments.forEach ((e, i) => | |||
| { | |||
| [['black', 'strokeText'], ['white', 'fillText']].forEach (([cl, f]) => | |||
| { | |||
| ctx.fillStyle = cl; | |||
| ctx[f] (e.content, canvas.width + (e.time - curTime - 1) * (canvas.width + e.content.length * 48) / 4, 6 + 60 * (i % 12)); | |||
| }); | |||
| }); | |||
| } | |||
| let cmtStyle; | |||
| if ((cmtStyle = document.querySelector ('.comment-threads')?.parentElement?.style) != null) | |||
| cmtStyle.display = 'none'; | |||
| }, 100); | |||
| }, 30); | |||
| ``` | |||