CSS랑 자바스크립트 아래거로 바꾸고


https://cdn.jsdelivr.net/gh/BabybirdOligodendrocyte/bokitubebirdtheme-server@master/channel/style.css


https://cdn.jsdelivr.net/gh/BabybirdOligodendrocyte/bokitubebirdtheme-server@master/channel/script.js




javascript에


var channelName = "니케FC 중계방";

var faviconUrl = "<custom favicon URL here>";

var scrollingBannerEnabled = false; //true or false

//$.get('https://cdn.jsdelivr.net/gh/deerfarce/cytube-nnd-chat@master/index.js')


function Inline4CC() {


  $('#messagebuffer').off('click').click(e => {


        let t = e.target, p = t.parentElement;


        if(e.button != 0) return;


        if(t.className == 'channel-emote')


            $('#chatline').val((i, v) => v + ' ' + e.target.title).focus();


        else if(t.tagName == "IMG") {


            e.preventDefault();


            $('<div id="picoverlay"></div>').click(f => $('#picoverlay').remove()).prependTo('body').append($(p).clone());


        } else if(t.tagName == "VIDEO") {


            e.preventDefault();


            $('<div id="picoverlay"></div>').click(f => $('#picoverlay').remove()).prependTo('body').append($('<video autoplay controls/>').attr('src', t.src));


        }


    });


}

//if teamcolor.js is already loaded, run the inline  immediately, otherwise the teamcolor  will run the inline itself


Inline4CC();


/* Disable / remove Buddy feature completely */

(function disableBuddyFeature() {

  const BUDDY_SELECTOR = [

    '#buddy-settings-btn',

    '#buddy-settings-overlay',

    '#buddy-settings-popup',

    '#buddy-container',

    '#buddy-layer',

    '#buddy-stage',

    '.buddy',

    '.buddy-character',

    '.buddy-sprite',

    '.buddy-name',

    '.buddy-speech',

    '.buddy-bubble',

    '.chat-buddy',

    '[id*="buddy"]',

    '[class*="buddy"]'

  ].join(',');


  function removeBuddyElements(root = document) {

    root.querySelectorAll(BUDDY_SELECTOR).forEach(el => {

      el.remove();

    });

  }


  function clearBuddyStorage() {

    try {

      Object.keys(localStorage).forEach(key => {

        if (/buddy/i.test(key)) {

          localStorage.removeItem(key);

        }

      });

    } catch (e) {

      console.warn('[DisableBuddy] localStorage clear failed:', e);

    }

  }


  function disableBuddyGlobals() {

    try {

      // Buddy 관련 함수들이 존재하면 무력화

      const noop = function () {};


      [

        'createBuddySettingsPopup',

        'openBuddySettingsPopup',

        'closeBuddySettingsPopup',

        'toggleBuddySettingsPopup',

        'broadcastMyBuddySettings',

        'applyMyBuddySettings',

        'applyCustomSettingsToBuddy',

        'selectBuddySprite',

        'applyCustomBuddySprite',

        'selectBuddySize',

        'selectBuddyPersonality',

        'selectBuddyIdleStyle',

        'selectBuddyMovementStyle',

        'selectBuddySocialTendency',

        'selectBuddyPosition'

      ].forEach(name => {

        try {

          window[name] = noop;

        } catch (e) {}

      });


      // Buddy 데이터 객체가 전역에 있으면 비움

      if (window.buddyCharacters) {

        window.buddyCharacters = {};

      }


      if (window.myBuddySettings) {

        window.myBuddySettings = null;

      }

    } catch (e) {

      console.warn('[DisableBuddy] global disable failed:', e);

    }

  }


  function disableBuddy() {

    clearBuddyStorage();

    disableBuddyGlobals();

    removeBuddyElements();

  }


  // 최초 실행

  disableBuddy();


  // 외부 스크립트가 나중에 buddy를 다시 만들 경우 즉시 제거

  const observer = new MutationObserver(mutations => {

    for (const mutation of mutations) {

      mutation.addedNodes.forEach(node => {

        if (node.nodeType !== 1) return;


        if (node.matches && node.matches(BUDDY_SELECTOR)) {

          node.remove();

          return;

        }


        if (node.querySelectorAll) {

          removeBuddyElements(node);

        }

      });

    }

  });


  observer.observe(document.documentElement, {

    childList: true,

    subtree: true

  });


  // 혹시 타이머/애니메이션으로 계속 부활하는 경우 대비

  setInterval(disableBuddy, 2000);

})();






/* CyTube slash emote search only */

(function () {

  "use strict";


  const AC = "bb-slash-emote-ac";

  let emotes = [];

  let acIdx = -1;


  const $ = (s, r = document) => r.querySelector(s);

  const $$ = (s, r = document) => Array.from(r.querySelectorAll(s));


  function loadEmotes() {

    if (!window.CHANNEL || !Array.isArray(CHANNEL.emotes)) return false;


    emotes = CHANNEL.emotes

      .filter(e => e && e.name && e.image)

      .map(e => {

        const raw = String(e.name).replace(/^\//, "");


        return {

          // 화면 표시용: slash 검색 기능이라는 걸 알기 쉽게 /를 붙여 보여줌

          name: "/" + raw,


          // 실제 채팅창에 삽입할 값: slash 제거

          raw: raw,


          image: e.image

        };

      })

      .sort((a, b) => a.raw.localeCompare(b.raw));


    return emotes.length > 0;

  }


  function chatline() {

    return $("#chatline");

  }


  function cleanupOldPanels() {

    [

      "#bb-mini-emote-btn",

      "#bb-mini-emote-panel",

      "#bb-mini-emote-ac",

      "#bb-ep-btn",

      "#bb-ep-panel",

      "#bb-ep-ac",

      "#bb-fixed-ep-btn",

      "#bb-fixed-emotespanel",

      "#bb-fixed-ep-ac"

    ].forEach(sel => $$(sel).forEach(el => el.remove()));

  }


  function closeAc() {

    const old = $("#" + AC);

    if (old) old.remove();

    acIdx = -1;

  }


  function currentSlashWord() {

    const input = chatline();

    if (!input) return null;


    const pos = input.selectionStart ?? input.value.length;

    const before = input.value.slice(0, pos);


    // 현재 커서 앞쪽에서 "/검색어" 형태만 감지

    const m = before.match(/(^|\s)\/([^\s/]*)$/);


    return m ? (m[2] || "").toLowerCase() : null;

  }


  function insertEmote(rawName) {

    const input = chatline();

    if (!input) return;


    // 혹시라도 "/emote"가 들어와도 최종 삽입 전 slash 제거

    const insertName = String(rawName || "").replace(/^\//, "");

    if (!insertName) return;


    const start = input.selectionStart ?? input.value.length;

    const end = input.selectionEnd ?? start;


    const before = input.value.slice(0, start);

    const after = input.value.slice(end);


    // 커서 앞의 "/검색어" 부분을 찾아서 그 부분만 이모티콘명으로 치환

    const m = before.match(/(^|\s)\/[^\s/]*$/);


    if (m) {

      const cut = before.length - m[0].length;

      const keep = m[1] || "";


      input.value = before.slice(0, cut) + keep + insertName + " " + after;


      input.selectionStart = input.selectionEnd =

        before.slice(0, cut).length + keep.length + insertName.length + 1;

    } else {

      const add = (before && !/\s$/.test(before) ? " " : "") + insertName + " ";


      input.value = before + add + after;

      input.selectionStart = input.selectionEnd = before.length + add.length;

    }


    input.focus();

    closeAc();


    // CyTube 쪽에서 input/change 감지를 쓰는 경우를 위한 이벤트 발생

    input.dispatchEvent(new Event("input", { bubbles: true }));

    input.dispatchEvent(new Event("change", { bubbles: true }));

  }


  function showAc() {

    closeAc();


    if (!loadEmotes()) return;


    const input = chatline();

    const key = currentSlashWord();


    if (!input || key === null) return;


    const found = emotes

      .filter(e =>

        e.raw.toLowerCase().includes(key) ||

        e.name.toLowerCase().includes(key)

      )

      .slice(0, 12);


    if (!found.length) return;


    const box = document.createElement("div");

    box.id = AC;


    found.forEach((e, i) => {

      const row = document.createElement("div");

      row.className = "bb-slash-emote-row" + (i === 0 ? " active" : "");


      row.innerHTML =

        '<img src="' + e.image + '" loading="lazy">' +

        '<span>' + e.name + "</span>";


      // 실제 삽입값을 data-raw에 저장

      row.dataset.raw = e.raw;


      row.addEventListener("mousedown", ev => {

        ev.preventDefault();

        insertEmote(row.dataset.raw);

      });


      box.appendChild(row);

    });


    acIdx = 0;


    const form = input.closest("form") || input.parentNode;

    if (!form) return;


    if (getComputedStyle(form).position === "static") {

      form.style.position = "relative";

    }


    form.appendChild(box);

  }


  function moveAc(dir) {

    const rows = $$("#" + AC + " .bb-slash-emote-row");

    if (!rows.length) return false;


    rows.forEach(r => r.classList.remove("active"));


    acIdx += dir;


    if (acIdx < 0) acIdx = rows.length - 1;

    if (acIdx >= rows.length) acIdx = 0;


    rows[acIdx].classList.add("active");

    rows[acIdx].scrollIntoView({ block: "nearest" });


    return true;

  }


  function pickAc() {

    const row = $("#" + AC + " .bb-slash-emote-row.active");

    if (!row) return false;


    insertEmote(row.dataset.raw);

    return true;

  }


  function bindChatline() {

    const input = chatline();

    if (!input || input.dataset.bbSlashEmoteBound) return;


    input.dataset.bbSlashEmoteBound = "1";


    input.addEventListener("input", showAc);


    input.addEventListener("keydown", e => {

      if (!$("#" + AC)) return;


      if (e.key === "ArrowDown") {

        e.preventDefault();

        moveAc(1);

      } else if (e.key === "ArrowUp") {

        e.preventDefault();

        moveAc(-1);

      } else if (e.key === "Tab") {

        if (pickAc()) e.preventDefault();

      } else if (e.key === "Enter") {

        if (pickAc()) e.preventDefault();

      } else if (e.key === "Escape") {

        closeAc();

      }

    });


    input.addEventListener("blur", () => {

      setTimeout(closeAc, 150);

    });

  }


  function boot() {

    cleanupOldPanels();

    bindChatline();


    if (!loadEmotes()) {

      setTimeout(boot, 1000);

    }

  }


  const mo = new MutationObserver(() => {

    cleanupOldPanels();

    bindChatline();

  });


  mo.observe(document.documentElement, {

    childList: true,

    subtree: true

  });


  if (document.readyState === "loading") {

    document.addEventListener("DOMContentLoaded", boot);

  } else {

    boot();

  }

})();






css에


:root {


    --leftcontentvw:  78.4vw; /* Width of video player section, chat will fill the rest */


    --bannerimg: url("INSERT YOUR IMAGE HERE"); /* Sliding banner image in MOTD */


    --dialogbgimageurl: url("INSERT YOUR IMAGE HERE"); /* Modal background image */


    --bgimageurl: url("INSERT YOUR IMAGE HERE"); /* Background channel image */


    --primarycolor: #000000;


    --secondarycolor: #2e2e2e;


    --tertiarycolor: #627b83;


}


.channel-emote {


    min-height: 100px!important;


    max-height: 100px!important;


    max-width: 400px!important;


}



/* ===========================================================


   Embed 경고창에서 Embed 버튼만 남기고 나머지 제거


   =========================================================== */


#ytapiplayer .alert.alert-warning {


    padding: 8px !important;


    text-align: center;


}




/* 제목, strong, 텍스트, 링크 모두 숨김 */


#ytapiplayer .alert.alert-warning strong,


#ytapiplayer .alert.alert-warning br,


#ytapiplayer .alert.alert-warning a,


#ytapiplayer .alert.alert-warning hr,


#ytapiplayer .alert.alert-warning .close {


    display: none !important;


}




/* Embed 버튼만 보이도록 유지 */


#ytapiplayer .alert.alert-warning .btn {


    display: inline-block !important;


    width: auto;


    margin: 0 auto;


}


#font-tags-btn,

#draw-btn {

  display: none !important;

}


#buddy-settings-btn,

#buddy-settings-overlay,

#buddy-settings-popup,

#buddy-container,

#buddy-layer,

#buddy-stage,

.buddy,

.buddy-character,

.buddy-sprite,

.buddy-name,

.buddy-speech,

.buddy-bubble,

.chat-buddy,

[id*="buddy"],

[class*="buddy"] {

  display: none !important;

  visibility: hidden !important;

  opacity: 0 !important;

  pointer-events: none !important;

}








/* Slash emote search only */

#bb-slash-emote-ac {

  absolute;

  left: 0;

  right: 0;

  bottom: 100%;

  z-index: 10000;

  max-height: 250px;

  overflow-y: auto;

  background: #202020;

  border: 1px solid rgba(255, 255, 255, .16);

  border-radius: 5px 5px 0 0;

  box-shadow: 0 -8px 22px rgba(0, 0, 0, .35);

}


.bb-slash-emote-row {

  display: flex;

  align-items: center;

  gap: 8px;

  height: 34px;

  padding: 4px 8px;

  color: #eee;

  cursor: pointer;

  line-height: 1;

  box-sizing: border-box;

}


.bb-slash-emote-row:hover,

.bb-slash-emote-row.active {

  background: rgba(255, 255, 255, .14);

}


.bb-slash-emote-row img {

  width: 26px;

  height: 26px;

  object-fit: contain;

  flex: 0 0 auto;

}


.bb-slash-emote-row span {

  overflow: hidden;

  white-space: nowrap;

  text-overflow: ellipsis;

  font-size: 12px;

}


/* Remove previous mini emote panel leftovers */

#bb-mini-emote-btn,

#bb-mini-emote-panel,

#bb-mini-emote-ac,

#bb-ep-btn,

#bb-ep-panel,

#bb-ep-ac,

#bb-fixed-ep-btn,

#bb-fixed-emotespanel,

#bb-fixed-ep-ac {

  display: none !important;

}


/* 모바일에서 사라진 채팅 UI를 다시 여는 우측 상단 버튼 커스텀 */

@media only screen and (max-width: 768px) {

  #mobile-ui-indicator {

    top: 14px !important;

    right: 14px !important;


    /* 기존 14x14 기준 약 4배 */

    width: 56px !important;

    height: 56px !important;


    border-radius: 16px !important;

    opacity: 0 !important;

    pointer-events: none !important;


    background: rgba(15, 15, 20, 0.82) !important;

    border: 1px solid rgba(255, 255, 255, 0.38) !important;

    box-shadow:

      0 8px 24px rgba(0, 0, 0, 0.45),

      inset 0 1px 0 rgba(255, 255, 255, 0.18) !important;


    backdrop-filter: blur(8px) !important;

    -webkit-backdrop-filter: blur(8px) !important;


    z-index: 999999 !important;

  }


  /* UI가 숨겨졌을 때만 버튼 보이기 */

  body.mobile-ui-idle:not(.mobile-chat-open) #mobile-ui-indicator {

    opacity: 0.92 !important;

    pointer-events: auto !important;

  }


  /* 채팅창 아이콘 */

  #mobile-ui-indicator::before {

    content: "" !important;

    absolute !important;

    left: 50% !important;

    top: 50% !important;

    width: 30px !important;

    height: 24px !important;

    transform: translate(-50%, -50%) !important;


    background: rgba(255, 255, 255, 0.92) !important;

    border-radius: 8px !important;

    box-shadow: 0 2px 6px rgba(0, 0, 0, 0.25) !important;

  }


  /* 말풍선 꼬리 */

  #mobile-ui-indicator::after {

    content: "" !important;

    absolute !important;

    left: 20px !important;

    bottom: 14px !important;

    width: 10px !important;

    height: 10px !important;


    background: rgba(255, 255, 255, 0.92) !important;

    transform: rotate(45deg) !important;

    border-radius: 2px !important;

  }


  /* 채팅 말풍선 안쪽 줄 */

  body.mobile-ui-idle:not(.mobile-chat-open) #mobile-ui-indicator {

    background-image:

      linear-gradient(

        rgba(15, 15, 20, 0.82),

        rgba(15, 15, 20, 0.82)

      ) !important;

  }


  body.mobile-ui-idle:not(.mobile-chat-open) #mobile-ui-indicator::before {

    background:

      linear-gradient(

        to bottom,

        transparent 0,

        transparent 6px,

        rgba(80, 80, 90, 0.95) 6px,

        rgba(80, 80, 90, 0.95) 8px,

        transparent 8px,

        transparent 12px,

        rgba(80, 80, 90, 0.95) 12px,

        rgba(80, 80, 90, 0.95) 14px,

        transparent 14px

      ),

      rgba(255, 255, 255, 0.94) !important;

  }


  /* 터치하기 쉽게 살짝 눌림 효과 */

  #mobile-ui-indicator:active {

    transform: scale(0.94) !important;

  }

}




//폰트

/* ================================

   Chat Font Custom

   - 한국어 스트림/커뮤니티 UI용 폰트

   - 폰트 크기 조절 변수 포함

================================ */


/* 폰트 크기 조절 */

:root {

  --chat-font-size: 14px;

  --chat-line-height: 1.45;

  --chat-font-weight: 400;

}


/* 채팅창 전체 폰트 */

#chatwrap,

#chatline,

#messagebuffer,

#chatinput,

#chatheader,

#userlist,

#userlisttoggle,

#emotelist,

#chatcontrols,

#chatwrap button,

#chatwrap input,

#chatwrap textarea,

#chatwrap select {

  font-family:

    "Pretendard",

    "Noto Sans KR",

    "Apple SD Gothic Neo",

    "Malgun Gothic",

    "맑은 고딕",

    system-ui,

    -apple-system,

    BlinkMacSystemFont,

    sans-serif !important;

}


/* 채팅 메시지 본문 */

#messagebuffer .chat-msg,

#messagebuffer .message,

#messagebuffer .server-whisper,

#messagebuffer .server-msg,

#messagebuffer div[class*="chat"],

#messagebuffer div[class*="message"] {

  font-size: var(--chat-font-size) !important;

  line-height: var(--chat-line-height) !important;

  font-weight: var(--chat-font-weight) !important;

  letter-spacing: -0.01em !important;

}


/* 닉네임 */

#messagebuffer .username,

#messagebuffer .user,

#messagebuffer .nick,

#messagebuffer strong {

  font-family:

    "Pretendard",

    "Noto Sans KR",

    "Apple SD Gothic Neo",

    "Malgun Gothic",

    "맑은 고딕",

    system-ui,

    sans-serif !important;


  font-weight: 600 !important;

  letter-spacing: -0.015em !important;

}


/* 시간 표시 */

#messagebuffer .timestamp,

#messagebuffer .time,

#messagebuffer .chat-timestamp {

  font-size: calc(var(--chat-font-size) - 1px) !important;

  line-height: var(--chat-line-height) !important;

  font-weight: 400 !important;

  opacity: 0.72;

}


/* 채팅 입력창 */

#chatline,

#chatinput input,

#chatinput textarea,

input[name="chatline"] {

  font-size: var(--chat-font-size) !important;

  line-height: var(--chat-line-height) !important;

  font-weight: 400 !important;

  letter-spacing: -0.01em !important;

}


/* 모바일 채팅 UI */

#mobile-chat-overlay,

#mobile-chat-overlay *,

#mobile-quick-input,

#mobile-quick-input *,

#mobile-chat-toggle {

  font-family:

    "Pretendard",

    "Noto Sans KR",

    "Apple SD Gothic Neo",

    "Malgun Gothic",

    "맑은 고딕",

    system-ui,

    -apple-system,

    BlinkMacSystemFont,

    sans-serif !important;

}


/* 모바일 메시지 크기 */

@media only screen and (max-width: 768px) {

  :root {

    --chat-font-size: 14px;

    --chat-line-height: 1.5;

  }


  #messagebuffer .chat-msg,

  #messagebuffer .message,

  #messagebuffer div[class*="chat"],

  #messagebuffer div[class*="message"],

  #mobile-chat-overlay,

  #mobile-chat-overlay * {

    font-size: var(--chat-font-size) !important;

    line-height: var(--chat-line-height) !important;

  }

}


/* 한 채팅 메시지 안에서 4번째 이후 채널 이모티콘 숨김 */

#messagebuffer > div > span img.channel-emote:nth-of-type(n+4) {

  display: none !important;

}























일단 이렇게 해서 써보길 바람


혹시 당황해서 4cc갤 찾아오는 사람 있을까봐 남겨둠