Skip to content

Commit

Permalink
support nicovideo(re kari)
Browse files Browse the repository at this point in the history
  • Loading branch information
rutan committed Jun 14, 2024
1 parent 4832bb4 commit b7a1cf8
Show file tree
Hide file tree
Showing 5 changed files with 138 additions and 40 deletions.
1 change: 1 addition & 0 deletions app/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
{
"matches": [
"https://www.nicovideo.jp/watch/*",
"https://www.nicovideo.jp/watch_tmp/*",
"https://live.nicovideo.jp/watch/*",
"https://live2.nicovideo.jp/watch/*"
],
Expand Down
78 changes: 78 additions & 0 deletions src/constants.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
export const EXTENSION_LABEL = '[非公式] PinP';

/*
* video タグのセレクタ
*/
// ニコニコ動画
export const NICO_VIDEO_VIDEO_TAG_SELECTOR = '#MainVideoPlayer video';
// ニコニコ動画(Re:仮)
export const NICO_VIDEO_TMP_VIDEO_TAG_SELECTOR = 'main [data-name="content"] video';
// ニコニコ生放送
export const NICO_LIVE_VIDEO_TAG_SELECTOR = '[class^=___video-layer___] video';

export const VIDEO_TAG_SELECTOR = [
NICO_VIDEO_VIDEO_TAG_SELECTOR,
NICO_VIDEO_TMP_VIDEO_TAG_SELECTOR,
NICO_LIVE_VIDEO_TAG_SELECTOR,
].join(',');

/*
* コメント用 canvas のセレクタ
*/
// ニコニコ動画
export const NICO_VIDEO_COMMENT_CANVAS_TAG_SELECTOR = '.CommentRenderer canvas';
// ニコニコ動画(Re:仮)
export const NICO_VIDEO_TMP_COMMENT_CANVAS_TAG_SELECTOR = 'main [data-name="comment"] > canvas';
// ニコニコ生放送
export const NICO_LIVE_COMMENT_CANVAS_TAG_SELECTOR = '[class^=___comment-layer___] canvas';

export const COMMENT_CANVAS_TAG_SELECTOR = [
NICO_VIDEO_COMMENT_CANVAS_TAG_SELECTOR,
NICO_VIDEO_TMP_COMMENT_CANVAS_TAG_SELECTOR,
NICO_LIVE_COMMENT_CANVAS_TAG_SELECTOR,
].join(',');

/*
* コピー元とするボタンのセレクタ
*/
// ニコニコ動画
export const NICO_VIDEO_TARGET_BUTTON_SELECTOR = '.ControllerContainer .EnableFullScreenButton';
// ニコニコ動画(Re:仮)
export const NICO_VIDEO_TMP_TARGET_BUTTON_SELECTOR = 'main .w_24px:not(.p_2px)';
// ニコニコ生放送
export const NICO_LIVE_TARGET_BUTTON_SELECTOR = '[class^=___addon-controller___] [class^=___fullscreen-button___]';

export const TARGET_BUTTON_SELECTOR = [
NICO_VIDEO_TARGET_BUTTON_SELECTOR,
NICO_VIDEO_TMP_TARGET_BUTTON_SELECTOR,
NICO_LIVE_TARGET_BUTTON_SELECTOR,
].join(',');

/**
* 提供画面の HTML のセレクタ(ニコニコ動画のみ)
*/
export const NICO_VIDEO_SUPPORTER_VIEW_SELECTOR = '#UadPlayer .SupporterView';
export const NICO_VIDEO_TMP_SUPPORTER_VIEW_SELECTOR = 'main [data-name="supporter-content"]';

export const SUPPORTER_VIEW_SELECTOR = [
NICO_VIDEO_SUPPORTER_VIEW_SELECTOR,
NICO_VIDEO_TMP_SUPPORTER_VIEW_SELECTOR,
].join(',');

/**
* 提供画面の Canvas のセレクタ(ニコニコ動画のみ)
*/
export const NICO_VIDEO_SUPPORTER_VIEW_CANVAS_SELECTOR = '#SupporterView-canvas';
export const NICO_VIDEO_TMP_SUPPORTER_VIEW_CANVAS_SELECTOR = 'main [data-name="supporter-content"] canvas';

export const SUPPORTER_VIEW_CANVAS_SELECTOR = [
NICO_VIDEO_SUPPORTER_VIEW_CANVAS_SELECTOR,
NICO_VIDEO_TMP_SUPPORTER_VIEW_CANVAS_SELECTOR,
].join(',');

/**
* Akashic のゲーム画面の canvas のセレクタ(ニコニコ生放送のみ)
*/
export const NICO_LIVE_AKASHIC_CANVAS_SELECTOR = '#akashic-gameview canvas';

export const AKASHIC_CANVAS_SELECTOR = [NICO_LIVE_AKASHIC_CANVAS_SELECTOR].join(',');
67 changes: 37 additions & 30 deletions src/contentScript.ts
Original file line number Diff line number Diff line change
@@ -1,41 +1,48 @@
import { EXTENSION_LABEL, TARGET_BUTTON_SELECTOR, VIDEO_TAG_SELECTOR } from './constants';
import { copyButton } from './functions/copyButton';
import { initPinP, startPinP } from './functions/pinp';
import PictureInPictureIcon from './svg/pinpIcon';

const TITLE = '[非公式] PinP';

const checkPinPButton = setInterval(function () {
const fullScreenButton = document.querySelector<HTMLElement>(
'.ControllerContainer .EnableFullScreenButton, [class^=___addon-controller___] [class^=___fullscreen-button___]'
);
if (!fullScreenButton) return;
(() => {
// ページにスクリプトを挿入
// ※主にギフト画像の読み込み問題用。解消したら削除したい。
const path = chrome.runtime.getURL('js/inject.js');
const script = document.createElement('script');
script.src = path;
document.head.append(script);

initPinP();
let count = 0;
const checkPinPButton = setInterval(function () {
const targetButtons = document.querySelectorAll<HTMLElement>(TARGET_BUTTON_SELECTOR);
if (targetButtons.length === 0) {
// 一定回数チェックして見つからなかったらページ構造が変わったと判断して終了
++count;
if (count > 15) clearInterval(checkPinPButton);
return;
}

// フルスクボタンをコピーしPinPボタンにする
copyButton({
srcButton: fullScreenButton,
title: TITLE,
icon: PictureInPictureIcon,
onClick: startPinP,
});
// PinPの初期化
initPinP();

// videoのPinP操作からstartPinPを呼び出すようにする
const video = document.querySelector<HTMLVideoElement>('#MainVideoPlayer video, [class^=___video-layer___] video');
if (video) {
video.disablePictureInPicture = false;
video.addEventListener('enterpictureinpicture', (e) => {
e.preventDefault();
startPinP();
// ボタンをコピーしPinPボタンにする
const targetButton = targetButtons[targetButtons.length - 1];
copyButton({
srcButton: targetButton,
title: EXTENSION_LABEL,
icon: PictureInPictureIcon,
onClick: startPinP,
});
}

clearInterval(checkPinPButton);
}, 500);
// videoのPinP操作からstartPinPを呼び出すようにする
const video = document.querySelector<HTMLVideoElement>(VIDEO_TAG_SELECTOR);
if (video) {
video.disablePictureInPicture = false;
video.addEventListener('enterpictureinpicture', (e) => {
e.preventDefault();
startPinP();
});
}

(() => {
const path = chrome.runtime.getURL('js/inject.js');
const script = document.createElement('script');
script.src = path;
document.head.append(script);
clearInterval(checkPinPButton);
}, 500);
})();
2 changes: 2 additions & 0 deletions src/functions/copyButton.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ interface CopyButtonParameter {
export function copyButton({ srcButton, title, icon, onClick }: CopyButtonParameter): void {
const cloneButton = srcButton.cloneNode(true) as HTMLElement;

cloneButton.setAttribute('title', title);

// ニコ動
if (cloneButton.hasAttribute('data-title')) {
cloneButton.setAttribute('data-title', title);
Expand Down
30 changes: 20 additions & 10 deletions src/functions/pinp.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,11 @@
import {
AKASHIC_CANVAS_SELECTOR,
COMMENT_CANVAS_TAG_SELECTOR,
SUPPORTER_VIEW_CANVAS_SELECTOR,
SUPPORTER_VIEW_SELECTOR,
VIDEO_TAG_SELECTOR,
} from '../constants';

const FRAME_RATE = 60;

let isHidden = false;
Expand Down Expand Up @@ -53,15 +61,11 @@ function calcSize(srcWidth: number, srcHeight: number, dstWidth: number, dstHeig

export function handleVideo(): void {
const myId = ++uid;
const comment = document.querySelector<HTMLCanvasElement>(
'.CommentRenderer canvas, [class^=___comment-layer___] canvas'
);
const targetVideo = document.querySelector<HTMLVideoElement>(
'#MainVideoPlayer video, [class^=___video-layer___] video'
);
const supporterView = document.querySelector<HTMLDivElement>('#UadPlayer .SupporterView');
const supporterCanvas = document.getElementById('SupporterView-canvas') as HTMLCanvasElement;
const akashicCanvas = document.querySelector<HTMLCanvasElement>('#akashic-gameview canvas');
const comment = document.querySelector<HTMLCanvasElement>(COMMENT_CANVAS_TAG_SELECTOR);
const targetVideo = document.querySelector<HTMLVideoElement>(VIDEO_TAG_SELECTOR);
const supporterView = document.querySelector<HTMLDivElement>(SUPPORTER_VIEW_SELECTOR);
const supporterCanvas = document.querySelector<HTMLCanvasElement>(SUPPORTER_VIEW_CANVAS_SELECTOR);
const akashicCanvas = document.querySelector<HTMLCanvasElement>(AKASHIC_CANVAS_SELECTOR);

function update() {
if (!comment || !targetVideo || !context || myId != uid) {
Expand Down Expand Up @@ -97,7 +101,13 @@ export function handleVideo(): void {
);

// supporter
if (supporterView?.style.visibility === 'visible' && supporterCanvas) {
if (
// ニコニコ動画
(supporterView?.style.visibility === 'visible' ||
// ニコニコ動画(Re:仮)
(supporterView?.style.visibility === '' && supporterView?.style.display === 'block')) &&
supporterCanvas
) {
const supporterSize = calcSize(supporterCanvas.width, supporterCanvas.height, canvas.width, canvas.height);
context.drawImage(
supporterCanvas,
Expand Down

0 comments on commit b7a1cf8

Please sign in to comment.