// ==UserScript==
// @name 아프리카TV - 사이드바 UI 변경
// @name:ko 아프리카TV - 사이드바 UI 변경
// @namespace https://www.afreecatv.com/
// @version 2024-01-85
// @description 아프리카TV의 사이드바 UI를 변경합니다.
// @description:ko 아프리카TV의 사이드바 UI를 변경합니다.
// @author You
// @match https://www.afreecatv.com/
// @match https://www.afreecatv.com/?hash=*
// @match https://www.afreecatv.com/?NaPm=*
// @match https://play.afreecatv.com/*/*
// @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 installMessage = GM_getValue("installMessage", 1);
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 clickDisplayCount = GM_getValue("clickDisplayCount", 10);
let blockedUsers = GM_getValue('blockedUsers', []);
let blockedCategories = GM_getValue('blockedCategories', []);
let open_newtab = GM_getValue("open_newtab", 0);
let playerSmode = GM_getValue("playerSmode", 0);
let preplayerSmode = playerSmode;
let sidebarMinimized = GM_getValue("sidebarMinimized", 0);
let smodeSidebar = GM_getValue("smodeSidebar", 1);
let menuIds = {};
let categoryMenuIds = {};
const isDarkMode = document.body.classList.contains('thema_dark');
let savedCategory = GM_getValue("szBroadCategory",0);
let delayCheckEnabled = true;
let sharpModeCheckEnabled = true;
let autoChangeQuality = GM_getValue("autoChangeQuality", 0);
let autoChangeMute = GM_getValue("autoChangeMute", 0);
let removeDupSwitch = GM_getValue("removeDupSwitch", 1);
let showUptime = GM_getValue("showUptime", 1);
let showRemainingBuffer = GM_getValue("showRemainingBuffer", 1);
let pinSwitch = GM_getValue("pinSwitch", 1);
let webplayer_scroll_left = 240;
if(sidebarMinimized){
webplayer_scroll_left = 52;
}
// 데이터를 로드하고 처리하는 함수
function loadData() {
// 현재 시간 기록
var currentTime = new Date().getTime();
// 이전 실행 시간 불러오기
var lastExecutionTime = GM_getValue("lastExecutionTime", 0);
// 마지막 실행 시간으로부터 1시간 이상 경과했는지 확인
if (currentTime - lastExecutionTime >= 3600000) { // 1시간은 3600000 밀리초
GM_xmlhttpRequest({
method: "GET",
url: "https://live.afreecatv.com/script/locale/ko_KR/broad_category.js",
onload: function(response) {
if (response.status === 200) {
// 성공적으로 데이터를 받았을 때 처리할 코드 작성
var szBroadCategory = response.responseText;
// 이후 처리할 작업 추가
szBroadCategory = JSON.parse(szBroadCategory.split('var szBroadCategory = ')[1].slice(0, -1));
if (szBroadCategory.CHANNEL.RESULT === "1") {
// 데이터 저장
GM_setValue("szBroadCategory", szBroadCategory);
// 현재 시간을 마지막 실행 시간으로 업데이트
GM_setValue("lastExecutionTime", currentTime);
}
} else {
console.error("Failed to load data:", response.statusText);
}
},
onerror: function(error) {
console.error("Error occurred while loading data:", error);
}
});
} else {
console.log("1 hour not elapsed since last execution. Skipping data load.");
}
}
// 페이지가 로드되면 데이터를 로드하고 처리
window.addEventListener('load', function() {
console.log(GM_getValue("lastExecutionTime"));
loadData();
});
const css_Darkmode = `
@media screen and (max-width: 1136px) {
.left_navbar a:first-child {
display: none;
}
}
#sidebar.min {
width: 52px;
}
#sidebar.min .users-section a.user span {
display: none;
}
#sidebar.min .users-section button {
font-size:11px;
padding: 1px;
}
#sidebar.max .button-fold-sidebar {
background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' preserveAspectRatio='none slice' viewBox='0 0 7 11'%3e%3cpath fill='%23f9f9f9' d='M5.87 11.01L.01 5.51 5.87.01l1.08 1.01-4.74 4.45L7 9.96 5.87 11z'/%3e%3c/svg%3e");
background-size: 7px 11px;
background-repeat: no-repeat;
width: 26px;
height: 26px;
background-position: center;
position: absolute;
top: 13px;
left: 200px;
}
#sidebar.max .button-unfold-sidebar {
display:none;
}
#sidebar.min .button-fold-sidebar {
display:none;
}
#sidebar.min .button-unfold-sidebar {
background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' preserveAspectRatio='none slice' viewBox='0 0 7 11'%3e%3cpath fill='%23f9f9f9' d='M1.13 11.01l5.86-5.5L1.13.01.05 1.02l4.74 4.45L0 9.96 1.13 11z'/%3e%3c/svg%3e");
background-size: 7px 11px;
background-repeat: no-repeat;
width: 26px;
height: 26px;
background-position: center;
position: relative;
top: 8px;
left: 12px;
padding-bottom:10px;
}
#sidebar.min .top-section span.max{
display:none;
}
#sidebar.max .top-section span.min{
display:none;
}
.game_post_area {
width: 94%;
left: 30px;
}
.game_post_area .scroll_area ul li{
background-color:#0E0E10;
}
#list-container {
overflow-x: hidden;
background-color:#0E0E10;
}
#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,
.users-section.follow > .user.show-more,
.users-section.top > .user.show-more {
display: none;
}
#toggleButton, #toggleButton2, #toggleButton3 {
padding:12px;
color:#A1A1A1;
width: 100%;
text-align: center;
}
.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: 12px 0px 6px 0px;
}
#sidebar .top-section>span {
text-transform: uppercase;
font-weight: 550;
font-size: 14px;
margin-top: 6px;
margin-bottom: 2px;
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;
}
.users-section .user {
display: grid;
grid-template-areas: "profile-picture username watchers" "profile-picture description blank";
grid-template-columns: 40px auto auto;
padding: 6px 10px;
}
.users-section .user:hover {
background-color: #26262c;
cursor: pointer;
}
.users-section .user .profile-picture {
grid-area: profile-picture;
width: 32px;
height: 32px;
border-radius: 50%;
}
.users-section .user .username {
grid-area: username;
font-size: 14px;
font-weight: 600;
color:#DEDEE3;
letter-spacing: 0.6px;
margin-left:1px;
}
.users-section .user .description {
grid-area: description;
font-size: 13px;
color: #a1a1a1;
font-weight: 400;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
margin-left:1px;
}
.users-section .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;
}
.users-section .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;
display: flex;
}
.tooltip-container img {
position: relative;
z-index: 999;
width: auto;
height: auto;
max-width:320px;
max-height:240px
flex: 0;
}
.tooltiptext {
flex: 0;
position: relative;
z-index: 999;
width: 320px;
max-width: 100%; /* 넘치는 경우 최대 너비 */
height: auto;
background-color: #26262C;
color: #fff;
text-align: center;
align-items: center; /* 세로 가운데 정렬 */
justify-content: center; /* 가로 가운데 정렬 */
box-sizing: border-box; /* 패딩을 포함한 전체 너비 유지 */
padding: 8px 20px 14px 20px;
}
#serviceHeader .a_d_banner {
display: none !important;
}
`;
const css_Whitemode = `
@media screen and (max-width: 1136px) {
.left_navbar a:first-child {
display: none;
}
}
#sidebar.max {
width: 240px;
}
#sidebar.min {
width: 52px;
}
#sidebar.min .users-section a.user span {
display: none;
}
#sidebar.min .users-section button {
font-size:11px;
padding: 1px;
}
#sidebar.max .button-fold-sidebar {
background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' preserveAspectRatio='none slice' viewBox='0 0 7 11'%3e%3cpath fill='%23888' d='M5.87 11.01L.01 5.51 5.87.01l1.08 1.01-4.74 4.45L7 9.96 5.87 11z'/%3e%3c/svg%3e");
background-size: 7px 11px;
background-repeat: no-repeat;
width: 26px;
height: 26px;
background-position: center;
position: absolute;
top: 13px;
left: 200px;
}
#sidebar.max .button-unfold-sidebar {
display:none;
}
#sidebar.min .button-fold-sidebar {
display:none;
}
#sidebar.min .button-unfold-sidebar {
background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' preserveAspectRatio='none slice' viewBox='0 0 7 11'%3e%3cpath fill='%23888' d='M1.13 11.01l5.86-5.5L1.13.01.05 1.02l4.74 4.45L0 9.96 1.13 11z'/%3e%3c/svg%3e");
background-size: 7px 11px;
background-repeat: no-repeat;
width: 26px;
height: 26px;
background-position: center;
position: relative;
top: 8px;
left: 12px;
padding-bottom:10px;
}
#sidebar.min .top-section span.max{
display:none;
}
#sidebar.max .top-section span.min{
display:none;
}
.game_post_area {
width: 94%;
left: 30px;
}
.game_post_area .scroll_area ul li{
background-color:#F7F7F8;
}
#list-container {
overflow-x: hidden;
background-color:#F7F7F8;
}
#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,
.users-section.follow > .user.show-more,
.users-section.top > .user.show-more {
display: none;
}
#toggleButton, #toggleButton2, #toggleButton3 {
padding:12px;
color:#53535F;
width: 100%;
text-align: center;
}
.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: 1F1F23;
font-size: 15px;
font-weight: 600;
}
.left_nav_button.active {
color: #0545B1;
}
#sidebar {
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: 12px 0px 6px 0px;
}
#sidebar .top-section>span {
text-transform: uppercase;
font-weight: 600;
font-size: 14px;
margin-top: 6px;
margin-bottom: 2px;
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;
}
.users-section .user {
display: grid;
grid-template-areas: "profile-picture username watchers" "profile-picture description blank";
grid-template-columns: 40px auto auto;
padding: 6px 10px;
}
.users-section .user:hover {
background-color: #E6E6EA;
cursor: pointer;
}
.users-section .user .profile-picture {
grid-area: profile-picture;
width: 32px;
height: 32px;
border-radius: 50%;
}
.users-section .user .username {
grid-area: username;
font-size: 14px;
font-weight: 600;
color:#1F1F23;
letter-spacing: 0.6px;
margin-left:1px;
}
.users-section .user .description {
grid-area: description;
font-size: 13px;
font-weight: 400;
color: #53535F;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
margin-left:1px;
}
.users-section .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;
}
.users-section .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;
display: flex;
}
.tooltip-container img {
position: relative;
z-index: 999;
width: auto;
height: auto;
max-width:320px;
max-height:240px
flex: 0;
}
.tooltiptext {
flex: 0;
position: relative;
z-index: 999;
width: 320px;
max-width: 100%; /* 넘치는 경우 최대 너비 */
height: auto;
background-color: #E6E6EA;
color: black;
text-align: center;
align-items: center; /* 세로 가운데 정렬 */
justify-content: center; /* 가로 가운데 정렬 */
box-sizing: border-box; /* 패딩을 포함한 전체 너비 유지 */
padding: 8px 20px 14px 20px;
}
#serviceHeader .a_d_banner {
display: none !important;
}
`;
const css_Darkmode_player = `
.remainingBuffer {
overflow: visible;
display: inline-block;
position: relative;
z-index: 1;
margin-left: 15px;
vertical-align: middle;
}
.remainingBuffer p{
font-size: 12px;
color: #888888;
vertical-align: middle;
text-align: center;
}
.elapsed-time {
overflow: visible;
display: inline-block;
position: relative;
z-index: 1;
margin-left: 15px;
vertical-align: middle;
}
.elapsed-time p{
font-size: 13px;
vertical-align: middle;
text-align: center;
}
@media (max-width: 1320px) {
.layout_v2#webplayer.chat_open #webplayer_contents,
.layout_v2#webplayer.chat_open.list_open #webplayer_contents,
.layout_v2#webplayer.chat_open.list_bookmark_open #webplayer_contents {
min-width: 600px;
}
}
@media screen and (max-width: 1120px) {
.left_nav_button {
display: none;
}
}
#sidebar.max {
width: 240px;
}
#sidebar.min {
width: 52px;
}
#sidebar.min .users-section a.user span {
display: none;
}
#sidebar.min .users-section button {
font-size:11px;
padding: 1px;
}
#sidebar.max .button-fold-sidebar {
background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' preserveAspectRatio='none slice' viewBox='0 0 7 11'%3e%3cpath fill='%23f9f9f9' d='M5.87 11.01L.01 5.51 5.87.01l1.08 1.01-4.74 4.45L7 9.96 5.87 11z'/%3e%3c/svg%3e");
background-size: 7px 11px;
background-repeat: no-repeat;
width: 26px;
height: 26px;
background-position: center;
position: absolute;
top: 13px;
left: 200px;
}
#sidebar.max .button-unfold-sidebar {
display:none;
}
#sidebar.min .button-fold-sidebar {
display:none;
}
#sidebar.min .button-unfold-sidebar {
background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' preserveAspectRatio='none slice' viewBox='0 0 7 11'%3e%3cpath fill='%23f9f9f9' d='M1.13 11.01l5.86-5.5L1.13.01.05 1.02l4.74 4.45L0 9.96 1.13 11z'/%3e%3c/svg%3e");
background-size: 7px 11px;
background-repeat: no-repeat;
width: 26px;
height: 26px;
background-position: center;
position: relative;
top: 10px;
left: 12px;
padding-bottom:10px;
}
#sidebar.min .top-section span.max{
display:none;
}
#sidebar.max .top-section span.min{
display:none;
}
#afreecatv_player {
width: 100%;
}
.smode #webplayer_scroll {
top: 0;
left:0;
}
#webplayer_scroll{
left: ${webplayer_scroll_left}px;
}
#sidebar {
height:100vh;
grid-area: sidebar;
background-color: #1F1F23;
color:white;
overflow-y: auto;
position: fixed;
top: 56px;
}
#sidebar > :last-child {
padding-bottom: 240px; /* 마지막 자식에만 padding 추가 */
}
#sidebar::-webkit-scrollbar {
display: none; /* Chrome, Safari, Edge */
}
#sidebar .top-section {
display: flex;
align-items: center;
justify-content: space-around;
margin: 12px 0px 6px 0px;
}
#sidebar .top-section>span {
text-transform: uppercase;
font-weight: 550;
font-size: 14px;
margin-top: 6px;
margin-bottom: 2px;
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;
}
.users-section .user {
display: grid;
grid-template-areas: "profile-picture username watchers" "profile-picture description blank";
grid-template-columns: 40px auto auto;
padding: 6px 10px;
}
.users-section .user:hover {
background-color: #26262c;
cursor: pointer;
}
.users-section .user .profile-picture {
grid-area: profile-picture;
width: 32px;
height: 32px;
border-radius: 50%;
}
.users-section .user .username {
grid-area: username;
font-size: 14px;
font-weight: 600;
color:#DEDEE3;
letter-spacing: 0.6px;
margin-left:1px;
}
.users-section .user .description {
grid-area: description;
font-size: 13px;
color: #a1a1a1;
font-weight: 400;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
margin-left:1px;
}
.users-section .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;
}
.users-section .user .watchers .dot {
font-size: 7px;
margin-right: 5px;
}
#webplayer_top .logo {
top: 18px;
left: 18px;
}
.left_navbar {
display: flex;
align-items: center;
justify-content: flex-end;
position: absolute;
flex-direction: row-reverse;
top: 0px;
left: 140px;
}
.left_nav_button {
position: relative;
width: 70px;
height: 56px;
padding: 0;
border: 0;
border-radius: 50%;
cursor: pointer;
z-index: 3001;
transition: all .2s;
color: #e5e5e5;
font-size: 15px;
font-weight: 600;
}
.tooltip-container {
z-index: 999;
width: 320px;
height: auto;
position: fixed;
background-color: #26262C;
display: flex;
}
.tooltip-container img {
position: relative;
z-index: 999;
width: auto;
height: auto;
max-width:320px;
max-height:240px
flex: 0;
}
.tooltiptext {
flex: 0;
position: relative;
z-index: 999;
width: 320px;
max-width: 100%; /* 넘치는 경우 최대 너비 */
height: auto;
background-color: #26262C;
color: #fff;
text-align: center;
align-items: center; /* 세로 가운데 정렬 */
justify-content: center; /* 가로 가운데 정렬 */
box-sizing: border-box; /* 패딩을 포함한 전체 너비 유지 */
padding: 8px 20px 14px 20px;
}
.users-section.myplus > .user.show-more,
.users-section.follow > .user.show-more,
.users-section.top > .user.show-more {
display: none;
}
#toggleButton, #toggleButton2, #toggleButton3 {
padding:12px;
color:#A1A1A1;
width: 100%;
text-align: center;
}
`;
const css_Whitemode_player = `
.remainingBuffer {
overflow: visible;
display: inline-block;
position: relative;
z-index: 1;
margin-left: 15px;
vertical-align: middle;
}
.remainingBuffer p{
font-size: 12px;
color: #888888;
vertical-align: middle;
text-align: center;
}
.elapsed-time {
overflow: visible;
display: inline-block;
position: relative;
z-index: 1;
margin-left: 15px;
vertical-align: middle;
}
.elapsed-time p{
font-size: 13px;
vertical-align: middle;
text-align: center;
}
@media (max-width: 1320px) {
.layout_v2#webplayer.chat_open #webplayer_contents,
.layout_v2#webplayer.chat_open.list_open #webplayer_contents,
.layout_v2#webplayer.chat_open.list_bookmark_open #webplayer_contents {
min-width: 600px;
}
}
@media screen and (max-width: 1120px) {
.left_nav_button {
display: none;
}
}
#afSearcharea .search_window .searchInputWrap {
border: 1px solid #E5E5E5 !important;
}
#webplayer_top {
border-bottom: 1px solid #E5E5E5 !important;
}
#sidebar.max {
width: 240px;
}
#sidebar.min {
width: 52px;
}
#sidebar.min .users-section a.user span {
display: none;
}
#sidebar.min .users-section button {
font-size:11px;
padding: 1px;
}
#sidebar.max .button-fold-sidebar {
background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' preserveAspectRatio='none slice' viewBox='0 0 7 11'%3e%3cpath fill='%23888' d='M5.87 11.01L.01 5.51 5.87.01l1.08 1.01-4.74 4.45L7 9.96 5.87 11z'/%3e%3c/svg%3e");
background-size: 7px 11px;
background-repeat: no-repeat;
width: 26px;
height: 26px;
background-position: center;
position: absolute;
top: 13px;
left: 200px;
}
#sidebar.max .button-unfold-sidebar {
display:none;
}
#sidebar.min .button-fold-sidebar {
display:none;
}
#sidebar.min .button-unfold-sidebar {
background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' preserveAspectRatio='none slice' viewBox='0 0 7 11'%3e%3cpath fill='%23888' d='M1.13 11.01l5.86-5.5L1.13.01.05 1.02l4.74 4.45L0 9.96 1.13 11z'/%3e%3c/svg%3e");
background-size: 7px 11px;
background-repeat: no-repeat;
width: 26px;
height: 26px;
background-position: center;
position: relative;
top: 8px;
left: 12px;
padding-bottom:10px;
}
#sidebar.min .top-section span.max{
display:none;
}
#sidebar.max .top-section span.min{
display:none;
}
#afreecatv_player {
width: 100%;
}
.smode #webplayer_scroll {
top: 0;
left:0;
}
#webplayer_scroll{
left: ${webplayer_scroll_left}px;
}
#sidebar {
width: 240px;
height:100vh;
grid-area: sidebar;
background-color: #EFEFF1;
color:white;
overflow-y: auto;
position: fixed;
top: 56px;
}
#sidebar > :last-child {
padding-bottom: 240px; /* 마지막 자식에만 padding 추가 */
}
#sidebar::-webkit-scrollbar {
display: none; /* Chrome, Safari, Edge */
}
#sidebar .top-section {
display: flex;
align-items: center;
justify-content: space-around;
margin: 12px 0px 6px 0px;
}
#sidebar .top-section>span {
text-transform: uppercase;
font-weight: 600;
font-size: 14px;
margin-top: 6px;
margin-bottom: 2px;
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;
}
.users-section .user {
display: grid;
grid-template-areas: "profile-picture username watchers" "profile-picture description blank";
grid-template-columns: 40px auto auto;
padding: 6px 10px;
}
.users-section .user:hover {
background-color: #E6E6EA;
cursor: pointer;
}
.users-section .user .profile-picture {
grid-area: profile-picture;
width: 32px;
height: 32px;
border-radius: 50%;
}
.users-section .user .username {
grid-area: username;
font-size: 14px;
font-weight: 600;
color:#1F1F23;
letter-spacing: 0.6px;
margin-left:1px;
}
.users-section .user .description {
grid-area: description;
font-size: 13px;
font-weight: 400;
color: #53535F;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
margin-left:1px;
}
.users-section .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;
}
.users-section .user .watchers .dot {
font-size: 7px;
margin-right: 5px;
}
.tooltip-container {
z-index: 999;
width: 320px;
height: auto;
position: fixed;
background-color: #E6E6EA;
display: flex;
}
.tooltip-container img {
position: relative;
z-index: 999;
width: auto;
height: auto;
max-width:320px;
max-height:240px
flex: 0;
}
.tooltiptext {
flex: 0;
position: relative;
z-index: 999;
width: 320px;
max-width: 100%; /* 넘치는 경우 최대 너비 */
height: auto;
background-color: #E6E6EA;
color: black;
text-align: center;
align-items: center; /* 세로 가운데 정렬 */
justify-content: center; /* 가로 가운데 정렬 */
box-sizing: border-box; /* 패딩을 포함한 전체 너비 유지 */
padding: 8px 20px 14px 20px;
}
#webplayer_top .logo {
top: 18px;
left: 18px;
}
.left_navbar {
display: flex;
align-items: center;
justify-content: flex-end;
position: absolute;
flex-direction: row-reverse;
top: 0px;
left: 140px;
}
.left_nav_button {
position: relative;
width: 70px;
height: 56px;
padding: 0;
border: 0;
border-radius: 50%;
cursor: pointer;
z-index: 3001;
transition: all .2s;
color: #1F1F23;
font-size: 15px;
font-weight: 600;
}
.users-section.myplus > .user.show-more,
.users-section.follow > .user.show-more,
.users-section.top > .user.show-more {
display: none;
}
#toggleButton, #toggleButton2, #toggleButton3 {
padding:12px;
color:#53535F;
width: 100%;
text-align: center;
}
`;
//======================================공용 함수======================================//
function refreshPageOnDarkModeToggle() {
var modecheck1 = document.getElementById("modecheck");
var modecheck2 = document.getElementById("modecheck2");
if (modecheck1 !== null) {
modecheck1.addEventListener("change", function () {
location.reload();
});
}
if (modecheck2 !== null) {
modecheck2.addEventListener("change", function () {
location.reload();
});
}
}
function addNumberSeparator(number) {
// toLocaleString 메서드를 사용하여 숫자에 구분자 추가
number = Number(number);
return number.toLocaleString();
}
function getCategoryName(targetCateNo) {
function searchCategory(categories, targetCateNo) {
// 카테고리 배열을 순회합니다.
for (let category of categories) {
// 현재 카테고리의 cate_no가 목표 cate_no와 일치하는지 확인합니다.
if (category.cate_no === targetCateNo) {
// 일치하는 경우 cate_name을 반환합니다.
return category.cate_name;
} else {
// 현재 카테고리에 child가 있는지 확인합니다.
if (category.child && category.child.length > 0) {
// 재귀적으로 child 카테고리를 검색합니다.
let result = searchCategory(category.child, targetCateNo);
// 재귀 호출 결과가 null이 아니라면 해당 cate_name을 반환합니다.
if (result !== null) {
return result;
}
}
}
}
// cate_no에 해당하는 카테고리가 없는 경우 null을 반환합니다.
return null;
}
// 함수 호출 시 CHANNEL.BROAD_CATEGORY에서 시작합니다.
return searchCategory(savedCategory.CHANNEL.BROAD_CATEGORY, targetCateNo);
}
// 차단 목록을 저장합니다.
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, follow) {
// 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');
// Check if follow option is enabled and if 'pin' attribute exists
if (follow) {
const pinA = (a.getAttribute('pin') === 'Y') ? 1 : 0;
const pinB = (b.getAttribute('pin') === 'Y') ? 1 : 0;
// If pinA and pinB are different, pinA comes first
if (pinA !== pinB) {
return pinB - pinA;
}
}
// Sort based on watchers
return watchersB - watchersA;
});
// Clear container and append sorted elements
container.innerHTML = '';
userArray.forEach(user => {
container.appendChild(user);
});
}
function makeTopNavbarAndSidebar(page){
// .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 buttonData = [
{ href: 'https://www.afreecatv.com/?hash=all', text: '전체' },
{ href: 'https://www.afreecatv.com/?hash=game', text: '게임' },
{ href: 'https://www.afreecatv.com/?hash=bora', text: '보.라' },
{ href: 'https://www.afreecatv.com/?hash=sports', text: '스포츠' }
];
buttonData.reverse().forEach(function (data) {
var newButton = document.createElement('a');
newButton.href = data.href;
newButton.innerHTML = `<button type="button" class="left_nav_button">${data.text}</button>`;
leftNavbar.appendChild(newButton);
});
var tooltipContainer = document.createElement('div');
tooltipContainer.classList.add('tooltip-container');
const sidebarClass = sidebarMinimized ? "min" : "max";
if(page==="main"){
const newHtml = `
<div id="sidebar" class="max">
</div>
`;
const serviceLnbElement = document.getElementById('serviceLnb');
if (serviceLnbElement) {
serviceLnbElement.insertAdjacentHTML('beforeend', newHtml);
}
var listsection = document.querySelector('#list-section');
listsection.appendChild(tooltipContainer);
}
if(page==="player"){
const sidebarHtml = `
<div id="sidebar" class="${sidebarClass}">
</div>
`;
const webplayerElement = document.getElementById('webplayer');
if (webplayerElement) {
webplayerElement.insertAdjacentHTML('beforeend', sidebarHtml);
}
webplayerElement.appendChild(tooltipContainer);
}
}
function updateElementWithContent(targetElement, newContent) {
// DocumentFragment 생성
function createFragment(content) {
var fragment = document.createDocumentFragment();
var tempDiv = document.createElement('div');
tempDiv.innerHTML = content;
while (tempDiv.firstChild) {
fragment.appendChild(tempDiv.firstChild);
}
return fragment;
}
// 기존 내용을 지우고 DocumentFragment를 적용
function applyFragment(fragment) {
targetElement.innerHTML = ''; // 기존 내용을 모두 지움
targetElement.appendChild(fragment); // 새로운 내용 추가
}
// 호출 시점에 전달된 newContent를 사용하여 DocumentFragment 생성 후 적용
applyFragment(createFragment(newContent));
}
// 사용자 요소를 생성하는 함수
function createUserElement(channel, is_mobile_push) {
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+"/"+broadNo;
const broad_thumnail = `https://liveimg.afreecatv.com/m/${broadNo}`;
const userElement = document.createElement('a');
userElement.classList.add('user');
if(!open_newtab){
userElement.setAttribute('href',`${playerLink}`);
} else {
userElement.setAttribute('href',`${playerLink}`);
userElement.setAttribute('target','_blank');
}
userElement.setAttribute('data-watchers',`${totalViewCnt}`);
userElement.setAttribute('broad_thumnail',`${broad_thumnail}`);
userElement.setAttribute('tooltip',`${broadTitle}`);
userElement.setAttribute('user_id',`${userId}`);
if (is_mobile_push) {
userElement.setAttribute('pin', `${is_mobile_push}`);
}
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}'`);
if (open_newtab === 1) {
profilePicture.setAttribute('onclick', `event.preventDefault(); event.stopPropagation(); document.getElementById('sidebar').offsetWidth === 52 ? window.open('${playerLink}', '_blank') : window.open('https://bj.afreecatv.com/${userId}', '_blank');`);
} else {
profilePicture.setAttribute('onclick', `event.preventDefault(); event.stopPropagation(); document.getElementById('sidebar').offsetWidth === 52 ? location.href = '${playerLink}' : window.open('https://bj.afreecatv.com/${userId}', '_blank');`);
}
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;
}
function isUserInFollowSection(userid) {
const followUsers = document.querySelectorAll('.users-section.follow .user');
// 유저가 포함되어 있는지 확인
for (const user of followUsers) {
if (user.getAttribute('user_id') === userid) {
return true; // 유저가 포함되어 있으면 true를 리턴
}
}
return false; // 유저가 포함되어 있지 않으면 false를 리턴
}
function insertFoldButton() {
const foldButton = `
<div class="button-fold-sidebar" role="button"></div>
<div class="button-unfold-sidebar" role="button"></div>
`;
const newHtml = `${foldButton}`;
const webplayer_scroll = document.getElementById('webplayer_scroll') || document.getElementById('list-container');
const serviceLnbElement = document.getElementById('sidebar');
if (serviceLnbElement) {
serviceLnbElement.insertAdjacentHTML('beforeend', newHtml);
// 버튼 요소 가져오기
const buttons = serviceLnbElement.querySelectorAll('.button-fold-sidebar, .button-unfold-sidebar');
buttons.forEach(function(button) {
// 버튼에 클릭 이벤트 리스너 추가
button.addEventListener('click', function () {
// sidebar 상태 변경
sidebarMinimized = !sidebarMinimized;
// max 클래스가 있으면 제거하고 min 클래스 추가
if (serviceLnbElement.classList.contains('max')) {
serviceLnbElement.classList.remove('max');
serviceLnbElement.classList.add('min');
webplayer_scroll.style.left = '52px';
}
// min 클래스가 있으면 제거하고 min 클래스 추가
else if (serviceLnbElement.classList.contains('min')) {
serviceLnbElement.classList.remove('min');
serviceLnbElement.classList.add('max');
webplayer_scroll.style.left = '240px';
}
// sidebarMinimized 값을 저장
GM_setValue("sidebarMinimized", sidebarMinimized ? 1 : 0);
});
});
}
}
function insertTopChannels(update){
let topIcon = `<img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAAwCAYAAABXAvmHAAAACXBIWXMAAAsTAAALEwEAmpwYAAAEzklEQVR4nO1ZaYgcVRB+URMVb7zibTDGA1FBFA90QSHGY3emq/qhO9Nd1TuR+aegiAhCFgSViIoiHmCI+kOMP4zHD0Ex8UciqOCJENR4H4nX6iYao5JVKjOdru6Znp5s98xOYD940DOvXr2q96req6pnzCxmMZiwli4A4K+lybfZkwBAlwHwJCL/Jw2A/0DkK8yeAERaDMDbQuGjRn9KnxlkIAaXNgTdJfT3jRYpAcCXmEGE44ydA8ATkdnQJmvHzgQITkXkb5U5TVrL55lBAkDtJET+Ua30N9Z6C8N++dZKINJma/0TzSDAWnsgAH+o7P0XAD69lc5bCEA/qR163/O8A8xMYnx8fC9EXq1t3HH4wjR6xOBi7eAA9LzwMDMFAF6mVn7Kdfn67DFBRZ9OALzMzAQcJzgfgP5Rq39Pt2MRablS4l9r/YtMPzEyUjsIkTcqIdZaa/fudrzQAtAbavxG8SXTLwDwSmXHv0/nRHGc6vH62EWkFaYfQPSvjdtwUJkuL9flaoLX1aaXYOb9EOlztfrP5uWJyKuUQ3+2ZMmN+5peAYDvUJNNWDt2ZF6ejuMdJWao+N5ueoFSiQ+N2yzfVBRvRLpZ7eqv1tYPMUUDgMbVKn1Rr9fnFsXbWjsPkb7q2d0gdqljHQBemi1U7TSxaUTaUC77i7LoXZduiMdKdl5hCiCSF48yOzMfGhraB5HeUQq/l7VjtrELm8Mx3dzqu6PAa0qBO7PoxRGTCQ0A39bFuLsU/SuFCC8OBcB/h4zLZTqliwtqaxsFtlpLx3UaWy77i5QZbZcbP7cCjkOuWv2PsugB+Dkl+CfNFv5e1cX4jyP6AHIrEA+86N5OtI4TXK6U3SFBmqSQEqmG/wtNxnz3TSdATAUAvR5NTm4H0jkJx10Z8eCntEMLbfp8/nWK9tXcCuioU47GdLoAdBnFcarHhH3yrZN9AC6n8SmX/TN0aJFbAbkZIwf2D09XgD5QW7+8tZ/vV/3vpvEZHR09QqenuRWQhCNkKOd7WiFLrdq2djGStTw/nk62L6/U6/W5OtnJrUCzqtY0ofYxSiKifKIDr12+gEjPtKOpVCqHKV6ThfqA43hnJfslk5IzO1IyveYjCb86pf5qV5VApLOVkp8WoAC9rFYkaO33S/rcz+YX3QsAwXBrf1BT871YhAK3KgFXJ/sB+HHVf3cWPwB+QNE/2jofvxQp4N+SW4Hm9d68iGh7MhxApPWRifE1WfwQ6Sq1wut0X6kUnKDClild3cuFRAUhtmo6jtdnfxokllI2/mXabsqcpig0nW8qDBH0EagduJskp5FXRwGbib0p0A61UMW+J0gCr5j/IFFnU4Hfwv+Hh5cencVH7gNlQhOR6dAmpdgLpmiMjNSOBeDv9DVfKvHJAPRm+J/rBjaLj451EGm9td6CeJFMKts83/QC1vK5OtYH4J/FEdXvtzoVa6Uilwj41gkPJfwWuQdMLwHgX9mYKJ6wqPZgSrQ5B4AeSh9HW/r2BCUvL4lEJSnMGhFGMqpGHZUWS/20A/0GiUL7Inwi1XxEp5u726Ax9uFqtXpwX4WPK+ItAOCn9XGa3Xa+WD4ph4AZFEjlrlF+oRXiqPKcJCvcaDu/3wagx+S2ttbuP9PyzmIWpoH/AeaUFWmyMuZqAAAAAElFTkSuQmCC" style="width:22px">`;
if(isDarkMode){
topIcon = `<img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAAwCAYAAABXAvmHAAAACXBIWXMAAAsTAAALEwEAmpwYAAAExUlEQVR4nO1ZaYgcVRB+HlkVjyheibckxgNRQZSomB8RFC8MElGiP0T9LSgiASELgkpERRGPxeBqghhfV3XPrpN+1bsx8yMRVOKJENR4H9FVo+sRjbKulDPtfN07Mz1s98xOYD94sDtd7+v63lGv6rUxs5hFb8L35Xxm97k2/dvsSSCKlhDJOLNMVpv7zfPCS8yeAM+LLmWWXXXnq41Iftdnppfhee5idbTutPtaG4ogii4yvQhmOZtIdsKo77A2PINo5BQi+RJEjAdBdK7pJRCVTyRy38HIf2GtLIyf699JEe5ba0dPML0AaysHMcu74NwPRHLaVDtZyCxjYPf22rXRgWYm0d/fvzeR+LjGmcPFzew9Ty7EDU4krBxmpkAkq2BE/2EOb2ijz4pUdFplZgLM4XnM7i+I9Q+031dWg/C/fd9dYLqJUql0MJFsB+c3WWv3abe/2jJLBWZhu+4l0y0QuWfB+Z+nE1GYw+NSYXeN6QZ8X65KreEV0+VilhuTXOEVppMYHKzsz+w+hvX7Yl5OZrceZvOjMAz3M50CkdwDI7/T2vDIvJzM0VG6DIF3pekEgqByaHLNutuL4maO7gDeH60dnWuKBpH0w0s+GRjYOqcobmttH7N81rGzQddlMtcJb812yp2qa5rZbfP9DYuy7JndbclcyfYVJsDzwpuSWWZr8kqlsi+RvAF93sqaMWttnzpe75N9qrcNIjcC03tvtr2snFrQuLvb6Hcf2IeFOK8bill2x8S+Hy7IOqCY3a9pAfqbtS8f26qv729YBAP1p574uQUwR8uB9L1se3kJ7D/QBiLWt9H//fpguWsLEFBPvJjlwda20VKwndAkTUvIaqYa/x4tbc3hHppOgthKwEZ4+fJmdpOTk3vhxtV8CZx6Dje02jbjIZLrQUCUWwBmnRoam9npdOM1CrObDwLmJ4t9WdacZ+R0TC1yC9CTsb4mRw9vZkfk3oFRXj2VRx4GAW824xkeHj4Cy9PcArTgiAk1vje2iZaA87sa5UjWlucly8nG1ysDA1vnYLGTW0B1OcRLqHGOghklkTzTggv2gnuhkU25XD4MuMZzC0hWXtGZ6edaSWnMjm1a3flowQ8C/mh0K+F54Vlg82FuAcxuGKb05vRz33fXYNzP4sNzgSi6eqoAuQX4SgUIkLuA0G/g0NOw/u/PFuAegRF+sgHfEAzYnbkF6PEeH0S6VNLpALPbAg5dmc0XXQ4DshmfBYEcH6ct+k683csFvEFIjxrm8Rj7mwsIF4CAT1vMZqUQ56tOhoshHZjAEIgbuJ0ip1pX1xM2kwzFE/Gzwr8naAEPL/5Gs87a7z/Fvw8NbTw6i6d2HvxfV5v60tkBMxmYolEqjRzDLF/hMR8E7iRm9ypkj9dl8aRynS3WRidjqK7ebJfnmU4gCKJzMNcnku91I4JDr7W6rNUbuWTCJ5uVA/7/Rc8B00kQucv0RbDZ0u3RRtlmLVt9rFk/+s/5Ln2Cqn55wUJlSvn4ijqjFZW26nczt6m5aLdNs9CuOF8XMTqXSJ7AcnMabTeze3zduvCQrjqfFKKb0D2P4TSr1WqDQQ0CplegN3e165c1tY06VpsdbWNE7nUieUpPa2vtATPt7yxmYar4F3KMj24yKDCnAAAAAElFTkSuQmCC" style="width:22px">`;
}
if(!update){
const newHtml = `
<div class="top-section top">
<span class="max">인기 채널</span>
<span class="min">${topIcon}</span>
</div>
<div class="users-section top">
</div>
`;
const serviceLnbElement = document.getElementById('sidebar');
if (serviceLnbElement) {
serviceLnbElement.insertAdjacentHTML('beforeend', newHtml);
}
}
const openList = document.querySelectorAll('.users-section.top .user:not(.show-more)').length;
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');
let temp_html = '';
channels.forEach(function(channel, index) {
if(isCategoryBlocked(channel.broad_cate_no)){
return;
}
if(isUserBlocked(channel.user_id)){
return;
}
const userElement = createUserElement(channel, 0);
if(update){
temp_html += userElement.outerHTML;
} else {
usersSection.appendChild(userElement);
}
});
if(update){
updateElementWithContent(usersSection, temp_html);
}
usersSection.classList.add('loaded');
if(update){
showMore('.users-section.top', 'toggleButton3', openList, display_top);
} else {
showMore('.users-section.top', 'toggleButton3', display_top, display_top);
}
makethumbnailtooltip();
} catch (error) {
console.error('Error parsing JSON:', error);
}
},
onerror: function(error) {
console.error('Error:', error);
}
});
}
function insertFavoriteChannels(response,update){
const openList = document.querySelectorAll('.users-section.follow .user:not(.show-more)').length;
let followIcon = `<img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAAwCAYAAABXAvmHAAAACXBIWXMAAAsTAAALEwEAmpwYAAADyUlEQVR4nO1YTWhdVRA+/TH+Ba3gorgQFBS0ulEsqItXFCWLmuZ8k0GSvDtzo/C0YFu0+IfIU7rQnSKCIIo7XYmRIiL+oCsRBbFimwr+ddOVWKy2aovK5OYl552Q9+59P7kp3A8O5OWe+c7MnJk5c45zFSpUqFBhLTA9PX3Z5KTMAjoHyDygfwByGtAfAX3Te/HMvKkbj80hSgHIW5nsAodxzRPJO4Cmu3bploEpzswXAvIkICeI9L/OQ44wJ7euxkWU3mZzcvD8BugTqnpBX8qPj993BaBfdl+wbZwxg51zG1o8zWZzI6BP2bciXIB+YTr0rDyRHIsIvyHSvcyz19fr9YvNQ/Y3oPuJ5OfIiy+1uAB5Ofr2E5E8PDGRXGccxkUk2wDZB8ihaO6xwkZkYRN6Xv6anJQHzJOdZEzpyIvPEMmz0f9e7BQazWZzI5E+aGuGO1EonCwEQuWZk1p+WX109ZBIHsnLQ6Q7IiMey11twoQ1z+dddHlxeW2l8vJqUR5AdoeJnas6WakMY75T2KyGnTsbFxHpt4HyhyzEivIw86b2nEi0q5DV4sBze12PmJhIrl2s7UeA9JpeeQDZFzji7a4CRHq0JWAVxpUMItkWGDDfVQDQk8sG8KgrGcw8GoT0ya4Cdqy3BGZmZi5xJYO5cWlBAyxulzL/blcyvNexICcPdxWwclcoaYYMQOcCfV7pKkCkdwYW/8ss211JYNabTYdAnx155DYs9jytMPq4l7OgXzSzluKTwPtf5xb2Pr0jauL2uzUGVrQkBfORSN4IrP9nLUPJ+/QmQP8O1n+9MEnW4urhsAVm1q1uyGDWrVm7vaT8d9aa9EiW3gjoqSCUvhrm4cbMo7ZGsN4p7+s39EUKKAF6NtiJ92q12mY3YNRqtc3GHSh/1u7OAyG3ljpK6oNjY3vOHwi5c67RaJxnZ064hve6xw0SRHogMmKOmUf65WXmkfCwWhwH3DAQG0Ek7/fzcsDMI0T6bsT5ghsmsntu20580MtlxUIQ0INrqnwLRPp0tOUfFil1NheQj0pRvgUieTzaiU/ztN82h0g/i5R/zpWBxUv3UrNlNXxqauryTg8GRPJ5ZPjzrkwA8lC7EXaBX3liZyfs8kXfZPygS2WvIJJ6+GyYPdrOXt36zpxcSSTfh4cUoPe79QQgudeavkDJX+xlgrl+FZH8EHj+DKCJW4/wXsbbX9PkuI3g92kgvcetZ1D2JPh7/DJHJH96n97lzgV4n94CyK+B508Aers7l8AL99mFxD1qF5Sy9alQoUIFNxT8D3rbJQHjF4hlAAAAAElFTkSuQmCC" style="width:20px">`;
if(isDarkMode){
followIcon = `<img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAAwCAYAAABXAvmHAAAACXBIWXMAAAsTAAALEwEAmpwYAAAD1ElEQVR4nO2YXYhVVRTHd6NZ1tAH9CA9CAYJZb4oCdVDUhS9GFQPvSgWPViQiklmRJzCh3orIgijGFAo2Gf9z5mud85aZ6Y69SSSEBrlFGTli0+hqGkf0sSac+/Mvnvy3nvu5wjnBxcunLP+e6191tp77W1MSUlJSckgqFartwLyLJGMAzIN8AWALwF8EpBPgOQJa+2SVjr6ThTxk0T8aW47q3GhphkT8TNxnN3SM8ettcuJ+FWAzwIy0/zHJ6KI77uSVhjK/fpOKx0iPkMke8fGsuu7cn58fPJ2gL9p7XjD4P9owDMzM9fUdYIgGCGS1/RZQa0j6kPHzhPxKU/0GMA7rE3uPnAgvVFnSP8TyW5AfvUGf6+uRSTvNz6TX4B0VxRN3qUaqhWGvIaIdxLJcU/nVOEgNG3cmSeSPwHepjPZzEad9lLqDYDf9Cbh3WapEQTBSBTx8/mY81+iUDrlOT/vfBQlDxawfblJSrzUrk4Y8kYviD0FVhu3YHmbKQggH/2P8x8W1SGSF9zCbmt10qXSzflmaXMlKpXKDUT8nfMVj2uKFdWx1i5xayIM061tBMCxM/s7TIdE0cTq2tp+gmjyzk51iHinMxFow0B+rBvoCmOGTBjyGicjplsaAHx+PoBs1AwZa7NRJyPOtzSobeuzBgcPJjeZIWPt1M0FA9C8nSuaRwfiZRMAecxZiX4wrdDlrlDR9BnKm8e6Px+0NAjD5GEn4n+jSDaYIRHH6Xr1YT4jeGNLI23C8p5nLogvOtkLuiUIghGAv3T8+LZtYyB9yGu+dpsBQ15LUrgeARlzqv/vQaYSwOsA+csZ/+PCItriatW7LbC11RWmz1hbXZG323Oz/722Jh2JxfHEWkAuOnl4tJ+bm7XZqI7hOH8RSO/pSpRIngLksiM6kWXZUtNjsixbqtrOOJf17NwTcW2pvdb4UJIk1/VE3Bizf//Ra3XP8Vrw7aaXALLPW5nGrbXLutW11i5zN6vab5/pBwuDYO7m5sDmzn/mab5j+kl+zm0496adHFY0BYn40ECdrwPw694nnyqy1Om7gHw+FOfrAPKKVxNftdN+6zsAf+19xbfMMNBDt9ts6RpeqVRua3ZhQCSHvZl/2wwTInmxMQg9wC/csfMd1j3oz9psN4uBMEw2N14b8kmiqTvqz62dWgnwT+4mRZQ8ZxYTRPK0Nn1OEL/pzYS16SqAf/buTreYxQjAj7u3aYCcrv3qQV0iSjeZxUyYXwmeW3gzJ38A8oi5GgCSewH+3Zn5s0TpA+ZqIo7T9Vq4+UUZrxu2PyUlJSWmL/wH5eEJ5sFzGH4AAAAASUVORK5CYII=" style="width:20px">`;
}
if(!update){
const newHtml = `
<div class="top-section follow">
<span class="max"><a href="https://my.afreecatv.com/favorite">즐겨찾기 중인 채널</a></span>
<span class="min"><a href="https://my.afreecatv.com/favorite">${followIcon}</a></span>
</div>
<div class="users-section follow">
</div>
`;
const serviceLnbElement = document.getElementById('sidebar');
if (serviceLnbElement) {
serviceLnbElement.insertAdjacentHTML('beforeend', newHtml);
}
}
try {
const jsonData = response;
// users-section에 동적으로 user 요소 추가
const usersSection = document.querySelector('.users-section.follow');
let temp_html = '';
jsonData.data.forEach(function(item, index) {
if (item.broad_info.length > 0) {
const channel = item.broad_info[0];
const is_mobile_push = item.is_mobile_push;
const userElement = createUserElement(channel,item.is_mobile_push);
if(update){
temp_html += userElement.outerHTML;
} else {
usersSection.appendChild(userElement);
}
}
});
if(update){
updateElementWithContent(usersSection, temp_html);
}
document.querySelector('.users-section.follow').classList.add('loaded');
makethumbnailtooltip();
desc_order('.users-section.follow', pinSwitch);
if(update){
showMore('.users-section.follow', 'toggleButton2', openList, display_follow);
} else {
showMore('.users-section.follow', 'toggleButton2', display_follow, display_follow);
}
} catch (error) {
console.error('Error parsing JSON:', error);
}
}
function insertMyplusChannels(update){
let myplusIcon = `<img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAACXBIWXMAAAsTAAALEwEAmpwYAAABmElEQVR4nO2Wu0oDQRSGNyhYCN6DF8RKwUewENKmyWXO2VMkuznHGLQLFr6BKL6AlWChpa2lYCsYFAUREREtRUXURrBQVk+ICpEsJruI+WFgZ3aG/5t/Z2fGspr6yyKa7UTkXUS5BeBVx3E6AjNPpaQLkfcQ5bVSeCMQ82w22w0gJc8UQC6Mkbg+PzTcnKjQg8j7OutzotwIkTuq9euGmqfTuV4AOdC4z4xxhi3LigDwmiaw3jDzTCbTh8iHH0Z8mkxOD3ntxkhRzZ8ApsYaYk6UjwLIkcZ8QiQD5XcAsqXtM3UzxC8ru1IA5DiRKPSX+8VisVZEfqzWX9O6A5AlImr5NQBRPvq5nzEy8ZP5N5AF3wBWlbofEeUmNb2bUACMcQb1r7kPCYCTOn4nFABEXtQElkMCkG1dA+kwACLet/fGljeuQAEAZFxnf+VrINYJwLaZdQ/YDAUAgFc0gfmQAOT9zuBtRoEDxOPFNkR+RpQX13XbgwaIeKejxl/yZe6p1gOmlmLbnLf8CutizpcAPOfbvKmm/p3eAMYsiMeMK5ANAAAAAElFTkSuQmCC" style="width:24px">`;
if(isDarkMode){
myplusIcon = `<img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAACXBIWXMAAAsTAAALEwEAmpwYAAABkUlEQVR4nO2Wu0oDQRSGExQsBO/BC2Kl4CNY+ABW4hMIFpZi4RuI4gtYCRYm3eE/m4th5uiKKQWDoiAiIqKlqIjaCBYjQyaYFIYsJruI+eHAzuwM/zdnDjMTi7X0l0XkdwNyBOgnQG+lUqorNPN0utADyDGzmIpIhmKez+d7mXWxZKpvmWXGfgPy2nRzIukD5MQZ3hD5Y0QyXmrrh6aae57fzyynbuXXzGrUGBNn1tsOYKdp5rlcbgDQZ26vrzKZ/RHbzyxLDugd2J9oijmRSjDLuVvlJVF+qPwP0Lu23/NksWGGXF3ZlXGRzR4MlscVCoV2QN5qjLeZeQZknYjafg1ApBLV49RUbfPvAGQ1MEDsh3YQeZ6adgCPkQAw62FXOy9RAcy6WjiMCmDNAWxEBCC+q4G50AGMMXG793Zu+eAKFQCQSZf++0ATuUEAzDLv0k+RAACy6QBWIgFg92awh1HoAEqpDkA+AP2ZTO51hgpgjInb29EVYDGQuVW9F0ydsRALKm6M8R2glwObt9TSv9MXwO1y9weCI98AAAAASUVORK5CYII=" style="width:24px">`;
}
if(!update){
const newHtml = `
<div class="top-section myplus">
<span class="max">MY+ 추천 채널</span>
<span class="min">${myplusIcon}</span>
</div>
<!--div class="twitch-message-section myplus">
<div class="description"><span>추천 채널이 없습니다</span></div>
</div-->
<div class="users-section myplus">
</div>
`;
const serviceLnbElement = document.getElementById('sidebar');
if (serviceLnbElement) {
serviceLnbElement.insertAdjacentHTML('beforeend', newHtml);
}
}
const openList = document.querySelectorAll('.users-section.myplus .user:not(.show-more)').length;
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;
// users-section에 동적으로 user 요소 추가
const usersSection = document.querySelector('.users-section.myplus');
/*if(channels.length!==0){
const noti = document.querySelector('.twitch-message-section.myplus');
noti.style.display = 'none';
}*/
let temp_html = '';
channels.forEach(function(channel, index) {
if (isCategoryBlocked(channel.broad_cate_no)){
return;
}
if(isUserBlocked(channel.user_id)){
return;
}
if(update && removeDupSwitch){
if(isUserInFollowSection(channel.user_id)){
return;
}
}
const userElement = createUserElement(channel, 0);
if(update){
temp_html += userElement.outerHTML;
} else {
usersSection.appendChild(userElement);
}
});
if(update){
updateElementWithContent(usersSection, temp_html);
}
usersSection.classList.add('loaded');
makethumbnailtooltip();
if(!myplus_order){
desc_order('.users-section.myplus',0);
}
if(removeDupSwitch){
waitForElement('.users-section.follow.loaded', function (elementSelector, element) {
removeDuplicates();
});
}
if(update){
showMore('.users-section.myplus', 'toggleButton', openList, display_myplus);
} else {
showMore('.users-section.myplus', 'toggleButton', display_myplus, display_myplus);
}
} catch (error) {
console.error('Error parsing JSON:', error);
}
},
onerror: function(error) {
console.error('Error:', error);
}
});
}
function makethumbnailtooltip() {
try {
const elements = document.getElementsByClassName('user');
const tooltipcontainer = document.getElementsByClassName('tooltip-container')[0];
// 각 요소에 대해 반복하면서 이벤트 리스너 추가
for (const element of elements) {
// 이미 이벤트 리스너가 적용되어 있는지 확인
const hasEventListener = element.getAttribute('data-tooltip-listener') === 'true';
const username = element.querySelector('span.username');
const description = element.querySelector('span.description');
const watchers = element.querySelector('span.watchers');
if (!hasEventListener) {
element.addEventListener('mouseenter', function () {
const rect = this.getBoundingClientRect();
const elementX = rect.left + document.getElementById('sidebar').offsetWidth; // 요소의 X 좌표
const elementY = rect.top; // 요소의 Y 좌표
// 각 툴팁에 대해 위치 설정
const imgSrc = this.getAttribute('broad_thumnail');
const broad_title = this.getAttribute('tooltip');
let tooltipContent = broad_title;
if(document.getElementById('sidebar').offsetWidth===52){
tooltipContent = `${username.textContent} · ${description.textContent} · ${watchers.textContent}</br>` + tooltipContent;
}
// 새로운 div 요소를 생성하고 스타일과 내용을 설정
tooltipcontainer.style.left = `${elementX}px`;
tooltipcontainer.style.top = `${elementY}px`;
tooltipcontainer.innerHTML = `<img src="${imgSrc}"><div class="tooltiptext">${tooltipContent}</div>`;
tooltipcontainer.style.display = 'block';
});
element.addEventListener('mouseleave', function () {
tooltipcontainer.style.display = 'none';
});
// 이벤트 리스너가 적용되었음을 표시
element.setAttribute('data-tooltip-listener', 'true');
}
}
} catch (error) {
console.error('makethumbnailtooltip 함수에서 오류가 발생했습니다:', error);
// 여기에 적절한 오류 처리 코드를 추가하세요
}
}
function showMore(containerSelector, buttonId, n, fixed_n) {
const userContainer = document.querySelector(containerSelector);
const users = userContainer.querySelectorAll('.user');
const displayperClick = clickDisplayCount || 10;
//n보다 목록이 적으면 함수를 끝낸다
if (users.length < fixed_n + 1) {
return false;
}
// n개를 넘는 모든 요소를 숨긴다
users.forEach((user, index) => {
if (index >= n) {
user.classList.add('show-more');
}
});
const toggleButton = document.createElement('button');
if(users.length === n){
toggleButton.textContent = `접기`;
} else {
toggleButton.textContent = `더 보기 (${users.length - n})`;
}
toggleButton.id = buttonId;
userContainer.appendChild(toggleButton);
const toggleButtonElement = document.getElementById(buttonId);
toggleButtonElement.addEventListener('click', function () {
const users = userContainer.querySelectorAll('.user'); // 전체
const hiddenUsers = userContainer.querySelectorAll('.user.show-more'); // 숨겨진 요소
let hiddenUsers_length = hiddenUsers.length;
// 조건: 클릭시 숨겨진 요소가 0 이상
if (hiddenUsers_length > 0) {
hiddenUsers.forEach((hiddenuser, index) => {
// 클릭당 보여질만큼 목록을 보여주고 숨긴 요소 숫자에서 개수를 뺀다
if (index < displayperClick) {
hiddenuser.classList.remove('show-more');
hiddenUsers_length = hiddenUsers_length - 1;
}
});
// 결과: 숨겨진 요소에 따라 버튼 이름 변경
if(hiddenUsers_length > 0){
toggleButtonElement.textContent = `더 보기(${hiddenUsers_length})`;
} else {
toggleButtonElement.textContent = `접기`;
}
} else { // 조건: 클릭시 숨겨진 요소가 0 = 초기화해야 함
users.forEach((user, index) => {
if (index >= fixed_n) {
user.classList.add('show-more');
//hiddenUsers_length = hiddenUsers_length + 1;
}
});
toggleButtonElement.textContent = `더 보기(${users.length - fixed_n})`;
}
});
}
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 generateBroadcastElements(update){
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);
// if 문으로 code 값 확인
if (response.code === -10000) {
//console.log('로그인 상태가 아닙니다.');
insertTopChannels(update);
waitForElement('.users-section.top.loaded', function (elementSelector, element) {
document.querySelector('.users-section.top.loaded').classList.add('nologinuser');
});
return false;
}
insertFavoriteChannels(response,update);
if(myplus_position){
insertMyplusChannels(update);
insertTopChannels(update);
} else {
insertTopChannels(update);
insertMyplusChannels(update);
}
},
onerror: function(error) {
console.error('Error:', error);
}
});
}
function removeStudioButton(){
var studioPlay = document.querySelector('#studioPlayKorPlayer') || document.querySelector('#studioPlayKor');
if (studioPlay) {
studioPlay.parentNode.removeChild(studioPlay);
}
}
//=================================공용 함수 끝======================================//
//=================================메인 페이지 함수===================================//
function blockButtonOnMutation(){
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;
}
if(!open_newtab){
const title_href = nickname.parentNode.parentNode.querySelector("h3 > a");
const thumbnail_href = nickname.parentNode.parentNode.parentNode.querySelector("a");
title_href.removeAttribute('target');
thumbnail_href.removeAttribute('target');
}
var user_name = nickname.querySelector('span').textContent;
nickname.addEventListener('click', function() {
setTimeout(() => {
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);
});
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');
if(aBroadList){
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 setCategoryOnAjaxResponse(){
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) {
var url = settings.url;
var data = settings.data;
// 원본 jQuery.ajax 함수 호출
return originalAjax.apply(this, [settings]).done(function(responseData, textStatus, jqXHR) {
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; // 이미 클릭한 경우 더 이상 확인할 필요가 없으므로 반복문 종료
}
}
}
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);
}
//=================================메인 페이지 함수 끝===================================//
//=================================플레이어 페이지 함수 ===================================//
function detectSmode() {
var target = document.querySelector('body');
var webplayerScroll1 = document.getElementById('webplayer_scroll');
var firstRun = 1;
var observer = new MutationObserver(function(mutations) {
var sidebar = document.getElementById('sidebar');
var bodyClasses = target.classList;
if (bodyClasses.contains('smode')){
document.querySelector('#sidebar').style.display = 'none';
document.querySelector('.left_navbar').style.display = 'none';
webplayerScroll1.style.left = '0';
sidebar.style.top = '0px';
GM_setValue("playerSmode", 1);
} else {
document.querySelector('#sidebar').style.display = '';
document.querySelector('.left_navbar').style.display = '';
if (document.fullscreenElement || document.webkitFullscreenElement || document.mozFullScreenElement || document.msFullscreenElement) {
webplayerScroll1.style.left = '0';
} else {
webplayerScroll1.style.left = `${document.getElementById('sidebar').offsetWidth}px`;
}
sidebar.style.top = '56px';
if(firstRun && smodeSidebar) autoScreenMode(preplayerSmode);
GM_setValue("playerSmode", 0);
firstRun = 0;
}
});
observer.observe(target, {
attributeFilter: ['class']
});
}
function detectFullscreenmode(){
document.addEventListener('fullscreenchange', handleFullscreenChange);
document.addEventListener('webkitfullscreenchange', handleFullscreenChange);
document.addEventListener('mozfullscreenchange', handleFullscreenChange);
document.addEventListener('MSFullscreenChange', handleFullscreenChange);
function handleFullscreenChange() {
var sidebar = document.getElementById('sidebar');
var webplayerTop = document.getElementById('webplayer_top');
var leftNavbar = document.querySelector('.left_navbar');
var webplayerScroll = document.getElementById('webplayer_scroll');
if (document.fullscreenElement || document.webkitFullscreenElement || document.mozFullScreenElement || document.msFullscreenElement) {
// 전체화면 모드일 때
hideElement(sidebar);
hideElement(webplayerTop);
hideElement(leftNavbar);
webplayerScroll.style.left = '0px';
} else {
// 전체화면 모드가 아닐 때
showElement(sidebar);
showElement(webplayerTop);
showElement(leftNavbar);
webplayerScroll.style.left = `${document.getElementById('sidebar').offsetWidth}px`;
}
}
function hideElement(element) {
element.style.visibility = 'hidden';
}
function showElement(element) {
element.style.visibility = 'visible';
}
}
function appendPauseButton(){
try {
var button = document.querySelector("button#time_shift_play");
if (button) {
var displayStyle = window.getComputedStyle(button).getPropertyValue("display");
if (displayStyle === "none") {
var ctrlDiv = document.querySelector('div.ctrl');
var closeStreamButton = document.createElement("button");
closeStreamButton.setAttribute("type", "button");
closeStreamButton.setAttribute("id", "closeStream");
closeStreamButton.setAttribute("class", "pause on");
var tooltipDiv = document.createElement("div");
tooltipDiv.setAttribute("class", "tooltip");
var spanElement = document.createElement("span");
spanElement.textContent = "일시정지";
var emElement = document.createElement("em");
tooltipDiv.appendChild(spanElement);
tooltipDiv.appendChild(emElement);
closeStreamButton.appendChild(tooltipDiv);
ctrlDiv.insertBefore(closeStreamButton, ctrlDiv.firstChild);
closeStreamButton.addEventListener("click", function(e) {
e.preventDefault();
try {
if (closeStreamButton.classList.contains("on")) {
// livePlayer 변수가 정의되어 있어야 합니다.
livePlayer.closeStreamConnector();
closeStreamButton.classList.remove("on", "pause");
closeStreamButton.classList.add("off", "play");
spanElement.textContent = "재생";
} else {
// livePlayer 변수가 정의되어 있어야 합니다.
livePlayer._startBroad();
closeStreamButton.classList.remove("off", "play");
closeStreamButton.classList.add("on", "pause");
spanElement.textContent = "일시정지";
}
} catch (error) {
console.log(error);
}
});
} else {
console.log("button#time_shift_play의 style은 display: none;이 아닙니다.");
}
} else {
console.log("button#time_shift_play를 찾을 수 없습니다.");
}
} catch (error) {
console.error(error);
}
}
function showSidebarOnMouseOver() {
var sidebar = document.getElementById('sidebar');
var videoLayer = document.getElementById('videoLayer');
var webplayerScroll = document.getElementById('webplayer_scroll');
var body = document.body;
document.body.addEventListener('mousemove', function (event) {
var mouseX = event.clientX;
var mouseY = event.clientY;
if ((mouseX < 52 && mouseY < videoLayer.clientHeight - 150) || (mouseX < sidebar.clientWidth && mouseY < sidebar.clientHeight)) {
handleSidebarMouseOver();
} else {
handleSidebarMouseOut();
}
});
function handleSidebarMouseOver() {
if (body.classList.contains('smode') && sidebar.style.display === 'none') {
sidebar.style.display = '';
sidebar.style.top = '0px';
if (webplayerScroll.style.left === '0px') {
webplayerScroll.style.left = sidebar.offsetWidth + 'px';
}
}
}
function handleSidebarMouseOut() {
if (body.classList.contains('smode') && sidebar.style.display !== 'none') {
sidebar.style.top = '56px';
sidebar.style.display = 'none';
webplayerScroll.style.left = '0px';
}
}
}
function autoScreenMode(playerSmode){
if(playerSmode){
console.log(playerSmode);
waitForElement('button.btn_smode', function (elementSelector, element) {
element.click();
console.log(element);
});
}
}
function toggleSharpModeShortcut(){
document.querySelectorAll('input').forEach(input => {
input.addEventListener('focus', function() {
sharpModeCheckEnabled = false; // 포커스를 받으면 sharpModeCheckEnabled false로 설정하여 함수 실행을 막습니다.
});
input.addEventListener('blur', function() {
sharpModeCheckEnabled = true; // 포커스를 잃으면 sharpModeCheckEnabled true로 설정하여 함수 실행을 허용합니다.
});
});
const writeArea = document.getElementById('write_area');
writeArea.addEventListener('input', function() {
// write_area에 입력될 때마다 sharpModeCheckEnabled false로 설정하여 함수 실행을 막습니다.
sharpModeCheckEnabled = false;
});
document.addEventListener('keydown', function(event) {
const isEPressed = event.keyCode === 69;
// 모든 입력 상자와 write_area에 포커스가 없는 상태에서 E 키가 눌렸을 때만 togglesharpModeCheck 함수 실행
if (isEPressed && document.activeElement.nodeName !== 'INPUT' && document.activeElement.id !== 'write_area') {
togglesharpModeCheck();
}
});
function togglesharpModeCheck() {
const sharpModeCheckElement = document.getElementById('clear_screen');
sharpModeCheckElement.click();
showPlayerBar();
}
function showPlayerBar(){
const player = document.getElementById('afreecatv_player');
player.classList.remove('mouseover');
player.classList.add('mouseover');
const qualityBoxButton = document.querySelector('#afreecatv_player > div.player_ctrlBox > div.right_ctrl > div.quality_box > button.btn_quality_mode');
const qualityBoxOn = document.querySelector('.quality_box.on');
if (qualityBoxButton) {
if (!qualityBoxOn) {
qualityBoxButton.click();
}
setTimeout(function(){
if (qualityBoxOn) {
qualityBoxButton.click();
}
setTimeout(function(){
player.classList.remove('mouseover');
},250);
},750);
} else {
console.error('Setting button not found or not visible.');
}
}
const labelElement = document.querySelector('#afreecatv_player > div.player_ctrlBox > div.right_ctrl > div.quality_box > ul > li.clear_screen > label');
if (labelElement) {
let labelText = labelElement.innerHTML;
labelText = labelText.replace('선명한 모드', '선명한 모드(e)');
labelElement.innerHTML = labelText;
} else {
console.error('Label element not found.');
}
}
function toggleLowLatencyShortcut(){
document.querySelectorAll('input').forEach(input => {
input.addEventListener('focus', function() {
delayCheckEnabled = false; // 포커스를 받으면 delayCheckEnabled를 false로 설정하여 함수 실행을 막습니다.
});
input.addEventListener('blur', function() {
delayCheckEnabled = true; // 포커스를 잃으면 delayCheckEnabled를 true로 설정하여 함수 실행을 허용합니다.
});
});
const writeArea = document.getElementById('write_area');
writeArea.addEventListener('input', function() {
// write_area에 입력될 때마다 delayCheckEnabled를 false로 설정하여 함수 실행을 막습니다.
delayCheckEnabled = false;
});
document.addEventListener('keydown', function(event) {
const isDPressed = event.keyCode === 68;
// 모든 입력 상자와 write_area에 포커스가 없는 상태에서 D 키가 눌렸을 때만 toggleDelayCheck 함수 실행
if (isDPressed && document.activeElement.nodeName !== 'INPUT' && document.activeElement.id !== 'write_area') {
toggleDelayCheck();
}
});
function toggleDelayCheck() {
const delayCheckElement = document.getElementById('delay_check');
delayCheckElement.click();
showPlayerBar();
}
function showPlayerBar(){
const player = document.getElementById('afreecatv_player');
player.classList.remove('mouseover');
player.classList.add('mouseover');
const settingButton = document.querySelector('#afreecatv_player > div.player_ctrlBox > div.right_ctrl > div.setting_box > button.btn_setting');
const settingBoxOn = document.querySelector('.setting_box.on');
if (settingButton) {
if (!settingBoxOn) {
settingButton.click();
}
setTimeout(function(){
if (settingBoxOn) {
settingButton.click();
}
setTimeout(function(){
player.classList.remove('mouseover');
},250);
},750);
} else {
console.error('Setting button not found or not visible.');
}
}
const labelElement = document.querySelector('#afreecatv_player > div.player_ctrlBox > div.right_ctrl > div.setting_box > div > ul > li.checkbox_wrap > label');
if (labelElement) {
let labelText = labelElement.innerHTML;
labelText = labelText.replace('시차 단축', '시차 단축(d)');
labelElement.innerHTML = labelText;
} else {
console.error('Label element not found.');
}
}
function checkPlayerPageHeaderAd() {
waitForElement('#header_ad', function (elementSelector, element) {
element.remove();
})
}
function broadcastTimeElapsed() {
function extractDateTime(text) {
const dateTimeStr = text.split(' ')[0] + 'T' + text.split(' ')[1] + 'Z';
return new Date(dateTimeStr);
}
const broadcastStartTimeText = document.querySelector('#player_area > div.broadcast_information > div.text_information > ul > li:nth-child(1) > span').textContent.trim();
const broadcastStartTime = extractDateTime(broadcastStartTimeText);
broadcastStartTime.setHours(broadcastStartTime.getHours() - 9);
const elapsedTimeElement = document.createElement('div');
elapsedTimeElement.classList.add('elapsed-time');
const textInformationDiv = document.querySelector('div.text_information');
textInformationDiv.insertBefore(elapsedTimeElement, textInformationDiv.children[2].nextSibling);
function updateElapsedTime() {
const currentTime = new Date();
const timeDiff = currentTime - broadcastStartTime;
const secondsElapsed = Math.floor(timeDiff / 1000);
const hoursElapsed = Math.floor(secondsElapsed / 3600);
const minutesElapsed = Math.floor((secondsElapsed % 3600) / 60);
const remainingSeconds = secondsElapsed % 60;
const formattedTime = `${String(hoursElapsed).padStart(2, '0')}:${String(minutesElapsed).padStart(2, '0')}:${String(remainingSeconds).padStart(2, '0')}`;
elapsedTimeElement.innerHTML = `<p>${formattedTime}</p>`;
}
setInterval(updateElapsedTime, 1000);
}
function insertRemainingBuffer(element){
const video = element;
function getRemainingBufferTime(){
const buffered = video.buffered;
if (buffered.length > 0) {
let remainingBufferTime = buffered.end(buffered.length - 1) - video.currentTime;
remainingBufferTime = remainingBufferTime.toFixed(1);
remainingBufferTime = parseFloat(remainingBufferTime);
remainingBufferTime = remainingBufferTime % 1 === 0 ? remainingBufferTime.toFixed(1) : remainingBufferTime;
return remainingBufferTime;
}
}
// video의 onprogress 이벤트 핸들러
video.onprogress = function() {
// 남은 버퍼 시간 가져오기
let remainingBufferTime = getRemainingBufferTime();
// 요소 찾기
const existingRemainingBuffer = document.querySelector('.remainingBuffer');
// 형제 요소로 삽입할 HTML 생성
const remainingBufferHTML = `<div class="remainingBuffer" title="남은 버퍼 시간"><p>${remainingBufferTime}s</p></div>`;
// existingRemainingBuffer가 존재하는 경우
if (existingRemainingBuffer) {
// 내용물만 업데이트
existingRemainingBuffer.innerHTML = `<p>${remainingBufferTime}s</p>`;
} else {
// 요소 찾기
const elapsedTimeDiv = document.querySelector('#player_area > div.broadcast_information > div.text_information > div.elapsed-time');
const viewerCntDiv = document.querySelector('#player_area > div.broadcast_information > div.text_information > div.broadcast_viewer_cnt');
// elapsedTimeDiv가 존재하는 경우
if (elapsedTimeDiv) {
// 형제 요소로 삽입
elapsedTimeDiv.insertAdjacentHTML('afterend', remainingBufferHTML);
} else if (viewerCntDiv) { // viewerCntDiv가 존재하는 경우
// 형제 요소로 삽입
viewerCntDiv.insertAdjacentHTML('afterend', remainingBufferHTML);
}
}
};
}
// 타이머 식별자를 함수 외부에서 선언합니다.
var timerId_m;
function handleMuteByVisibility() {
const button = document.querySelector("#btn_sound");
if (document.hidden) {
// 탭이 비활성화됨
timerId_m = setTimeout(function(){
if (!button.classList.contains("mute")) {
button.click();
console.log("탭이 비활성화됨, 음소거");
}
},1000);
} else {
// 탭이 활성화됨
if (typeof timerId_m !== 'undefined') {
clearTimeout(timerId_m);
}
if (button.classList.contains("mute")) {
button.click();
console.log("탭이 활성화됨, 음소거 해제");
}
}
}
// 타이머 식별자를 함수 외부에서 선언합니다.
var timerId_q;
function handleChangeQualityByVisibility() {
const qualityButtons = document.querySelectorAll("#afreecatv_player > div.player_ctrlBox > div.right_ctrl > div.quality_box > ul > li:not([style='display: none;']) > button");
if (document.hidden) {
// 탭이 비활성화됨
// setTimeout 함수를 호출하고 타이머 식별자를 변수에 저장합니다.
timerId_q = setTimeout(function(){
const lastButtonIndex = qualityButtons.length - 1;
const lastButton = qualityButtons[lastButtonIndex];
lastButton.click();
console.log(`탭이 비활성화됨, ${lastButton.textContent}`);
}, 1000);
} else {
// 탭이 활성화됨
if (typeof timerId_q !== 'undefined') {
clearTimeout(timerId_q);
}
qualityButtons[1].click();
console.log(`탭이 활성화됨, ${qualityButtons[1].textContent}`);
}
}
function isVideoInPiPMode() {
// 현재 비디오 요소 가져오기
var videoElement = document.querySelector('video');
// 비디오 요소가 존재하고, PiP 모드인지 확인
if (videoElement !== null && document.pictureInPictureElement === videoElement) {
return true;
} else {
return false;
}
}
function registerVisibilityChangeHandler() {
document.addEventListener('visibilitychange', () => {
if(!isVideoInPiPMode()){
if(autoChangeMute) handleMuteByVisibility();
if(autoChangeQuality) handleChangeQualityByVisibility();
}
}, true);
}
//=================================플레이어 페이지 함수 끝 ===================================//
//============================ 메인 페이지 실행 ============================//
if (currentUrl.startsWith("https://www.afreecatv.com")) {
if(isDarkMode){
GM_addStyle(css_Darkmode);
} else {
GM_addStyle(css_Whitemode);
}
makeTopNavbarAndSidebar("main");
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
}
});
});
blockButtonOnMutation();
setCategoryOnAjaxResponse();
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) {
setTimeout(function () {
var refreshButton = document.getElementById('btnRefresh');
refreshButton.click();
}, 1000);
});
}
}
//============================ 플레이어 페이지 실행 ============================//
if (currentUrl.includes("play.afreecatv.com")) {
//embed 페이지에서는 실행하지 않음
var pattern = /^https:\/\/play.afreecatv.com\/.*\/.*\/embed(\?.*)?$/;
if (pattern.test(currentUrl) || currentUrl.includes("vtype=chat")) {
return;
}
detectSmode();
detectFullscreenmode();
appendPauseButton();
if(isDarkMode){
GM_addStyle(css_Darkmode_player);
} else {
GM_addStyle(css_Whitemode_player);
}
makeTopNavbarAndSidebar("player");
insertFoldButton();
toggleSharpModeShortcut();
toggleLowLatencyShortcut();
if(smodeSidebar) showSidebarOnMouseOver();
checkPlayerPageHeaderAd();
if(showUptime){
broadcastTimeElapsed();
}
if(showRemainingBuffer){
waitForElement('#livePlayer', function (elementSelector, element) {
insertRemainingBuffer(element);
});
}
registerVisibilityChangeHandler();
// #webplayer_top > h1 > a 요소 가져오기
var linkElement = document.querySelector("#webplayer_top > h1 > a");
// 만약 요소가 존재하고 target 속성이 있다면 제거
if (linkElement && linkElement.hasAttribute("target")) {
linkElement.removeAttribute("target");
}
}
//============================ 공용 실행 ============================//
GM_registerMenuCommand("❓ 알림 설정된 채널 상단 고정 " + (pinSwitch ? "(ON→OFF)" : "(OFF→ON)"), function() {
// coloring_live 값 변경
pinSwitch = pinSwitch ? 0 : 1;
// 변경된 값 저장
GM_setValue("pinSwitch", pinSwitch);
alert("설정 값이 변경되었습니다. 새로고침 후 적용됩니다.");
});
GM_registerMenuCommand("❓ 방송 경과 시간 표시 " + (showUptime ? "(ON→OFF)" : "(OFF→ON)"), function() {
// coloring_live 값 변경
showUptime = showUptime ? 0 : 1;
// 변경된 값 저장
GM_setValue("showUptime", showUptime);
alert("설정 값이 변경되었습니다. 새로고침 후 적용됩니다.");
});
GM_registerMenuCommand("❓ 남은 버퍼 시간 표시 " + (showRemainingBuffer ? "(ON→OFF)" : "(OFF→ON)"), function() {
// coloring_live 값 변경
showRemainingBuffer = showRemainingBuffer ? 0 : 1;
// 변경된 값 저장
GM_setValue("showRemainingBuffer", showRemainingBuffer);
alert("설정 값이 변경되었습니다. 새로고침 후 적용됩니다.");
});
GM_registerMenuCommand("❓ 비활성화된 탭 음소거 " + (autoChangeMute ? "(ON→OFF)" : "(OFF→ON)"), function() {
// coloring_live 값 변경
autoChangeMute = autoChangeMute ? 0 : 1;
// 변경된 값 저장
GM_setValue("autoChangeMute", autoChangeMute);
alert("설정 값이 변경되었습니다. 새로고침 후 적용됩니다.");
});
GM_registerMenuCommand("❓ 비활성화된 탭 화질 낮추기 " + (autoChangeQuality ? "(ON→OFF)" : "(OFF→ON)"), function() {
// coloring_live 값 변경
autoChangeQuality = autoChangeQuality ? 0 : 1;
// 변경된 값 저장
GM_setValue("autoChangeQuality", autoChangeQuality);
alert("설정 값이 변경되었습니다. 새로고침 후 적용됩니다.");
});
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("❓ MY+에서 즐찾 중복 제거 " + (removeDupSwitch ? "(ON → OFF)" : "(OFF → ON)"), function() {
// coloring_live 값 변경
removeDupSwitch = removeDupSwitch ? 0 : 1;
// 변경된 값 저장
GM_setValue("removeDupSwitch", removeDupSwitch);
alert("설정 값이 변경되었습니다. 새로고침 후 적용됩니다.");
});
GM_registerMenuCommand(`❓ 더 보기 1클릭당 추가될 목록의 수 (${clickDisplayCount})`, function() {
var clickDisplayCount = prompt('1 이상의 숫자를 입력', 10);
if (parseInt(clickDisplayCount) >= 1){
GM_setValue("clickDisplayCount", parseInt(clickDisplayCount));
alert("설정 값이 변경되었습니다. 새로고침 후 적용됩니다.");
} else {
alert("유효한 숫자를 입력해주세요");
}
});
GM_registerMenuCommand("❓ 방송목록 클릭 시 " + (open_newtab ? "(새 탭 → 현재 탭)" : "(현재 탭 → 새 탭)"), function() {
// coloring_live 값 변경
open_newtab = open_newtab ? 0 : 1;
// 변경된 값 저장
GM_setValue("open_newtab", open_newtab);
alert("설정 값이 변경되었습니다. 새로고침 후 적용됩니다.");
});
GM_registerMenuCommand("❓ 스크린모드에 좌측 마우스오버 사이드바 " + (smodeSidebar ? "(ON→OFF)" : "(OFF→ON)"), function() {
// coloring_live 값 변경
smodeSidebar = smodeSidebar ? 0 : 1;
// 변경된 값 저장
GM_setValue("smodeSidebar", smodeSidebar);
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);
});
refreshPageOnDarkModeToggle();
removeStudioButton();
generateBroadcastElements(0);
setInterval(function() {
generateBroadcastElements(1);
}, 60*1000);
if(installMessage){
alert("\n\n✔설정 페이지는\n✔tampermonkey 확장 아이콘 클릭(브라우저 오른쪽 위)\n(이 메시지는 설치 후 한 번만 표시 됩니다)");
GM_setValue("installMessage", 0);
}
})();