Refactored the player button component, updated the button display logic, and deleted the unused style files
This commit is contained in:
22
components/NavigationButtons.css
Normal file
22
components/NavigationButtons.css
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
.wxt-nav-button {
|
||||||
|
position: fixed;
|
||||||
|
right: 0px;
|
||||||
|
z-index: 9999;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 5px;
|
||||||
|
background-color: #28a745; /* 导航按钮使用绿色以作区分 */
|
||||||
|
color: white;
|
||||||
|
padding: 5px 10px;
|
||||||
|
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: 500;
|
||||||
|
text-decoration: none;
|
||||||
|
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.15);
|
||||||
|
cursor: pointer;
|
||||||
|
transition: transform 0.2s ease-in-out, background-color 0.2s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wxt-nav-button:hover {
|
||||||
|
transform: scale(1.05);
|
||||||
|
}
|
||||||
55
components/NavigationButtons.ts
Normal file
55
components/NavigationButtons.ts
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
import './NavigationButtons.css';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建或更新一个浮动导航按钮。
|
||||||
|
* 此按钮在新标签页中打开链接。
|
||||||
|
*/
|
||||||
|
function createOrUpdateNavButton(id: string, name: string, iconClass: string, url: string, topPosition: string) {
|
||||||
|
let button = document.getElementById(id) as HTMLAnchorElement | null;
|
||||||
|
|
||||||
|
if (!button) {
|
||||||
|
button = document.createElement('a');
|
||||||
|
button.id = id;
|
||||||
|
button.className = 'wxt-nav-button';
|
||||||
|
button.innerHTML = `
|
||||||
|
<i class="${iconClass}"></i>
|
||||||
|
<span>${name}</span>
|
||||||
|
`;
|
||||||
|
|
||||||
|
// 关键:设置在新标签页打开
|
||||||
|
button.target = '_blank';
|
||||||
|
// 安全性最佳实践
|
||||||
|
button.rel = 'noopener noreferrer';
|
||||||
|
|
||||||
|
document.body.appendChild(button);
|
||||||
|
}
|
||||||
|
|
||||||
|
button.href = url;
|
||||||
|
button.style.top = topPosition;
|
||||||
|
button.style.display = 'flex';
|
||||||
|
}
|
||||||
|
|
||||||
|
function hideButton(id: string) {
|
||||||
|
const button = document.getElementById(id);
|
||||||
|
if (button) {
|
||||||
|
button.style.display = 'none';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const MISSAV_BUTTON_ID = 'wxt-missav-nav-button';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 添加或更新 MissAV 导航按钮。
|
||||||
|
* @param videoNumber - 视频番号 (例如, 'IPX-811')。
|
||||||
|
*/
|
||||||
|
export function addOrUpdateNavigationButtons(videoNumber: string) {
|
||||||
|
const missavUrl = `https://missav.ws/${videoNumber.toLowerCase()}`;
|
||||||
|
createOrUpdateNavButton(MISSAV_BUTTON_ID, 'MissAV', 'icon-play', missavUrl, '200px');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 隐藏所有的导航按钮。
|
||||||
|
*/
|
||||||
|
export function hideNavigationButtons() {
|
||||||
|
hideButton(MISSAV_BUTTON_ID);
|
||||||
|
}
|
||||||
27
components/PlayerButtons.css
Normal file
27
components/PlayerButtons.css
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
.wxt-player-button {
|
||||||
|
/* 定位和层级 */
|
||||||
|
position: fixed;
|
||||||
|
right: 0px;
|
||||||
|
z-index: 9999;
|
||||||
|
|
||||||
|
/* 外观和布局 */
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 5px;
|
||||||
|
background-color: #3173dc; /* 播放器按钮使用蓝色 */
|
||||||
|
color: white;
|
||||||
|
padding: 5px 10px;
|
||||||
|
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: 500;
|
||||||
|
text-decoration: none;
|
||||||
|
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.15);
|
||||||
|
|
||||||
|
/* 交互效果 */
|
||||||
|
cursor: pointer;
|
||||||
|
transition: transform 0.2s ease-in-out, background-color 0.2s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wxt-player-button:hover {
|
||||||
|
transform: scale(1.05);
|
||||||
|
}
|
||||||
@@ -1,72 +1,66 @@
|
|||||||
|
import './PlayerButtons.css';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 创建或更新一个浮动播放器按钮。
|
* 创建或更新一个浮动播放器按钮。
|
||||||
* @param id - 按钮元素的 ID。
|
|
||||||
* @param name - 按钮上显示的文本。
|
|
||||||
* @param iconClass - 按钮图标的 CSS 类。
|
|
||||||
* @param url - 按钮点击后跳转的 URL。
|
|
||||||
* @param topPosition - 按钮的 CSS 'top' 属性值。
|
|
||||||
*/
|
*/
|
||||||
function createOrUpdateButton(id: string, name:string, iconClass: string, url: string, topPosition: string) {
|
function createOrUpdateButton(id: string, name:string, iconClass: string, url: string, topPosition: string) {
|
||||||
let button = document.getElementById(id) as HTMLAnchorElement | null;
|
let button = document.getElementById(id) as HTMLAnchorElement | null;
|
||||||
|
|
||||||
if (!button) {
|
if (!button) {
|
||||||
button = document.createElement('a');
|
button = document.createElement('a');
|
||||||
button.id = id;
|
button.id = id;
|
||||||
button.className = 'wxt-player-button'; // 为所有播放器按钮使用一个通用类名
|
button.className = 'wxt-player-button';
|
||||||
button.innerHTML = `
|
button.innerHTML = `
|
||||||
<i class="${iconClass}"></i>
|
<i class="${iconClass}"></i>
|
||||||
<span>${name}</span>
|
<span>${name}</span>
|
||||||
`;
|
`;
|
||||||
document.body.appendChild(button);
|
document.body.appendChild(button);
|
||||||
|
|
||||||
// 添加点击事件监听器
|
button.addEventListener('click', (e) => {
|
||||||
button.addEventListener('click', (e) => {
|
e.preventDefault();
|
||||||
e.preventDefault(); // 阻止 <a> 标签的默认跳转行为
|
window.location.href = button!.href;
|
||||||
window.location.href = button!.href;
|
});
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// 更新按钮的链接和位置
|
|
||||||
button.href = url;
|
|
||||||
button.style.top = topPosition;
|
|
||||||
button.style.display = 'flex'; // 确保按钮可见
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
button.href = url;
|
||||||
* 隐藏指定的播放器按钮。
|
button.style.top = topPosition;
|
||||||
* @param id - 要隐藏的按钮的 ID。
|
button.style.display = 'flex';
|
||||||
*/
|
}
|
||||||
function hideButton(id: string) {
|
|
||||||
const button = document.getElementById(id);
|
/**
|
||||||
if (button) {
|
* 隐藏指定的播放器按钮。
|
||||||
button.style.display = 'none';
|
*/
|
||||||
}
|
function hideButton(id: string) {
|
||||||
|
const button = document.getElementById(id);
|
||||||
|
if (button) {
|
||||||
|
button.style.display = 'none';
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 定义按钮的常量 ID
|
// 定义按钮的常量 ID
|
||||||
const IINA_BUTTON_ID = 'wxt-iina-floating-button';
|
const IINA_BUTTON_ID = 'wxt-iina-floating-button';
|
||||||
const POTPLAYER_BUTTON_ID = 'wxt-potplayer-floating-button';
|
const POTPLAYER_BUTTON_ID = 'wxt-potplayer-floating-button';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 添加或更新 IINA 和 PotPlayer 的浮动按钮。
|
* 添加或更新播放器按钮。
|
||||||
* @param missavUUID - 用于生成播放链接的 UUID。
|
* @param missavUUID - 用于生成播放链接的 UUID。
|
||||||
*/
|
*/
|
||||||
export function addOrUpdatePlayerButtons(missavUUID: string) {
|
export function addOrUpdatePlayerButtons(missavUUID: string) {
|
||||||
const playlistUrl = `https://surrit.com/${missavUUID}/playlist.m3u8`;
|
const playlistUrl = `https://surrit.com/${missavUUID}/playlist.m3u8`;
|
||||||
|
|
||||||
// IINA 按钮
|
// IINA 按钮
|
||||||
const iinaUrl = `iina://weblink?url=${playlistUrl}`;
|
const iinaUrl = `iina://weblink?url=${playlistUrl}`;
|
||||||
createOrUpdateButton(IINA_BUTTON_ID, 'IINA', 'icon-play', iinaUrl, '100px');
|
createOrUpdateButton(IINA_BUTTON_ID, 'IINA', 'icon-play', iinaUrl, '100px');
|
||||||
|
|
||||||
// PotPlayer 按钮
|
// PotPlayer 按钮
|
||||||
const potplayerUrl = `potplayer://${playlistUrl}`;
|
const potplayerUrl = `potplayer://${playlistUrl}`;
|
||||||
createOrUpdateButton(POTPLAYER_BUTTON_ID, 'PotPlayer', 'icon-play', potplayerUrl, '150px');
|
createOrUpdateButton(POTPLAYER_BUTTON_ID, 'PotPlayer', 'icon-play', potplayerUrl, '140px');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 隐藏所有的播放器按钮。
|
* 隐藏所有的播放器按钮。
|
||||||
*/
|
*/
|
||||||
export function hidePlayerButtons() {
|
export function hidePlayerButtons() {
|
||||||
hideButton(IINA_BUTTON_ID);
|
hideButton(IINA_BUTTON_ID);
|
||||||
hideButton(POTPLAYER_BUTTON_ID);
|
hideButton(POTPLAYER_BUTTON_ID);
|
||||||
}
|
}
|
||||||
@@ -1,19 +1,18 @@
|
|||||||
import './style.css'
|
// 从两个组件中导入方法
|
||||||
// 导入新的组件方法
|
|
||||||
import { addOrUpdatePlayerButtons, hidePlayerButtons } from '../../components/PlayerButtons';
|
import { addOrUpdatePlayerButtons, hidePlayerButtons } from '../../components/PlayerButtons';
|
||||||
|
import { addOrUpdateNavigationButtons, hideNavigationButtons } from '../../components/NavigationButtons';
|
||||||
|
|
||||||
// storage key, 与 popup 中保持一致
|
|
||||||
const STORAGE_KEY = 'feature_enabled';
|
const STORAGE_KEY = 'feature_enabled';
|
||||||
|
|
||||||
export default defineContentScript({
|
export default defineContentScript({
|
||||||
matches: ['*://*.javdb.com/v/*'],
|
matches: ['*://*.javdb.com/v/*'],
|
||||||
async main() {
|
async main() {
|
||||||
// 检查功能是否启用
|
|
||||||
const isEnabled = await storage.getItem(`sync:${STORAGE_KEY}`) ?? true;
|
const isEnabled = await storage.getItem(`sync:${STORAGE_KEY}`) ?? true;
|
||||||
|
|
||||||
if (!isEnabled) {
|
if (!isEnabled) {
|
||||||
console.log('❌ [JavDB Helper] 功能已禁用。');
|
console.log('❌ [JavDB Helper] 功能已禁用。');
|
||||||
hidePlayerButtons(); // 使用新的方法隐藏按钮
|
hidePlayerButtons();
|
||||||
|
hideNavigationButtons(); // 同时隐藏导航按钮
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -23,18 +22,22 @@ export default defineContentScript({
|
|||||||
if (window.location.pathname.startsWith('/v/')) {
|
if (window.location.pathname.startsWith('/v/')) {
|
||||||
const videoNumber = getVideoNumber();
|
const videoNumber = getVideoNumber();
|
||||||
if (videoNumber) {
|
if (videoNumber) {
|
||||||
|
// 只要有番号,就显示导航按钮
|
||||||
|
addOrUpdateNavigationButtons(videoNumber);
|
||||||
|
|
||||||
|
// 异步获取 UUID 来显示播放器按钮
|
||||||
const missavUUID = await getMissavUUID(videoNumber);
|
const missavUUID = await getMissavUUID(videoNumber);
|
||||||
if (missavUUID) {
|
if (missavUUID) {
|
||||||
// 成功获取 UUID,创建或更新按钮
|
addOrUpdatePlayerButtons(missavUUID);
|
||||||
addOrUpdatePlayerButtons(missavUUID); // 使用新的方法更新按钮
|
|
||||||
} else {
|
} else {
|
||||||
// 未获取到 UUID,隐藏按钮
|
// 如果没有 UUID,则只隐藏播放器按钮
|
||||||
hidePlayerButtons();
|
hidePlayerButtons();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// 如果不在视频详情页,隐藏按钮
|
// 如果不在视频详情页,隐藏所有按钮
|
||||||
hidePlayerButtons();
|
hidePlayerButtons();
|
||||||
|
hideNavigationButtons();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -53,7 +56,7 @@ export default defineContentScript({
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// 获取目标视频番号 (此函数保持不变)
|
// 获取目标视频番号
|
||||||
function getVideoNumber(): string {
|
function getVideoNumber(): string {
|
||||||
const targetElement = document.querySelector('a.button.is-white.copy-to-clipboard');
|
const targetElement = document.querySelector('a.button.is-white.copy-to-clipboard');
|
||||||
if (!targetElement) {
|
if (!targetElement) {
|
||||||
@@ -69,7 +72,7 @@ function getVideoNumber(): string {
|
|||||||
return targetNumber;
|
return targetNumber;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 获取 missav UUID (此函数保持不变)
|
// 获取 missav UUID
|
||||||
async function getMissavUUID(videoNumber: string): Promise<string> {
|
async function getMissavUUID(videoNumber: string): Promise<string> {
|
||||||
const lowerTargetNumber = videoNumber.toLowerCase();
|
const lowerTargetNumber = videoNumber.toLowerCase();
|
||||||
const targetUrl = `https://missav.ws/dm1/en/${lowerTargetNumber}`;
|
const targetUrl = `https://missav.ws/dm1/en/${lowerTargetNumber}`;
|
||||||
|
|||||||
@@ -1,28 +0,0 @@
|
|||||||
.wxt-player-button {
|
|
||||||
/* 定位和层级 */
|
|
||||||
position: fixed;
|
|
||||||
/* 'top' 属性现在通过内联样式设置 */
|
|
||||||
right: 0px;
|
|
||||||
z-index: 9999;
|
|
||||||
|
|
||||||
/* 外观和布局 */
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
gap: 5px;
|
|
||||||
background-color: #3173dc;
|
|
||||||
color: white;
|
|
||||||
padding: 5px 10px;
|
|
||||||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;
|
|
||||||
font-size: 14px;
|
|
||||||
font-weight: 500;
|
|
||||||
text-decoration: none;
|
|
||||||
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.15);
|
|
||||||
|
|
||||||
/* 交互效果 */
|
|
||||||
cursor: pointer;
|
|
||||||
transition: transform 0.2s ease-in-out, background-color 0.2s ease;
|
|
||||||
}
|
|
||||||
|
|
||||||
.wxt-player-button:hover {
|
|
||||||
transform: scale(1.05);
|
|
||||||
}
|
|
||||||
74
structure.md
74
structure.md
@@ -1,38 +1,38 @@
|
|||||||
Here's a brief summary of each of these files and directories:
|
Here's a brief summary of each of these files and directories:<br/>
|
||||||
|
<br/>
|
||||||
|
📂 {rootDir}/<br/>
|
||||||
|
📁 .output/<br/>
|
||||||
|
📁 .wxt/<br/>
|
||||||
|
📁 assets/<br/>
|
||||||
|
📁 components/<br/>
|
||||||
|
📁 composables/<br/>
|
||||||
|
📁 entrypoints/<br/>
|
||||||
|
📁 hooks/<br/>
|
||||||
|
📁 modules/<br/>
|
||||||
|
📁 public/<br/>
|
||||||
|
📁 utils/<br/>
|
||||||
|
📄 .env<br/>
|
||||||
|
📄 .env.publish<br/>
|
||||||
|
📄 app.config.ts<br/>
|
||||||
|
📄 package.json<br/>
|
||||||
|
📄 tsconfig.json<br/>
|
||||||
|
📄 web-ext.config.ts<br/>
|
||||||
|
📄 wxt.config.ts<br/>
|
||||||
|
|
||||||
📂 {rootDir}/
|
.output/: All build artifacts will go here<br/>
|
||||||
📁 .output/
|
.wxt/: Generated by WXT, it contains TS config<br/>
|
||||||
📁 .wxt/
|
assets/: Contains all CSS, images, and other assets that should be processed by WXT<br/>
|
||||||
📁 assets/
|
components/: Auto-imported by default, contains UI components<br/>
|
||||||
📁 components/
|
composables/: Auto-imported by default, contains source code for your project's composable functions for Vue<br/>
|
||||||
📁 composables/
|
entrypoints/: Contains all the entrypoints that get bundled into your extension<br/>
|
||||||
📁 entrypoints/
|
hooks/: Auto-imported by default, contains source code for your project's hooks for React and Solid<br/>
|
||||||
📁 hooks/
|
modules/: Contains local WXT Modules for your project<br/>
|
||||||
📁 modules/
|
public/: Contains any files you want to copy into the output folder as-is, without being processed by WXT<br/>
|
||||||
📁 public/
|
utils/: Auto-imported by default, contains generic utilities used throughout your project<br/>
|
||||||
📁 utils/
|
.env: Contains Environment Variables<br/>
|
||||||
📄 .env
|
.env.publish: Contains Environment Variables for publishing<br/>
|
||||||
📄 .env.publish
|
app.config.ts: Contains Runtime Config<br/>
|
||||||
📄 app.config.ts
|
package.json: The standard file used by your package manager<br/>
|
||||||
📄 package.json
|
tsconfig.json: Config telling TypeScript how to behave<br/>
|
||||||
📄 tsconfig.json
|
web-ext.config.ts: Configure Browser Startup<br/>
|
||||||
📄 web-ext.config.ts
|
wxt.config.ts: The main config file for WXT projects<br/>
|
||||||
📄 wxt.config.ts
|
|
||||||
|
|
||||||
.output/: All build artifacts will go here
|
|
||||||
.wxt/: Generated by WXT, it contains TS config
|
|
||||||
assets/: Contains all CSS, images, and other assets that should be processed by WXT
|
|
||||||
components/: Auto-imported by default, contains UI components
|
|
||||||
composables/: Auto-imported by default, contains source code for your project's composable functions for Vue
|
|
||||||
entrypoints/: Contains all the entrypoints that get bundled into your extension
|
|
||||||
hooks/: Auto-imported by default, contains source code for your project's hooks for React and Solid
|
|
||||||
modules/: Contains local WXT Modules for your project
|
|
||||||
public/: Contains any files you want to copy into the output folder as-is, without being processed by WXT
|
|
||||||
utils/: Auto-imported by default, contains generic utilities used throughout your project
|
|
||||||
.env: Contains Environment Variables
|
|
||||||
.env.publish: Contains Environment Variables for publishing
|
|
||||||
app.config.ts: Contains Runtime Config
|
|
||||||
package.json: The standard file used by your package manager
|
|
||||||
tsconfig.json: Config telling TypeScript how to behave
|
|
||||||
web-ext.config.ts: Configure Browser Startup
|
|
||||||
wxt.config.ts: The main config file for WXT projects
|
|
||||||
Reference in New Issue
Block a user