6
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

NodeCGで配信画面を作ってみよう(assetsを使おう編)

Posted at

はじめに

この記事はただカッコいいという理由だけでNodeCGを使った配信レイアウトを作ってみた備忘録の第3弾です。
今回はNodeCGの機能の一つ「assets」を使用して前回作成した配信画面の背景を変更できる機能を追加していきます。

前回の記事はこちら

使用するプロジェクト

今回使用するBundle(temp-bundle)は基本的に前回の記事で使用したものと同じものになります。
詳細は前回の記事を参照ください。

assetsとは

assetsとはユーザがダッシュボードから各種ファイルをアップロードしてBundle内で扱えるようにする仕組みです。

自前でファイルアップロード処理を実装する必要がないうえに、アップロードしたファイルはNodeCGが自動的にBundleのReplicantへ追加してくれるため、Bundleからのアクセスも行いやすいものとなっています。

assetsの設定

使用するassetsの設定もその他Bundleの設定と同様、Bundle配下のpackage.jsonに記述します。

package.json
{
  "name": "temp-bundle",
  "version": "1.0.0",
  "description": "",
  "scripts": {
    "build": "cd src/dashboard && vite build && cd ../graphics && vite build && cd ../extension && vite build",
    "dev": "vite"
  },
  "nodecg": {
    "compatibleRange": "*",
    // ↓assetsの設定
    "assetCategories": [
      {
        "name": "background",
        "title": "背景",
        "allowedTypes": [
          "jpg",
          "jpeg",
          "gif",
          "png",
          "mp4"
        ]
      }
    ],
    //  ここまで
    "dashboardPanels": [
      {
        "name": "layout",
        "title": "レイアウト",
        "width": 5,
        "height": 10,
        "file": "layout/index.html",
        "workspace": "レイアウト"
      }
    ],
    "graphics": [
      {
        "file": "layout/index.html",
        "width": "1920",
        "height": "1080"
      }
    ]
  },
  // 以下略
}

見たままですが各項目の簡単な説明です。

項目 説明
name assetsに使用する名前空間。
bundle内で一意である必要がある。
title assetsのタイトル。好きに設定してOK
allowedTypes アップロードするファイルの拡張子。
配列形式で指定する。

ここまで設定してNodeCGを起動し、ダッシュボードにアクセスするとassetsにファイルをアップロードすることが出来るようになります。

NodeCG01.jpg

ファイルを追加するとこんな感じ
NodeCG02.jpg

assetsにアップロードしたファイルはassets/{Bundle名}/{assets名}/フォルダ配下に保存されるため、Replicantと同様NodeCGを再起動しても保持されます。

ソースコード

Replicantの修正

さて、Bundleに対してファイルをアップロードできるように設定できたので
dashboardやgraphicsからファイルにアクセスできるようにしていきましょう。

前述のとおり、package.jsonに設定した各assetsは
NodeCGが自動的にReplicantを作成してくれるため、Replicantとしてアクセスすることが可能です。
今回使用しているBundleではBundleで用いるReplicantの型定義を行っているため、assetsをTypeScirptで扱うための型定義を追加していきます。

src/replicant.ts
// assetsの型定義
export type NodecgAssets = {
    "base": string,
    "namespace": string,
    "category": string,
    "ext": string,
    "name": string,
    "sum": string,
    "url": string
}

export type ReplicantMap = {
    "telop": string,
    "background": NodecgAssets | undefined,
    // assetsは「assets:{name}」プロパティとしてReplicantに追加される。
    "assets:background": NodecgAssets[]
}

export const replicantDefaultValues: ReplicantMap = {
    "telop": "sample-telop",
    "background": undefined,
    "assets:background": []
}

ソースコードを弄る

assets周りの設定が完了したので後はひたすらdashboardとgraphicsを弄るのみです。

dashboard

src/dashboard/layout/App.tsx
import { Button, Card, CardHeader, Grid, IconButton, TextField } from "@mui/material";
import { useReplicant } from "../../hooks";
import { NodecgAssets } from "../../replicant";
import { Close } from "@mui/icons-material";
import { FormEvent, useRef } from "react";

function App() {
    const [ telop, setTelop ] = useReplicant<"telop">("telop");
    const telopRef = useRef<HTMLInputElement>(null);
    const submitTelop = (e: FormEvent<HTMLFormElement>) => {
        e.preventDefault();
        if (telopRef.current) {
            setTelop(telopRef.current.value);
        }
    }

    // 背景ファイル周りの設定
    const [ , setBackground ] = useReplicant<"background">("background");
    const [ backgrounds, setBackgrounds ] = useReplicant<"assets:background">("assets:background");
    const deleteBG = (bg: NodecgAssets) => {
        // Replicantを更新することでassetsからファイルを削除できる。
        setBackgrounds([...backgrounds.filter(item => bg["url"] !== item["url"])])
    }
    return (
        <Grid container>
            <Grid item xs={12}>
                <form onSubmit={submitTelop}>
                    <TextField multiline margin="dense" label="テロップ" fullWidth defaultValue={telop} inputRef={telopRef} />
                    <Button variant="contained" type="submit">更新</Button>
                </form>
            </Grid>
            <Grid item xs={12}>
                <Grid container justifyContent="center" alignItems="flex-start">
                {backgrounds && backgrounds.map(bg => 
                    <Grid item className="img-preview-container">
                        <Card className="img-preview">
                            <CardHeader subheader={bg['name']} action={<IconButton size="small" onClick={() => {deleteBG(bg)}}><Close /></IconButton> } />
                            {bg['ext'] === ".mp4" ? <video title={bg['name']} src={bg['url']} onClick={() => setBackground(bg)} /> :
                            <img title={bg['name']} alt={bg['name']} src={bg['url']} onClick={() => {setBackground(bg)}} />}
                        </Card>
                    </Grid>
                )}
                </Grid>
            </Grid>
        </Grid>
    )
}
export default App
src/dashboard/layout/index.css
.img-preview {
    margin: 10px;
    position: relative;
}

.img-preview > img,
.img-preview > video {
    max-width: 300px;
}

.img-preview > img:hover,
.img-preview > video:hover {
    cursor: pointer;
}

配信画面に載せる画像ファイルを選択する部分はファイル名だけ並べていても分かりづらいと思ったのでプレビューを表示させるようにしています。
↓実装イメージ
NodeCG03.jpg

graphics

graphicsは特筆して書くこともないので畳んでおきます。

src/graphics/layout/App.tsx
import { useReplicant } from "../../hooks";

function App() {
    const [ telop ] = useReplicant<"telop">("telop");
    const [ background ] = useReplicant<"background">("background");
    return (
        <>
            {!background ? null :
            background['ext'] === ".mp4" ? 
                <video src={background['url']} autoPlay loop muted className="background-image" /> : 
                <img src={background['url']} className="background-image" />
            }
            <div id="telop">{telop}</div>
        </>
    )
}
export default App
src/graphics/layout/index.css
body {
    background-color: transparent;
    margin: 0;
    overflow: hidden;
}
  
.background-image {
    width: 1920px;
    height: 1080px;
}

#telop {
    width: 100%;
    font-size: 36px;
    min-height: 128px;
    display: flex;
    align-items: center;
    color: #f0f0f0;
    background-color: rgba(16, 16, 16, 0.8);
    padding: 10px;
    position: fixed;
    bottom: 0;
}

成果物

ビルドした後の実装イメージです。
プレビュー画像をクリックすることで配信画面の背景画像を変更できるようになりました。

NodeCG04.gif

おわりに

さて、今回はNodeCGダッシュボードで背景画像を変更するためassets機能を利用しましたが、assetsについてまとめている記事が全然見つからずにかなり苦戦しました(assetsについて分かりやすくまとめている記事があればぜひコメントで教えてください・・・)。

参考

6
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?