아프리카TV - 사이드바 UI 변경

아프리카TV의 사이드바 UI를 변경합니다.

目前为 2024-01-22 提交的版本。查看 最新版本

// ==UserScript==
// @name         아프리카TV - 사이드바 UI 변경
// @name:ko         아프리카TV - 사이드바 UI 변경
// @namespace    https://www.afreecatv.com/
// @version      2024-01-38
// @description  아프리카TV의 사이드바 UI를 변경합니다.
// @description:ko  아프리카TV의 사이드바 UI를 변경합니다.
// @author       You
// @match        https://www.afreecatv.com/
// @match        https://www.afreecatv.com/?hash=*
// @icon         https://www.google.com/s2/favicons?sz=64&domain=afreecatv.com
// @grant        GM_addStyle
// @grant        GM_xmlhttpRequest
// @grant        GM_setValue
// @grant        GM_getValue
// @grant        GM_registerMenuCommand
// @grant        GM_unregisterMenuCommand
// @run-at       document-end
// @license MIT
// ==/UserScript==

(function() {
    'use strict';
    const currentUrl = window.location.href;

    let coloring_live = GM_getValue("coloring_live", 1);
    let display_follow = GM_getValue("display_follow", 6);
    let display_myplus = GM_getValue("display_myplus", 6);
    let display_top = GM_getValue("display_top", 6);
    let myplus_position = GM_getValue("myplus_position", 1);
    let myplus_order = GM_getValue("myplus_order", 1);
    let blockedUsers = GM_getValue('blockedUsers', []);
    let blockedCategories = GM_getValue('blockedCategories', []) || [];
    let menuIds = {};
    let categoryMenuIds = {};

    const css_Darkmode = `
#list-container {
    overflow-x: hidden;
}
#listMain #wrap {
    min-width: 960px;
}
#listMain #wrap #serviceHeader {
    min-width: 960px;
}
#listMain #wrap #list-container #list-section {
    padding: 12px 22px 0 38px;
}
button.block-icon-svg-white {
  width: 40px;
  height: 50px;
}
button.block-icon-svg-white span {
    background-image: url('data:image/svg+xml,%3Csvg xmlns="http://www.w3.org/2000/svg" x="0px" y="0px" width="100" height="100" viewBox="0 0 64 64" style="fill:%23B2B2B2;"%3E%3Cpath d="M32 6C17.641 6 6 17.641 6 32C6 46.359 17.641 58 32 58C46.359 58 58 46.359 58 32C58 17.641 46.359 6 32 6zM32 10C37.331151 10 42.225311 11.905908 46.037109 15.072266L14.505859 45.318359C11.682276 41.618415 10 37.00303 10 32C10 19.869 19.869 10 32 10zM48.927734 17.962891C52.094092 21.774689 54 26.668849 54 32C54 44.131 44.131 54 32 54C26.99697 54 22.381585 52.317724 18.681641 49.494141L48.927734 17.962891z"%3E%3C/path%3E%3C/svg%3E');
    background-size: 100% 100%;
    width: 20px;
    height: 20px;
}
button.block-icon-svg-white:hover span {
    background-image: url('data:image/svg+xml,%3Csvg xmlns="http://www.w3.org/2000/svg" x="0px" y="0px" width="100" height="100" viewBox="0 0 64 64" style="fill:%235285FF;"%3E%3Cpath d="M32 6C17.641 6 6 17.641 6 32C6 46.359 17.641 58 32 58C46.359 58 58 46.359 58 32C58 17.641 46.359 6 32 6zM32 10C37.331151 10 42.225311 11.905908 46.037109 15.072266L14.505859 45.318359C11.682276 41.618415 10 37.00303 10 32C10 19.869 19.869 10 32 10zM48.927734 17.962891C52.094092 21.774689 54 26.668849 54 32C54 44.131 44.131 54 32 54C26.99697 54 22.381585 52.317724 18.681641 49.494141L48.927734 17.962891z"%3E%3C/path%3E%3C/svg%3E');
}
html {
    overflow: hidden;
}
.users-section.myplus > .user.show-more {
    display: none;
}
.users-section.follow > .user.show-more {
    display: none;
}
.users-section.top > .user.show-more {
    display: none;
}
#toggleButton, #toggleButton2, #toggleButton3 {
    padding:12px;
    color:#e5e5e5;
}
.left_navbar {
    display: flex;
    align-items: center;
    justify-content: flex-end;
    position: absolute;
    flex-direction: row-reverse;
    top: 0px;
    left: 160px;
}
.left_nav_button {
    position: relative;
    width: 70px;
    height: 70px;
    padding: 0;
    border: 0;
    border-radius: 50%;
    cursor: pointer;
    z-index: 3001;
    transition: all .2s;
    color: #e5e5e5;
    font-size: 15px;
    font-weight: 600;
}
.left_nav_button.active {
    color: #019BFE;
}
#sidebar {
    width: 240px;
    grid-area: sidebar;
    background-color: #1F1F23;
    color:white;
    margin-right:10px;
    padding-bottom:260px;
}

#sidebar .top-section {
    display: flex;
    align-items: center;
    justify-content: space-around;
    margin: 10px 0px;
}

#sidebar .top-section>span {
    text-transform: uppercase;
    font-weight: 550;
    font-size: 14px;
    margin-top: 6px;
    margin-bottom: 4px;
    color:#DEDEE3;
}

#sidebar .top-section>span>a {
    color:#DEDEE3;
}

#sidebar .twitch-message-section {
    margin: 0px 10px;
    margin-top: 10px;
    padding: 0 25px;
    background-color: #1F1F23;
}

#sidebar .twitch-message-section .title {
    margin: 0px;
    font-size: 1.5rem;
    font-weight: 500;
}

#sidebar .twitch-message-section .title>span {
    color: var(--primary-color);
}

#sidebar .twitch-message-section .description {
    margin: 8px 0px;
    line-height: 1.3rem;
    font-size: 0.9rem;
    color: #A1A1A1;
}
#sidebar .twitch-message-section .description>span {
    display: block;
    text-align: center;
}

.user {
    display: grid;
    grid-template-areas: "profile-picture username watchers" "profile-picture description blank";
    grid-template-columns: 40px auto auto;
    padding: 6px 10px;
}

.user:hover {
    background-color: #26262c;
    cursor: pointer;
}

.user .profile-picture {
    grid-area: profile-picture;
    width: 32px;
    height: 32px;
    border-radius: 50%;
}

.user .username {
    grid-area: username;
    font-size: 14px;
    font-weight: 600;
    color:#DEDEE3;
}

.user .description {
    grid-area: description;
    font-size: 13px;
    color: #a1a1a1;
    font-weight: 400;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.user .watchers {
    grid-area: watchers;
    display: flex;
    align-items: center;
    justify-content: flex-end;
    font-weight: 400;
    font-size: 14px;
    color: #c0c0c0;
    margin-right: 2px;
}

.user .watchers .dot {
    font-size: 7px;
    margin-right: 5px;
}

#listMain #wrap #serviceHeader #afLogo {
    left: 30px;
    height: 72px;
}

.btn_flexible {
    display: none;
}

#innerLnb {
    display: none;
}

#list-container {
    height: 100vh;
    overflow-y: auto;
}

#sidebar {
    height: 100vh;
    overflow-y: auto;
    position: fixed;
}

#sidebar::-webkit-scrollbar {
    display: none;  /* Chrome, Safari, Edge */
}


.tooltip-container {
    z-index: 999;
    width: 320px;
    height: auto;
    position: fixed;
    background-color: #26262C;
}
.tooltip-container img {
    position: relative;
    z-index: 999;
    width: auto;
    height: auto;
    max-height:240px
}
.tooltiptext {
    position: relative;
    z-index: 999;
    width: 320px;
    height: 48px;
    background-color: #26262C;
    color: #fff;
    text-align: center;
    display: flex;
    align-items: center; /* 세로 가운데 정렬 */
    justify-content: center; /* 가로 가운데 정렬 */
    top:-4px;
}

    `;

    const css_Whitemode = `
#list-container {
    overflow-x: hidden;
}
#listMain #wrap {
    min-width: 960px;
}
#listMain #wrap #serviceHeader {
    min-width: 960px;
}
#listMain #wrap #list-container #list-section {
    padding: 12px 22px 0 38px;
}
button.block-icon-svg {
  width: 40px;
  height: 50px;
}
button.block-icon-svg span {
    background-image: url('data:image/svg+xml,%3Csvg xmlns="http://www.w3.org/2000/svg" x="0px" y="0px" width="100" height="100" viewBox="0 0 64 64" style="fill:%237C7D7D;"%3E%3Cpath d="M32 6C17.641 6 6 17.641 6 32C6 46.359 17.641 58 32 58C46.359 58 58 46.359 58 32C58 17.641 46.359 6 32 6zM32 10C37.331151 10 42.225311 11.905908 46.037109 15.072266L14.505859 45.318359C11.682276 41.618415 10 37.00303 10 32C10 19.869 19.869 10 32 10zM48.927734 17.962891C52.094092 21.774689 54 26.668849 54 32C54 44.131 44.131 54 32 54C26.99697 54 22.381585 52.317724 18.681641 49.494141L48.927734 17.962891z"%3E%3C/path%3E%3C/svg%3E');
    background-size: 100% 100%;
    width: 20px;
    height: 20px;
}
button.block-icon-svg:hover span {
    background-image: url('data:image/svg+xml,%3Csvg xmlns="http://www.w3.org/2000/svg" x="0px" y="0px" width="100" height="100" viewBox="0 0 64 64" style="fill:%235285FF;"%3E%3Cpath d="M32 6C17.641 6 6 17.641 6 32C6 46.359 17.641 58 32 58C46.359 58 58 46.359 58 32C58 17.641 46.359 6 32 6zM32 10C37.331151 10 42.225311 11.905908 46.037109 15.072266L14.505859 45.318359C11.682276 41.618415 10 37.00303 10 32C10 19.869 19.869 10 32 10zM48.927734 17.962891C52.094092 21.774689 54 26.668849 54 32C54 44.131 44.131 54 32 54C26.99697 54 22.381585 52.317724 18.681641 49.494141L48.927734 17.962891z"%3E%3C/path%3E%3C/svg%3E');
}
html {
    overflow: hidden;
}
.users-section.myplus > .user.show-more {
    display: none;
}
.users-section.follow > .user.show-more {
    display: none;
}
.users-section.top > .user.show-more {
    display: none;
}
#toggleButton, #toggleButton2, #toggleButton3 {
    padding:12px;
    color:black;
}
.left_navbar {
    display: flex;
    align-items: center;
    justify-content: flex-end;
    position: absolute;
    flex-direction: row-reverse;
    top: 0px;
    left: 160px;
}
.left_nav_button {
    position: relative;
    width: 70px;
    height: 70px;
    padding: 0;
    border: 0;
    border-radius: 50%;
    cursor: pointer;
    z-index: 3001;
    transition: all .2s;
    color: black;
    font-size: 15px;
    font-weight: 600;
}
.left_nav_button.active {
  color: #0545B1;
}
#sidebar {

    font-family:'Malgun Gothic';
    width: 240px;
    grid-area: sidebar;
    background-color: #EFEFF1;
    color:black;
    padding-bottom:260px;
}

#sidebar .top-section {
    display: flex;
    align-items: center;
    justify-content: space-around;
    margin: 10px 0px;
}

#sidebar .top-section>span {
    text-transform: uppercase;
    font-weight: 600;
    font-size: 14px;
    margin-top: 6px;
    margin-bottom: 4px;
    color:#0E0E10;
}

#sidebar .top-section>span>a {
    color:#0E0E10;
}

#sidebar .twitch-message-section {
    margin: 0px 10px;
    margin-top: 10px;
    padding: 0 25px;
    background-color: #EFEFF1;
}

#sidebar .twitch-message-section .title {
    margin: 0px;
    font-size: 1.5rem;
    font-weight: 500;
}

#sidebar .twitch-message-section .title>span {
    color: var(--primary-color);
}

#sidebar .twitch-message-section .description {
    margin: 8px 0px;
    line-height: 1.3rem;
    font-size: 0.9rem;
    color: #53535F;
}

#sidebar .twitch-message-section .description>span {
    display: block;
    text-align: center;
}


.user {
    display: grid;
    grid-template-areas: "profile-picture username watchers" "profile-picture description blank";
    grid-template-columns: 40px auto auto;
    padding: 6px 10px;
}

.user:hover {
    background-color: #E6E6EA;
    cursor: pointer;
}

.user .profile-picture {
    grid-area: profile-picture;
    width: 32px;
    height: 32px;
    border-radius: 50%;
}

.user .username {
    grid-area: username;
    font-size: 14px;
    font-weight: 600;
    color:#1F1F23;
}

.user .description {
    grid-area: description;
    font-size: 13px;
    font-weight: 400;
    color: #53535F;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.user .watchers {
    grid-area: watchers;
    display: flex;
    align-items: center;
    justify-content: flex-end;
    font-size: 14px;
    font-weight: 400;
    color: black;
    margin-right: 2px;
}

.user .watchers .dot {
    font-size: 7px;
    margin-right: 5px;
}

#listMain #wrap #serviceHeader #afLogo {
    left: 30px;
    height: 72px;
}

.btn_flexible {
    display: none;
}

#innerLnb {
    display: none;
}

#list-container {
    height: 100vh;
    overflow-y: auto;
}

#sidebar {
    height: 100vh;
    overflow-y: auto;
    position: fixed;
}

#sidebar::-webkit-scrollbar {
    display: none;  /* Chrome, Safari, Edge */
}

.tooltip-container {
    z-index: 999;
    width: 320px;
    height: auto;
    position: fixed;
    background-color: #E6E6EA;
}
.tooltip-container img {
    position: relative;
    z-index: 999;
    width: auto;
    height: auto;
    max-height:240px
}
.tooltiptext {
    position: relative;
    z-index: 999;
    width: 320px;
    height: 48px;
    background-color: #E6E6EA;
    color: black;
    text-align: center;
    display: flex;
    align-items: center; /* 세로 가운데 정렬 */
    justify-content: center; /* 가로 가운데 정렬 */
    top:-4px;
}
    `;

    // 차단 목록을 저장합니다.
    function saveBlockedUsers() {
        GM_setValue('blockedUsers', blockedUsers);
    }

    // 사용자를 차단 목록에 추가합니다.
    function blockUser(userName, userId) {
        // 이미 차단된 사용자인지 확인
        if (!isUserBlocked(userId)) {
            blockedUsers.push({ userName, userId });
            saveBlockedUsers();
            alert(`사용자 ${userName}(${userId})를 차단했습니다.`);
            registerUnblockMenu({ userName, userId });
        } else {
            alert(`사용자 ${userName}(${userId})는 이미 차단되어 있습니다.`);
        }
    }

    // 함수: 사용자 차단 해제
    function unblockUser(userId) {
        // 차단된 사용자 목록에서 해당 사용자 찾기
        let unblockedUser = blockedUsers.find(user => user.userId === userId);

        // 사용자를 찾았을 때만 차단 해제 및 메뉴 삭제 수행
        if (unblockedUser) {
            // 차단된 사용자 목록에서 해당 사용자 제거
            blockedUsers = blockedUsers.filter(user => user.userId !== userId);

            // 변경된 목록을 저장
            GM_setValue('blockedUsers', blockedUsers);

            alert(`사용자 ${userId}의 차단이 해제되었습니다.`);

            unregisterUnblockMenu(unblockedUser.userName);
        }
    }

    // 사용자가 이미 차단되어 있는지 확인합니다.
    function isUserBlocked(userId) {
        return blockedUsers.some(user => user.userId === userId);
    }

    // 함수: 동적으로 메뉴 등록
    function registerUnblockMenu(user) {
        // GM_registerMenuCommand로 메뉴를 등록하고 메뉴 ID를 기록
        let menuId = GM_registerMenuCommand(`💔 차단 해제 - ${user.userName}`, function() {
            unblockUser(user.userId);
        });

        // 메뉴 ID를 기록
        menuIds[user.userName] = menuId;
    }

    // 함수: 동적으로 메뉴 삭제
    function unregisterUnblockMenu(userName) {
        // userName을 기반으로 저장된 메뉴 ID를 가져와서 삭제
        let menuId = menuIds[userName];
        if (menuId) {
            GM_unregisterMenuCommand(menuId);
            delete menuIds[userName]; // 삭제된 메뉴 ID를 객체에서도 제거
        }
    }

    // 카테고리 목록을 저장합니다.
    function saveBlockedCategories() {
        GM_setValue('blockedCategories', blockedCategories);
    }

    // 카테고리를 차단 목록에 추가합니다.
    function blockCategory(categoryName, categoryId) {
        // 이미 차단된 카테고리인지 확인
        if (!isCategoryBlocked(categoryId)) {
            blockedCategories.push({ categoryName, categoryId });
            saveBlockedCategories();
            alert(`카테고리 ${categoryName}(${categoryId})를 차단했습니다.`);
            registerCategoryUnblockMenu({ categoryName, categoryId });
        } else {
            alert(`카테고리 ${categoryName}(${categoryId})는 이미 차단되어 있습니다.`);
        }
    }

    // 함수: 카테고리 차단 해제
    function unblockCategory(categoryId) {
        // 차단된 카테고리 목록에서 해당 카테고리 찾기
        let unblockedCategory = blockedCategories.find(category => category.categoryId === categoryId);

        // 카테고리를 찾았을 때만 차단 해제 및 메뉴 삭제 수행
        if (unblockedCategory) {
            // 차단된 카테고리 목록에서 해당 카테고리 제거
            blockedCategories = blockedCategories.filter(category => category.categoryId !== categoryId);

            // 변경된 목록을 저장
            GM_setValue('blockedCategories', blockedCategories);

            alert(`카테고리 ${categoryId}의 차단이 해제되었습니다.`);

            unregisterCategoryUnblockMenu(unblockedCategory.categoryName);
        }
    }

    // 카테고리가 이미 차단되어 있는지 확인합니다.
    function isCategoryBlocked(categoryId) {
        return blockedCategories.some(category => category.categoryId === categoryId);
    }

    // 함수: 동적으로 카테고리 메뉴 등록
    function registerCategoryUnblockMenu(category) {
        // GM_registerMenuCommand로 카테고리 메뉴를 등록하고 메뉴 ID를 기록
        let menuId = GM_registerMenuCommand(`💔 카테고리 차단 해제 - ${category.categoryName}`, function() {
            unblockCategory(category.categoryId);
        });

        // 메뉴 ID를 기록
        categoryMenuIds[category.categoryName] = menuId;
    }

    // 함수: 동적으로 카테고리 메뉴 삭제
    function unregisterCategoryUnblockMenu(categoryName) {
        // categoryName을 기반으로 저장된 메뉴 ID를 가져와서 삭제
        let menuId = categoryMenuIds[categoryName];
        if (menuId) {
            GM_unregisterMenuCommand(menuId);
            delete categoryMenuIds[categoryName]; // 삭제된 메뉴 ID를 객체에서도 제거
        }
    }

    function waitForElement(elementSelector, callBack, attempts = 0, maxAttempts = 100) {
        const element = document.querySelector(elementSelector);

        if (element) {
            callBack(elementSelector, element);
        } else {
            if (attempts < maxAttempts) {
                setTimeout(function () {
                    waitForElement(elementSelector, callBack, attempts + 1, maxAttempts);
                }, 200);
            } else {
                console.error('Reached maximum attempts. Element not found.');
            }
        }
    }

    function desc_order(selector){
        // Get the container element
        const container = document.querySelector(selector);

        // Get all user elements
        const userElements = document.querySelectorAll(`${selector} >.user`);

        // Convert NodeList to Array for easier manipulation
        const userArray = Array.from(userElements);

        // Sort userArray based on the data-watchers attribute
        userArray.sort((a, b) => {
            const watchersA = parseInt(a.getAttribute('data-watchers') || '0');
            const watchersB = parseInt(b.getAttribute('data-watchers') || '0');
            return watchersB - watchersA;
        });

        // Clear container and append sorted elements
        container.innerHTML = '';
        userArray.forEach(user => {
            container.appendChild(user);
        });
    }

    function addNumberSeparator(number) {
        // toLocaleString 메서드를 사용하여 숫자에 구분자 추가
        number = Number(number);
        return number.toLocaleString();
    }

    function getCategoryName(cate_no){

        const categoryList = oMainCategory.category_list;

        const filteredList = categoryList.filter(word => !["전체", "제한"].some(keyword => word.menu_name.includes(keyword)));

        const targetActionContent = cate_no;

        const regexPattern = new RegExp(targetActionContent.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"), "i");

        const matchedItem = filteredList.find(item => regexPattern.test(item.action_content));

        // 일치하는 항목이 있다면 해당 항목의 menu_name 리턴, 없으면 null 리턴
        let result = matchedItem ? matchedItem.menu_name : cate_no;

        if(result==="00040121"){
            result = "종합게임";
        }
        if(result==="00300000"){
            result = "연령제한";
        }
        if(result==="ADULT_BROAD_CATE"){
            result = "연령제한";
        }
        if(result==="LoL"){
            result = "리그 오브 레전드";
        }
        if(result==="스타"){
            result = "스타크래프트";
        }
        if(result==="00720000"){
            result = "LCK";
        }

        return result;
    }

    // 사용자 요소를 생성하는 함수
    function createUserElement(channel) {
        const userId = channel.user_id;
        const broadNo = channel.broad_no;
        const totalViewCnt = channel.total_view_cnt;
        const broadTitle = channel.broad_title;
        const userNick = channel.user_nick;
        const playerLink = "https://play.afreecatv.com/"+userId;
        const broad_thumnail = `https://liveimg.afreecatv.com/m/${broadNo}`;

        const userElement = document.createElement('div');
        userElement.classList.add('user');
        userElement.setAttribute('onclick',`window.open('${playerLink}', '_blank')`);
        userElement.setAttribute('data-watchers',`${totalViewCnt}`);
        userElement.setAttribute('broad_thumnail',`${broad_thumnail}`);
        userElement.setAttribute('tooltip',`${broadTitle}`);
        userElement.setAttribute('user_id',`${userId}`);
        //userElement.setAttribute('broad_no',`${broadNo}`);

        const profilePicture = document.createElement('img');
        const pp_webp="https://stimg.afreecatv.com/LOGO/"+userId.slice(0, 2)+"/"+userId+"/m/"+userId+".webp";
        const pp_jpg="https://profile.img.afreecatv.com/LOGO/"+userId.slice(0, 2)+"/"+userId+"/m/"+userId+".jpg";
        profilePicture.src = pp_webp; // 프로필사진
        profilePicture.setAttribute('onerror', `this.onerror=null; this.src='${pp_jpg}'`);
        profilePicture.setAttribute('alt', `${userId}'`);
        profilePicture.setAttribute('onclick', `event.stopPropagation();window.open('https://bj.afreecatv.com/${userId}', '_blank');`);
        //profilePicture.onerror=`this.onerror=null; this.src='${pp_jpg}'`;
        profilePicture.classList.add('profile-picture');
        const username = document.createElement('span');
        username.classList.add('username');
        username.textContent = userNick; //스트리머명

        const cat_no = channel.broad_cate_no;

        const description = document.createElement('span');
        description.classList.add('description');
        description.textContent = getCategoryName(cat_no); //카테고리

        userElement.setAttribute('broad_cate_no',`${cat_no}`);

        const watchers = document.createElement('span');
        watchers.classList.add('watchers');
        if(coloring_live === 1){
            if(channel.auto_hashtags[0]==="웰컴"){
                watchers.innerHTML = `<span class="dot" title="#WELCOME" role="img" aria-label="Amount of people watching">🟣</span>${addNumberSeparator(totalViewCnt)}</span>`;
            } else if(channel.broad_resolution==="2560x1440"){
                watchers.innerHTML = `<span class="dot" title="1440P" role="img" aria-label="Amount of people watching">🟠</span>${addNumberSeparator(totalViewCnt)}</span>`;
            } else {
                watchers.innerHTML = `<span class="dot" role="img" aria-label="Amount of people watching">🔴</span>${addNumberSeparator(totalViewCnt)}</span>`;
            }
        } else {
            watchers.innerHTML = `<span class="dot" role="img" aria-label="Amount of people watching">🔴</span>${addNumberSeparator(totalViewCnt)}</span>`;
        }

        userElement.appendChild(profilePicture);
        userElement.appendChild(username);
        userElement.appendChild(description);
        userElement.appendChild(watchers);

        return userElement;
    }

        // 특정 HTML 삽입
        const newHtml = `
            <div id="sidebar">
            </div>
        `;

        // #serviceLnb 하위에 HTML 삽입
        const serviceLnbElement = document.getElementById('serviceLnb');
        if (serviceLnbElement) {
            serviceLnbElement.insertAdjacentHTML('beforeend', newHtml);
        }

    function insertTopChannels(){

        // 특정 HTML 삽입
        const newHtml = `
            <div class="top-section">
                <span>인기 채널</span>
            </div>
            <div class="users-section top">
            </div>
        `;

        // #serviceLnb 하위에 HTML 삽입
        const serviceLnbElement = document.getElementById('sidebar');
        if (serviceLnbElement) {
            serviceLnbElement.insertAdjacentHTML('beforeend', newHtml);
        }
        if(aBroadList){
            try {
                const channels = aBroadList.broad;

                // users-section에 동적으로 user 요소 추가
                const usersSection = document.querySelector('.users-section.top');
                channels.forEach(channel => {
                    if(isCategoryBlocked(channel.broad_cate_no)){
                        return;
                    }
                    if(isUserBlocked(channel.user_id)){
                        return;
                    }
                    const userElement = createUserElement(channel);
                    usersSection.appendChild(userElement);
                });
                usersSection.classList.add('loaded');
            } catch (error) {
                console.error('Error parsing JSON:', error);
            }
        } else {
            GM_xmlhttpRequest({
                method: 'GET',
                url: 'https://live.afreecatv.com/api/main_broad_list_api.php?selectType=action&orderType=view_cnt&pageNo=1&lang=ko_KR',
                headers: {
                    'Content-Type': 'application/json',
                },
                onload: function(response) {
                    try {
                        // 응답을 JSON으로 파싱
                        const jsonResponse = JSON.parse(response.responseText);

                        // 응답에서 필요한 정보 추출
                        const channels = jsonResponse.broad;

                        // users-section에 동적으로 user 요소 추가
                        const usersSection = document.querySelector('.users-section.top');
                        channels.forEach(channel => {
                            if(isCategoryBlocked(channel.broad_cate_no)){
                                return;
                            }
                            if(isUserBlocked(channel.user_id)){
                                return;
                            }
                            const userElement = createUserElement(channel);
                            usersSection.appendChild(userElement);
                        });
                        usersSection.classList.add('loaded');
                    } catch (error) {
                        console.error('Error parsing JSON:', error);
                    }
                },
                onerror: function(error) {
                    console.error('Error:', error);
                }
            });
        }
    }

    function insertFavoriteChannels(response){

        // 특정 HTML 삽입
        const newHtml = `
            <div class="top-section">
                <span><a href="https://my.afreecatv.com/favorite">즐겨찾기 중인 채널</a></span>
            </div>
            <div class="users-section follow">
            </div>
        `;

        // #serviceLnb 하위에 HTML 삽입
        const serviceLnbElement = document.getElementById('sidebar');
        if (serviceLnbElement) {
            serviceLnbElement.insertAdjacentHTML('beforeend', newHtml);
        }

        try {
            // 응답에서 필요한 정보 추출
            const jsonData = response;
            // 데이터 배열을 순회하면서 각각의 객체에서 broad_info를 확인합니다.
            jsonData.data.forEach(item => {
                // broad_info가 비어있는지 확인합니다.
                if (item.broad_info.length === 0) { //비방
                    //console.log(`broad_info is empty for user ${item.user_nick}`);
                } else { //방송중
                    // broad_info가 비어있지 않은 경우, 여러가지 작업을 수행할 수 있습니다.
                    //console.log(`broad_info is not empty for user ${item.user_nick}`);
                    // users-section에 동적으로 user 요소 추가
                    let channel = item.broad_info[0];
                    const usersSection = document.querySelector('.users-section.follow');
                    const userElement = createUserElement(channel);
                    usersSection.appendChild(userElement);
                }
            });
            document.querySelector('.users-section.follow').classList.add('loaded');
        } catch (error) {
            console.error('Error parsing JSON:', error);
        }
    }

    function insertMyplusChannels(){

        // 특정 HTML 삽입
        const newHtml = `
            <div class="top-section">
                <span>MY+ 추천 채널</span>
            </div>
            <div class="twitch-message-section myplus">
            <div class="description"><span>추천 채널이 없습니다</span></div>
            </div>
            <div class="users-section myplus">
            </div>
        `;

        // #serviceLnb 하위에 HTML 삽입
        const serviceLnbElement = document.getElementById('sidebar');
        if (serviceLnbElement) {
            serviceLnbElement.insertAdjacentHTML('beforeend', newHtml);
        }

        GM_xmlhttpRequest({
            method: 'GET',
            url: 'https://live.afreecatv.com/api/myplus/preferbjLiveVodController.php?nInitCnt=6&szRelationType=C',
            headers: {
                'Content-Type': 'application/json',
            },
            onload: function(response) {
                try {
                    // 응답을 JSON으로 파싱
                    const jsonResponse = JSON.parse(response.responseText);

                    // 응답에서 필요한 정보 추출
                    const channels = jsonResponse.DATA.live_list;

                    if(channels.length!==0){
                        const noti = document.querySelector('.twitch-message-section.myplus');
                        noti.style.display = 'none';
                    }

                    // users-section에 동적으로 user 요소 추가
                    const usersSection = document.querySelector('.users-section.myplus');
                    channels.forEach(channel => {
                        if (isCategoryBlocked(channel.broad_cate_no)){
                            return;
                        }
                        if(isUserBlocked(channel.user_id)){
                            return;
                        }
                        const userElement = createUserElement(channel);
                        usersSection.appendChild(userElement);
                    });
                    usersSection.classList.add('loaded');
                } catch (error) {
                    console.error('Error parsing JSON:', error);
                }
            },
            onerror: function(error) {
                console.error('Error:', error);
            }
        });
    }

    function makethumbnailtooltip(){
        // HTMLCollection을 가져옴
        const elements = document.getElementsByClassName('user');
        const tooltipcontainer = document.getElementsByClassName('tooltip-container')[0];

        // 각 요소에 대해 반복하면서 이벤트 리스너 추가
        for (const element of elements) {
            element.addEventListener('mouseenter', function() {
                const rect = this.getBoundingClientRect();

                const elementX = rect.left + 240; // 요소의 X 좌표
                const elementY = rect.top; // 요소의 Y 좌표
                //console.log(elementX,elementY);
                // 각 툴팁에 대해 위치 설정
                const imgSrc = this.getAttribute('broad_thumnail');
                const broad_title = this.getAttribute('tooltip');

                // 새로운 div 요소를 생성하고 스타일과 내용을 설정
                tooltipcontainer.style.left = `${elementX}px`;
                tooltipcontainer.style.top = `${elementY}px`;

                tooltipcontainer.innerHTML = `<img src="${imgSrc}"><div class="tooltiptext">${broad_title}</div>`;

                tooltipcontainer.style.display = 'block';
            });
            element.addEventListener('mouseleave', function() {
                tooltipcontainer.style.display = 'none';
            });
        }
    }

    function showMore_myplus(n){
        const userContainer = document.querySelector('.users-section.myplus');
        const users = userContainer.querySelectorAll('.user');
        if (users.length < n+1){
            return false;
        }
        users.forEach((user, index) => {
            if (index >= n) {
                user.classList.add('show-more');
            }
        });
        // 동적으로 버튼 생성 및 삽입
        const toggleButton = document.createElement('button');
        toggleButton.textContent = `더 보기 (${users.length - n})`;
        toggleButton.id = 'toggleButton';

        userContainer.appendChild(toggleButton);
        const toggle_button = document.getElementById('toggleButton');

        toggle_button.addEventListener('click', function () {
            const users = userContainer.querySelectorAll('.user');
            const hiddenUsers = users.length - n; // 숨겨진 요소의 개수 계산
            const lastUser = users[users.length - 1];
            if (lastUser.classList.contains('show-more')) {
                // 더 보기를 눌렀을 때
                toggleButton.textContent = `접기`;
                users.forEach((user, index) => {
                    if (index >= n) {
                        user.classList.remove('show-more');
                    }
                });
            } else {
                // 접기를 눌렀을 때
                toggleButton.textContent = `더 보기 (${hiddenUsers})`;
                users.forEach((user, index) => {
                    if (index >= n) {
                        user.classList.add('show-more');
                    }
                });
            }
        });
    }
    function showMore_follow(n){
        const userContainer = document.querySelector('.users-section.follow');
        const users = userContainer.querySelectorAll('.user');
        if (users.length < n+1){
            return false;
        }
        users.forEach((user, index) => {
            if (index >= n) {
                user.classList.add('show-more');
            }
        });
        // 동적으로 버튼 생성 및 삽입
        const toggleButton = document.createElement('button');
        toggleButton.textContent = `더 보기 (${users.length - n})`;
        toggleButton.id = 'toggleButton2';

        userContainer.appendChild(toggleButton);
        const toggle_button = document.getElementById('toggleButton2');

        toggle_button.addEventListener('click', function () {
            const users = userContainer.querySelectorAll('.user');
            const hiddenUsers = users.length - n; // 숨겨진 요소의 개수 계산
            const lastUser = users[users.length - 1];
            if (lastUser.classList.contains('show-more')) {
                // 더 보기를 눌렀을 때
                toggleButton.textContent = `접기`;
                users.forEach((user, index) => {
                    if (index >= n) {
                        user.classList.remove('show-more');
                    }
                });
            } else {
                // 접기를 눌렀을 때
                toggleButton.textContent = `더 보기 (${hiddenUsers})`;
                users.forEach((user, index) => {
                    if (index >= n) {
                        user.classList.add('show-more');
                    }
                });
            }
        });
    }
    function showMore_top(n){
        const userContainer = document.querySelector('.users-section.top');
        const users = userContainer.querySelectorAll('.user');
        if (users.length < n+1){
            return false;
        }
        users.forEach((user, index) => {
            if (index >= n) {
                user.classList.add('show-more');
            }
        });
        // 동적으로 버튼 생성 및 삽입
        const toggleButton = document.createElement('button');
        toggleButton.textContent = `더 보기 (${users.length - n})`;
        toggleButton.id = 'toggleButton3';

        userContainer.appendChild(toggleButton);
        const toggle_button = document.getElementById('toggleButton3');

        toggle_button.addEventListener('click', function () {
            const users = userContainer.querySelectorAll('.user');
            const hiddenUsers = users.length - n; // 숨겨진 요소의 개수 계산
            const lastUser = users[users.length - 1];
            if (lastUser.classList.contains('show-more')) {
                // 더 보기를 눌렀을 때
                toggleButton.textContent = `접기`;
                users.forEach((user, index) => {
                    if (index >= n) {
                        user.classList.remove('show-more');
                    }
                });
            } else {
                // 접기를 눌렀을 때
                toggleButton.textContent = `더 보기 (${hiddenUsers})`;
                users.forEach((user, index) => {
                    if (index >= n) {
                        user.classList.add('show-more');
                    }
                });
            }
        });
    }
    function removeDuplicates(){
        if(document.querySelectorAll('.users-section.follow > .user').length ===0){
            return false;
        }
        // .users-section.follow > .user 모든 요소 반복
        document.querySelectorAll('.users-section.follow > .user').forEach(followUser => {
            const followUserId = followUser.getAttribute('user_id');

            // .users-section.myplus > .user 모든 요소 반복
            document.querySelectorAll('.users-section.myplus > .user').forEach(myplusUser => {
                const myplusUserId = myplusUser.getAttribute('user_id');

                // user_id 일치 여부 확인
                if (followUserId === myplusUserId) {
                    // 일치할 경우 .user 요소 제거
                    myplusUser.remove();
                }
            });
        });
    }

    function detectContentLoad(){
        var target1 = document.querySelector('#broadlist_area > ul');
        var target2 = document.querySelector('#btnRefresh');

        var observer1 = new MutationObserver(function(mutations) {
            console.log('changed');
            target2.classList.add('loaded');
            waitForElement('.users-section.top.loaded.nologinuser', function (elementSelector, element) {
                appendBlockbutton();
            });
            waitForElement('.users-section.myplus.loaded', function (elementSelector, element) {
                waitForElement('.users-section.top.loaded', function (elementSelector, element) {
                    appendBlockbutton();
                });
            });
        });

        observer1.observe(target1, {
            attributes: true,
            childList: true
        });

    }

    function appendBlockbutton(){
        var nicknames = document.querySelectorAll('.cBox-info > .details > a.nick');
        nicknames.forEach(function(nickname) {
            if (!nickname.classList.contains("checked")) {
                nickname.classList.add("checked");
                var user_id = nickname.getAttribute('user_id');
                if (isUserBlocked(user_id)) {
                    //nickname.parentNode.parentNode.parentNode.style.display = 'none';
                    nickname.parentNode.parentNode.parentNode.remove();
                    return;
                }
                var user_name = nickname.querySelector('span').textContent;
                nickname.addEventListener('click', function() {
                    setTimeout(() => {
                        const isDarkMode = document.querySelector('html').getAttribute('dark') === 'true';
                        var buttonElement = document.createElement('button');
                        buttonElement.type = 'button';
                        if(isDarkMode){
                            buttonElement.className = 'block-icon-svg-white';
                        } else {
                            buttonElement.className = 'block-icon-svg';
                        }
                        buttonElement.setAttribute('tip', '채널 차단');

                        var spanElement = document.createElement('span');
                        spanElement.textContent = '채널 차단';
                        buttonElement.appendChild(spanElement);
                        buttonElement.onclick = function() {
                            //nickname.parentNode.parentNode.parentNode.style.display = 'none';
                            nickname.parentNode.parentNode.parentNode.remove();
                            blockUser(user_name,user_id);
                        };

                        // contextMenu 내에 버튼 요소 추가
                        var contextMenu = document.querySelector('#contextMenu');
                        if (contextMenu) {
                            contextMenu.appendChild(buttonElement);
                        } else {
                            console.error('#contextMenu를 찾을 수 없습니다.');
                        }
                        var cate_no = nickname.parentNode.parentNode.querySelector('div.tag_wrap.checked').getAttribute('cate_no') || null;
                        if(cate_no){
                            var buttonElement2 = document.createElement('button');
                            buttonElement2.type = 'button';
                            if(isDarkMode){
                                buttonElement2.className = 'block-icon-svg-white';
                            } else {
                                buttonElement2.className = 'block-icon-svg';
                            }
                            buttonElement2.setAttribute('tip', '카테고리 차단');

                            var spanElement2 = document.createElement('span');
                            spanElement2.textContent = '카테고리 차단';
                            buttonElement2.appendChild(spanElement2);
                            buttonElement2.onclick = function() {
                                //nickname.parentNode.parentNode.parentNode.remove();
                                blockCategory(getCategoryName(cate_no),cate_no);
                            };

                            // contextMenu 내에 버튼 요소 추가
                            if (contextMenu) {
                                contextMenu.appendChild(buttonElement2);
                            } else {
                                console.error('#contextMenu를 찾을 수 없습니다.');
                            }
                        }
                    }, 100);
                });
                //const currentUrl = window.location.href;
                //if (currentUrl === "https://www.afreecatv.com/" || currentUrl === "https://www.afreecatv.com/?hash=all") {
                appendCategory(nickname);
                //}
            }
        });
    }

    function appendCategory(nickname){

        var broadlist_area = nickname.parentNode.parentNode.parentNode.parentNode.parentNode.getAttribute('id');
        var tagContainer = nickname.parentNode.parentNode.querySelector('.tag_wrap');
        var user_id_list = nickname.getAttribute('user_id');

        const channels = aBroadList.broad;
        for (const channel of channels) {
            const cate_no = channel.broad_cate_no;
            const cate_name = getCategoryName(channel.broad_cate_no);
            const user_id_js = channel.user_id;
            if (user_id_list === user_id_js){
                if (isCategoryBlocked(cate_no)) {
                    nickname.parentNode.parentNode.parentNode.remove();
                }
                if(!tagContainer.classList.contains("checked")){
                    tagContainer.classList.add("checked");
                    tagContainer.setAttribute("cate_no",`${cate_no}`)
                    var newATag = document.createElement('a');
                    newATag.textContent = cate_name;
                    newATag.setAttribute("href",`javascript:`)
                    newATag.addEventListener('click', function() {
                        // 클릭 이벤트가 발생했을 때 실행될 코드
                        var cate_no_org = `${cate_no}`;
                        var tag_wrap_checked = document.querySelectorAll('.cBox-info > .tag_wrap.checked');

                        if(!newATag.classList.contains("clicked")){
                            newATag.classList.add("clicked");
                            tag_wrap_checked.forEach(function(element) {
                                var cate_no_dst = element.getAttribute('cate_no');
                                if (cate_no_org === cate_no_dst) {
                                    element.querySelector('a').classList.add("clicked");
                                    element.querySelector('a').textContent=cate_name+" ⨉";
                                    return;
                                }

                                // 숨기는 동작을 수행
                                element.parentNode.parentNode.style.display = 'none';
                            });
                        } else {
                            newATag.classList.remove("clicked");
                            tag_wrap_checked.forEach(function(element) {
                                var cate_no_dst = element.getAttribute('cate_no');
                                if (cate_no_org === cate_no_dst) {
                                    element.querySelector('a').classList.remove("clicked");
                                    element.querySelector('a').textContent=cate_name;
                                    return;
                                }

                                // 숨기는 동작을 수행
                                element.parentNode.parentNode.style.display = 'block';
                            });
                        }
                    });
                    tagContainer.insertBefore(newATag, tagContainer.firstChild);
                    return;
                }
            }
        }

        if(broadlist_area === "prefer_broadlist_area"){
            waitForElement('div.users-section.myplus.loaded', function (elementSelector, element) {
                var users = element.querySelectorAll('.user');
                var cate_no;
                let checker = 0;
                users.forEach(function(user) {
                    var user_id_myplus = user.getAttribute('user_id');
                    if (user_id_list === user_id_myplus){
                        //nickname.parentNode.parentNode.parentNode.remove();
                        console.log(user_id_myplus);
                        cate_no = user.getAttribute('broad_cate_no');
                        checker = 1;
                        return;
                    }
                });
                if(!checker){
                    nickname.parentNode.parentNode.parentNode.remove();
                } else {
                    if(!tagContainer.classList.contains("checked")){
                        tagContainer.classList.add("checked");
                        tagContainer.setAttribute("cate_no",`${cate_no}`)
                        var newATag = document.createElement('a');
                        newATag.textContent = getCategoryName(cate_no);
                        newATag.setAttribute("href",`javascript:`)
                        newATag.addEventListener('click', function() {
                            // 클릭 이벤트가 발생했을 때 실행될 코드
                            var cate_no_org = `${cate_no}`;
                            var tag_wrap_checked = document.querySelectorAll('.cBox-info > .tag_wrap.checked');

                            if(!newATag.classList.contains("clicked")){
                                newATag.classList.add("clicked");
                                tag_wrap_checked.forEach(function(element) {
                                    var cate_no_dst = element.getAttribute('cate_no');
                                    if (cate_no_org === cate_no_dst) {
                                        element.querySelector('a').classList.add("clicked");
                                        element.querySelector('a').textContent=getCategoryName(cate_no)+" ⨉";
                                        return;
                                    }

                                    // 숨기는 동작을 수행
                                    element.parentNode.parentNode.style.display = 'none';
                                });
                            } else {
                                newATag.classList.remove("clicked");
                                tag_wrap_checked.forEach(function(element) {
                                    var cate_no_dst = element.getAttribute('cate_no');
                                    if (cate_no_org === cate_no_dst) {
                                        element.querySelector('a').classList.remove("clicked");
                                        element.querySelector('a').textContent=getCategoryName(cate_no);
                                        return;
                                    }

                                    // 숨기는 동작을 수행
                                    element.parentNode.parentNode.style.display = 'block';
                                });
                            }
                        });
                        tagContainer.insertBefore(newATag, tagContainer.firstChild);
                        return;
                    }
                }
            });
        }
    }
    function detectBroadlist(){
        // 간격 (밀리초 단위)
        var intervalTime = 1000;

        // setInterval을 사용하여 주기적으로 실행
        var intervalId = setInterval(function() {
            // $.ajax가 정의되었는지 확인
            if ($.ajax) {
                // clearInterval을 사용하여 간격 검사 중지
                clearInterval(intervalId);

                // 여기에 $.ajax가 설정된 후에 실행할 스크립트를 작성
                //console.log('$.ajax is defined:', $.ajax);

                // 원본 jQuery.ajax 함수 저장
                var originalAjax = $.ajax;

                // 새로운 jQuery.ajax 함수 정의
                $.ajax = function(settings) {
                    // 요청 설정에서 URL 추출
                    var url = settings.url;

                    // 전송되는 데이터 추출
                    var data = settings.data;

                    // 요청 로깅
                    //GM_log('JQuery AJAX Request URL:', url);
                    //GM_log('JQuery AJAX Request Parameters:', data);

                    // 원본 jQuery.ajax 함수 호출
                    return originalAjax.apply(this, [settings]).done(function(responseData, textStatus, jqXHR) {
                        // 성공적인 응답 로깅
                        //GM_log('JQuery AJAX Response:', responseData);

                        if(url==="https://live.afreecatv.com/api/main_broad_list_api.php"){
                            // tag_wrap_checked가 비어있지 않고, 그 안에 클래스가 'clicked'인 a 태그가 하나라도 있다면 클릭
                            var isClicked = 0;
                            var tag_wrap_checked = document.querySelectorAll('.cBox-info > .tag_wrap.checked');
                            if (tag_wrap_checked.length > 0) {
                                for (var i = 0; i < tag_wrap_checked.length; i++) {
                                    var aTags = tag_wrap_checked[i].querySelectorAll('a.clicked');
                                    if (aTags.length > 0) {
                                        // 여러 a 태그 중 첫 번째 것을 클릭
                                        aTags[0].click();
                                        isClicked = 1;
                                        break; // 이미 클릭한 경우 더 이상 확인할 필요가 없으므로 반복문 종료
                                    }
                                }
                            }
                            //console.log(responseData);
                            var nicknames = document.querySelectorAll('.cBox-info > .details > a');
                            nicknames.forEach(function(nickname) {
                                var tagContainer = nickname.parentNode.parentNode.querySelector('.tag_wrap');
                                var user_id_org = nickname.getAttribute('user_id');

                                const elements = responseData.broad;
                                for (const element of elements) {
                                    const user_id_dst = element.user_id;
                                    if (user_id_org === user_id_dst) {
                                        const cate_no = element.broad_cate_no;
                                        const cate_name = getCategoryName(cate_no);

                                        if (isCategoryBlocked(cate_no)){
                                            nickname.parentNode.parentNode.parentNode.remove();
                                            return;
                                        }
                                        if (!tagContainer.classList.contains("checked")) {
                                            tagContainer.classList.add("checked");
                                            tagContainer.setAttribute("cate_no", `${cate_no}`);

                                            var newATag = document.createElement('a');
                                            newATag.textContent = cate_name;
                                            newATag.setAttribute("href", `javascript:`);
                                            newATag.addEventListener('click', function() {
                                                var cate_no_org = `${cate_no}`;
                                                var tag_wrap_checked = document.querySelectorAll('.cBox-info > .tag_wrap.checked');

                                                if (!newATag.classList.contains("clicked")) {
                                                    newATag.classList.add("clicked");
                                                    tag_wrap_checked.forEach(function(element) {
                                                        var cate_no_dst = element.getAttribute('cate_no');
                                                        if (cate_no_org === cate_no_dst) {
                                                            element.querySelector('a').classList.add("clicked");
                                                            element.querySelector('a').textContent = `${cate_name} ⨉`;
                                                            return;
                                                        }

                                                        element.parentNode.parentNode.style.display = 'none';
                                                    });
                                                } else {
                                                    newATag.classList.remove("clicked");
                                                    tag_wrap_checked.forEach(function(element) {
                                                        var cate_no_dst = element.getAttribute('cate_no');
                                                        if (cate_no_org === cate_no_dst) {
                                                            element.querySelector('a').classList.remove("clicked");
                                                            element.querySelector('a').textContent = cate_name;
                                                            return;
                                                        }

                                                        element.parentNode.parentNode.style.display = 'block';
                                                    });
                                                }
                                            });

                                            tagContainer.insertBefore(newATag, tagContainer.firstChild);
                                        }
                                        break; // user_id 일치하는 첫 번째 요소만 처리하고 반복문 종료
                                    }
                                }
                            });

                            if(isClicked){
                                aTags[0].click();
                            }
                        }
                    }).fail(function(jqXHR, textStatus, errorThrown) {
                        // 실패한 응답 로깅
                        console.log('JQuery AJAX Error:', textStatus, errorThrown);
                    });
                };
            }
        }, intervalTime);
    }

    // HTML 요소를 가져옵니다.
    const htmlElement = document.querySelector('html');

    // dark 속성의 값을 확인합니다.
    const isDarkMode = htmlElement.getAttribute('dark') === 'true';

    if(isDarkMode){
        GM_addStyle(css_Darkmode);
    } else {
        GM_addStyle(css_Whitemode);
    }

    var listsection = document.querySelector('#list-section');
    // .left_navbar를 찾거나 생성
    var leftNavbar = document.querySelector('.left_navbar');
    if (!leftNavbar) {
        leftNavbar = document.createElement('div');
        leftNavbar.className = 'left_navbar';

        // 페이지의 적절한 위치에 추가
        var targetElement = document.body; // 원하는 위치에 따라 수정
        targetElement.insertBefore(leftNavbar, targetElement.firstChild);
    }

    // 새로운 버튼을 만들기
    var newButton = document.createElement('a');
    newButton.href = 'https://www.afreecatv.com/?hash=all';
    newButton.innerHTML = '<button type="button" class="left_nav_button">전체</button>';
    var newButton2 = document.createElement('a');
    newButton2.href = 'https://www.afreecatv.com/?hash=game';
    newButton2.innerHTML = '<button type="button" class="left_nav_button">게임</button>';
    var newButton3 = document.createElement('a');
    newButton3.href = 'https://www.afreecatv.com/?hash=bora';
    newButton3.innerHTML = '<button type="button" class="left_nav_button">보.라</button>';
    var newButton4 = document.createElement('a');
    newButton4.href = 'https://www.afreecatv.com/?hash=sports';
    newButton4.innerHTML = '<button type="button" class="left_nav_button">스포츠</button>';
    var tooltipContainer = document.createElement('div');
    tooltipContainer.classList.add('tooltip-container');

    // .left_navbar에 버튼 삽입
    listsection.appendChild(tooltipContainer);
    leftNavbar.appendChild(newButton4);
    leftNavbar.appendChild(newButton3);
    leftNavbar.appendChild(newButton2);
    leftNavbar.appendChild(newButton);

    waitForElement('.left_nav_button', function (elementSelector, element) {
        // Get the current page URL
        const currentPage = window.location.href;

        // Get all navigation links
        const navLinks = document.querySelectorAll('.left_nav_button');

        // Loop through each link and check if it matches the current page
        navLinks.forEach(link => {
            var parentLink = link.parentElement;
            if (parentLink.href === currentPage) {
                link.classList.add('active'); // Add the 'active' class if it matches
            }
        });
    });

    GM_xmlhttpRequest({
        method: 'GET',
        url: 'https://myapi.afreecatv.com/api/favorite',
        headers: {
            'Content-Type': 'application/json',
        },
        onload: function(response) {
            // 응답 수정
            response = response.responseText;
            response = JSON.parse(response);
            //console.log(response);

            // if 문으로 code 값 확인
            if (response.code === -10000) {
                //console.log('로그인 상태가 아닙니다.');
                insertTopChannels();
                waitForElement('.users-section.top.loaded', function (elementSelector, element) {
                    makethumbnailtooltip();
                    document.querySelector('.users-section.top.loaded').classList.add('nologinuser');
                });
                return false;
            }

            let hasNonEmptyBroadInfo = false;

            // "data" 배열의 각 요소를 확인하는 반복문
            for (const item of response.data) {
                // "broad_info"가 비어 있지 않은 경우
                if (item.broad_info.length > 0) {
                    hasNonEmptyBroadInfo = true;
                    // 여기에 해당 요소에 대한 추가 동작을 수행할 수 있습니다.
                    break; // 만약 하나라도 비어 있지 않은 경우에 중단하려면 이 부분을 사용합니다.
                }
            }

            if (response.data.length === 0) {
                //console.log('즐찾이 없습니다.');
                if(myplus_position){
                    insertMyplusChannels();
                    insertTopChannels();
                } else {
                    insertTopChannels();
                    insertMyplusChannels();
                }
                waitForElement('.users-section.myplus.loaded', function (elementSelector, element) {
                    waitForElement('.users-section.top.loaded', function (elementSelector, element) {
                        makethumbnailtooltip();
                    });
                });
                waitForElement('.users-section.myplus.loaded', function (elementSelector, element) {
                    if(!myplus_order){
                        desc_order('.users-section.myplus');
                    }
                    showMore_myplus(display_myplus);
                });
                waitForElement('.users-section.top.loaded', function (elementSelector, element) {
                    showMore_top(display_top);
                });
            } else if (hasNonEmptyBroadInfo) { // 즐찾 중 방송중인 스트리머가 한 명 이상
                insertFavoriteChannels(response);
                if(myplus_position){
                    insertMyplusChannels();
                    insertTopChannels();
                } else {
                    insertTopChannels();
                    insertMyplusChannels();
                }
                waitForElement('.users-section.follow.loaded', function (elementSelector, element) {
                    waitForElement('.users-section.myplus.loaded', function (elementSelector, element) {
                        removeDuplicates();
                        waitForElement('.users-section.top.loaded', function (elementSelector, element) {
                            makethumbnailtooltip();
                        });
                    });
                });
                waitForElement('.users-section.follow.loaded', function (elementSelector, element) {
                    desc_order('.users-section.follow');
                    showMore_follow(display_follow);
                });
                waitForElement('.users-section.myplus.loaded', function (elementSelector, element) {
                    if(!myplus_order){
                        desc_order('.users-section.myplus');
                    }
                    showMore_myplus(display_myplus);
                });
                waitForElement('.users-section.top.loaded', function (elementSelector, element) {
                    showMore_top(display_top);
                });
            } else { // 즐찾은 있지만 전부 비방
                const newHtml = `
                <div class="top-section">
                   <span><a href="https://my.afreecatv.com/favorite">즐겨찾기 중인 채널</a></span>
                </div>
                <div class="twitch-message-section">
                <div class="description"><span>방송 중인 채널이 없습니다</span></div>
                </div>
                `;
                const serviceLnbElement = document.getElementById('sidebar');
                if (serviceLnbElement) {
                    serviceLnbElement.insertAdjacentHTML('beforeend', newHtml);
                }
                if(myplus_position){
                    insertMyplusChannels();
                    insertTopChannels();
                } else {
                    insertTopChannels();
                    insertMyplusChannels();
                }
                waitForElement('.users-section.myplus.loaded', function (elementSelector, element) {
                    waitForElement('.users-section.top.loaded', function (elementSelector, element) {
                        makethumbnailtooltip();
                    });
                });
                waitForElement('.users-section.myplus.loaded', function (elementSelector, element) {
                    if(!myplus_order){
                        desc_order('.users-section.myplus');
                    }
                    showMore_myplus(display_myplus);
                });
                waitForElement('.users-section.top.loaded', function (elementSelector, element) {
                    showMore_top(display_top);
                });
            }
        },
        onerror: function(error) {
            console.error('Error:', error);
        }
    });

    // 메뉴를 통합한 동작 정의
    GM_registerMenuCommand("❓ 1440P #웰컴 색 표시 " + (coloring_live ? "(ON → OFF)" : "(OFF → ON)"), function() {
        // coloring_live 값 변경
        coloring_live = coloring_live ? 0 : 1;

        // 변경된 값 저장
        GM_setValue("coloring_live", coloring_live);
        alert("설정 값이 변경되었습니다. 새로고침 후 적용됩니다.");
    });
    GM_registerMenuCommand("❓ MY+/인기 우선순위 변경 " + (myplus_position ? "(MY+ → 인기)" : "(인기 → MY+)"), function() {
        // coloring_live 값 변경
        myplus_position = myplus_position ? 0 : 1;

        // 변경된 값 저장
        GM_setValue("myplus_position", myplus_position);
        alert("설정 값이 변경되었습니다. 새로고침 후 적용됩니다.");
    });
    GM_registerMenuCommand("❓ MY+ 정렬 변경 " + (myplus_order ? "(추천순 → 시청자순)" : "(시청자순 → 추천순)"), function() {
        // coloring_live 값 변경
        myplus_order = myplus_order ? 0 : 1;

        // 변경된 값 저장
        GM_setValue("myplus_order", myplus_order);
        alert("설정 값이 변경되었습니다. 새로고침 후 적용됩니다.");
    });
    GM_registerMenuCommand(`❔ 즐겨찾기 표시 수 설정 (${display_follow})`, function() {
        var num_follow = prompt('0 이상의 숫자를 입력', 6);
        if (parseInt(num_follow) >= 0){
            GM_setValue("display_follow", parseInt(num_follow));
            alert("설정 값이 변경되었습니다. 새로고침 후 적용됩니다.");
        } else {
            alert("유효한 숫자를 입력해주세요");
        }
    });
    GM_registerMenuCommand(`❔ MY+ 추천 표시 수 설정 (${display_myplus})`, function() {
        var num_myplus = prompt('0 이상의 숫자를 입력', 6);
        if (parseInt(num_myplus) >= 0){
            GM_setValue("display_myplus", parseInt(num_myplus));
            alert("설정 값이 변경되었습니다. 새로고침 후 적용됩니다.");
        } else {
            alert("유효한 숫자를 입력해주세요");
        }
    });
    GM_registerMenuCommand(`❔ 인기 채널 표시 수 설정 (${display_top})`, function() {
        var num_top = prompt('0 이상의 숫자를 입력', 6);
        if (parseInt(num_top) >= 0){
            GM_setValue("display_top", parseInt(num_top));
            alert("설정 값이 변경되었습니다. 새로고침 후 적용됩니다.");
        } else {
            alert("유효한 숫자를 입력해주세요");
        }
    });

    blockedUsers.forEach(function(user) {
        registerUnblockMenu(user);
    });
    blockedCategories.forEach(function(category) {
        registerCategoryUnblockMenu(category);
    });

    detectContentLoad();
    detectBroadlist();
    if (currentUrl === "https://www.afreecatv.com/?hash=bora" || currentUrl === "https://www.afreecatv.com/?hash=game" || currentUrl === "https://www.afreecatv.com/?hash=sports") {
        waitForElement('button.refresh.loaded', function (elementSelector, element) {
            console.log('1234')
            setTimeout(function () {
                var refreshButton = document.getElementById('btnRefresh');
                refreshButton.click();
            }, 1000);
        });
    }
})();

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址