Skip to content

Commit

Permalink
feat: 0.1版本,支持弹幕显示、语音播报。
Browse files Browse the repository at this point in the history
  • Loading branch information
liuxian496 committed Sep 15, 2023
1 parent c204311 commit 22fbd53
Show file tree
Hide file tree
Showing 11 changed files with 295 additions and 57 deletions.
79 changes: 79 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
# Iceborne

Iceborne 弹幕播报,是一个简易版的,支持 mac os 系统的弹幕播报应用。基于 Electron 和[bilibili 线上弹幕姬](https://link.bilibili.com/ctool/vtuber/)开发,是一个纯前端的直播弹幕显示和播报工具。

## 功能简介

### 1. 弹幕窗口位置

弹幕窗口会在所有其它<strong>窗口之上</strong>,默认会显示在右上角。

### 2. 拖拽移动

可以通过鼠标按住<strong>寒冰温度计图标</strong>

![寒冰温度计图标](/assets/ice100.jpg 'ice')
进行拖拽,改变窗体的位置

### 3. 弹幕播报

<p>支持播报开启和关闭</p>
<p>支持设置播放音量</p>

### 4. 弹幕样式设置

可以在[bilibili 线上弹幕姬](https://link.bilibili.com/ctool/vtuber/)中的样式设置视图,设置自己喜欢的弹幕样式。

## 使用方式

### 1. 获取房间号

(1)用浏览器打开[bilibili 线上弹幕姬](https://link.bilibili.com/ctool/vtuber/)建议使用 Chrome。

<p>
(2)如果没有登录过网页版的 bilibili,需要扫码登录。
</p>
<p>
(3)页面上方,OBS's link后面的url就是自己账号对应的,网页版的弹幕姬。roomid后面的数字就是房间号。请复制房间号。
</p>
<p>
(4)这个链接可以在OBS中使用,也可以用浏览器打开。如果不需要播报功能,可以用这个链接,分屏显示弹幕。
</p>

### 2. Iceborne弹幕播报

<p>
(1)点击Iceborne弹幕播报图标,打开应用。
</p>
<p>
(2)输入自己直播间的房间号(默认显示的是我自己的房间号)。
</p>
<p>
(3)点击连接按钮。右上角会显示弹幕窗口。可以拖拽改变位置。
</p>
<p>
(4)可以通过点击「语音播报」打开或关闭「弹幕播报」功能。
</p>


## 开发与打包

<p>这个应用是自用建议版,没有上架应用商店。有编程经验的用户,可以自己下载并打包。</p>
<p>不建议没有开发经验的用户,自己修改和打包,可能会遇到很多问题。</p>

### 1. 安装依赖

打开终端,运行:npm install

### 2. 启动调试工程

打开终端,运行:npm start

### 3. 打包

打开终端,运行:npm run package

## 如果你想请我喝一杯蜜雪冰城(Buy Me a Mixue Ice Cream & Tea)

<img src=".\\assets\\wechat.jpg" height="360">
<img src=".\\assets\\alipay.jpg" height="360">
Binary file added assets/alipay.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/ice100.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/wechat.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@
"electron-debug": "^3.2.0",
"electron-log": "^4.4.8",
"electron-updater": "^5.3.0",
"litten": "^0.3.0",
"litten": "^0.4.1",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-router-dom": "^6.11.2",
Expand Down Expand Up @@ -158,7 +158,7 @@
"webpack-merge": "^5.9.0"
},
"build": {
"productName": "ElectronReact",
"productName": "Iceborne弹幕播报",
"appId": "org.erb.ElectronReact",
"asar": true,
"asarUnpack": "**\\*.{node,dll}",
Expand Down
37 changes: 0 additions & 37 deletions src/main/barragePreload.ts

This file was deleted.

64 changes: 57 additions & 7 deletions src/main/barrageWin.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
import { BrowserWindow, app } from 'electron';
import path from 'path';
import { BarrageSetting } from 'page/page.types';

// import { resolveHtmlPath } from './util';

let barrageWin: BrowserWindow | null = null;

function createDanMuViewByRoomId(roomId: number) {
function createDanMuViewByRoomId(props: BarrageSetting) {
const { roomId, speech } = props;

barrageWin = new BrowserWindow({
show: false,
width: 245,
Expand All @@ -22,6 +26,11 @@ function createDanMuViewByRoomId(roomId: number) {
},
});

// ipcMain.on('toggle-voice', async (event, args) => {
// console.log(args.checked);
// barrageWin?.webContents.send('update-speech', args.checked);
// });

// barrageWin?.loadURL(resolveHtmlPath('barrage.html'));

// const view = new BrowserView();
Expand All @@ -30,12 +39,38 @@ function createDanMuViewByRoomId(roomId: number) {
// `http://link.bilibili.com/ctool/vtuber/index.html?roomid=${roomId}&full=1`
// );

// barrageWin.webContents.executeJavaScript(
// 'let aaa =document.getElementsByTagName("ul"); console.log(aaa.length)'
// );
barrageWin.webContents.executeJavaScript(
`
const supperChat = document.getElementsByClassName('super-chat')[0];
const ice = '<svg width="32" height="32" fill="#08CBD0" viewBox="0 0 16 16">'+
'<’path d="M5 12.5a1.5 1.5 0 1 1-2-1.415V9.5a.5.5 0 0 1 1 0v1.585A1.5 1.5 0 0 1 5 12.5z"/>'+
'<path d="M1 2.5a2.5 2.5 0 0 1 5 0v7.55a3.5 3.5 0 1 1-5 0V2.5zM3.5 1A1.5 1.5 0 0 0 2 2.5v7.987l-.167.15a2.5 2.5 0 1 0 3.333 0L5 10.486V2.5A1.5 1.5 0 0 0 3.5 1zm5 1a.5.5 0 0 1 .5.5v1.293l.646-.647a.5.5 0 0 1 .708.708L9 5.207v1.927l1.669-.963.495-1.85a.5.5 0 1 1 .966.26l-.237.882 1.12-.646a.5.5 0 0 1 .5.866l-1.12.646.884.237a.5.5 0 1 1-.26.966l-1.848-.495L9.5 8l1.669.963 1.849-.495a.5.5 0 1 1 .258.966l-.883.237 1.12.646a.5.5 0 0 1-.5.866l-1.12-.646.237.883a.5.5 0 1 1-.966.258L10.67 9.83 9 8.866v1.927l1.354 1.353a.5.5 0 0 1-.708.708L9 12.207V13.5a.5.5 0 0 1-1 0v-11a.5.5 0 0 1 .5-.5z"/>'+
'</svg>';
const iconDiv = document.createElement('div');
iconDiv.innerHTML = ice;
supperChat.append(iconDiv);
supperChat.style["-webkit-app-region"] = "drag";
supperChat.style.display="flex";
supperChat.style["align-items"]="center";
supperChat.style["padding-left"]="10px";
// 根据默认值控制语音播报功能的开启
window.electron.broadcast(${speech})
window.electron.onUpdateVoice((event, speech) => {
// 根据默认值控制语音播报功能的开启
window.electron.broadcast(speech)
})
`
);

barrageWin?.loadURL(
`http://link.bilibili.com/ctool/vtuber/index.html?roomid=${roomId}&full=1`
`https://link.bilibili.com/ctool/vtuber/index.html?roomid=${roomId}&full=1`
);

barrageWin.once('ready-to-show', () => {
Expand All @@ -48,10 +83,25 @@ function createDanMuViewByRoomId(roomId: number) {
});
}

export function showDanMuView(roomId: number) {
createDanMuViewByRoomId(roomId);
/**
* 打开弹幕窗口
* @param props
*/
export function showDanMuView(props: BarrageSetting) {
createDanMuViewByRoomId(props);
}

/**
* 关闭弹幕窗口
*/
export function hidenDanMuView() {
barrageWin?.close();
}

/**
* 更改语音朗读功能的开启
* @param startSpeaking 是否开启朗读 true表示开启,反之表示不开启
*/
export function changeBarrageSpeech(startSpeaking: boolean) {
barrageWin?.webContents.send('update-speech', startSpeaking);
}
28 changes: 24 additions & 4 deletions src/main/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,15 @@ import path from 'path';
import { app, BrowserWindow, shell, ipcMain } from 'electron';
import { autoUpdater } from 'electron-updater';
import log from 'electron-log';
import { BarrageSetting } from 'page/page.types';
import MenuBuilder from './menu';
import { resolveHtmlPath } from './util';
import { hidenDanMuView, showDanMuView } from './barrageWin';
import { DanMuProps } from './preload';

import {
hidenDanMuView,
showDanMuView,
changeBarrageSpeech,
} from './barrageWin';

class AppUpdater {
constructor() {
Expand All @@ -33,14 +38,29 @@ ipcMain.on('ipc-example', async (event, arg) => {
event.reply('ipc-example', msgTemplate('pong'));
});

ipcMain.on('show-danmu-view', async (event, args: DanMuProps) => {
await showDanMuView(parseInt(args.roomId, 10));
/**
* 接收打开弹幕窗口的消息
*/
ipcMain.on('show-danmu-view', async (event, args: BarrageSetting) => {
console.log(args);
console.log(`roomID: ${args.roomId}`);
await showDanMuView(args);
});

/**
* 接收关闭弹幕窗口的消息
*/
ipcMain.on('hide-danmu-view', async () => {
await hidenDanMuView();
});

/**
* 接收更改语音朗读功能是否开启的消息
*/
ipcMain.on('change-speech', async (event, args: boolean) => {
await changeBarrageSpeech(args);
});

if (process.env.NODE_ENV === 'production') {
const sourceMapSupport = require('source-map-support');
sourceMapSupport.install();
Expand Down
Loading

0 comments on commit 22fbd53

Please sign in to comment.