您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Enhances Chaturbate by adding multiple new features.
当前为
// ==UserScript== // @name Chaturbate Enhancer // @description Enhances Chaturbate by adding multiple new features. // @version 1.2.3 // @author MoonDivision // @license CC-BY-ND-4.0 // @copyright MoonDivision (https://sleazyfork.org/en/users/884016-moondivision) // @namespace https://sleazyfork.org/en/users/884016-moondivision // @homepage https://sleazyfork.org/en/scripts/441079-chaturbate-enhancer // @supportURL https://sleazyfork.org/en/scripts/441079-chaturbate-enhancer/feedback // @contributionURL https://chaturbate.com/in/?tour=JpRf&campaign=Nb8Yz&track=enh-contrib&next=/tipping/purchase_tokens/ // @icon https://www.google.com/s2/favicons?sz=32&domain=chaturbate.com // @icon64 https://www.google.com/s2/favicons?sz=64&domain=chaturbate.com // @match https://chaturbate.com/* // @match https://*.chaturbate.com/* // @connect camschedule.com // @connect onechance.onelove.workers.dev // @grant GM_addStyle // @grant GM_addElement // @grant GM_xmlhttpRequest // @require https://cdn.jsdelivr.net/npm/[email protected]/dist/jquery.min.js // @require https://cdn.jsdelivr.net/npm/hls.js@1 // @run-at document-body // @noframes // ==/UserScript== (function() { 'use strict'; let style = ` /* Hide media overlays */ .photoVideoDetailSection img { filter: unset !important; } .userUpload div { background: none !important; } .psContainer .lockOverlayBg, .smContainer .lockOverlayBg { display: none !important; } .userUpload img[src$="lock.svg"] { display: none !important; } /* Hide ads */ .ad, .vote-banner { display: none !important; } .cb-enh-avatar { margin-left: 10px; border: 1px solid #bfbfbf; width: 150px; height: 150px; background-color: #ebebeb; margin-bottom: 5px; background-size: 100% 100%; position: relative; } .darkmode .cb-enh-avatar { border-color: #2d3e50; background-color: #202c39; } .cb-enh-avatar, .cb-enh-avatar img { border-radius: 150px; } .cb-enh-avatar img { width: 100%; height: 100%; opacity: 0; position: absolute; left: 0; top: 0; -webkit-user-drag: none; -webkit-app-region: no-drag; user-drag: none; app-region: no-drag; pointer-events: none; -webkit-touch-callout: none; -webkit-user-select: none; -khtml-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; } .cb-enh-footer { font-size: 14px; color: #341b00; font-weight: bold; } .darkmode .cb-enh-footer { color: #efefef; } .cb-enh-footer a { color: inherit !important; text-decoration: underline; } /* Enlarge media in bio */ tr:not(.smContainer) .contentText .previewBorder { width: 190px; height: 135px; } tr:not(.smContainer) .contentText .tokenText { top: 118px !important; right: 5px !important; } /* Detach floaters in "about" */ tr:not(.smContainer):not(.psContainer) .contentText img, tr:not(.smContainer):not(.psContainer) .contentText li, tr:not(.smContainer):not(.psContainer) .contentText a, tr:not(.smContainer):not(.psContainer) .contentText p { position: unset !important; } .cb-enh-video { max-width: 900px; margin: 0px; padding: 0px; width: 100%; height: 100%; object-fit: contain; background-color: rgba(0, 0, 0, 0); display: inline; border: 0; outline: 0; } .cb-enh-video::-webkit-media-controls-play-button { display: none; } .cb-enh-video::-webkit-media-controls-timeline { display: none; } .cb-enh-video::-webkit-media-controls-current-time-display { display: none; } .cb-enh-video::-webkit-media-controls-timeline-container { display: none; } .cb-enh-video::-webkit-media-controls-time-remaining-display { display: none; } #cb-enh-inac-load-chat { cursor: pointer; } `; GM_addStyle(style); $(document).ready(function() { if('initialRoomDossier' in unsafeWindow) { enhanceRoom(); } if(!$('#id_animate_thumbnails').is(':checked')) { $(document).on('mouseenter', '.room_list_room img, .roomElement img, .roomCard img', function() { if(window.currentHoverInterval) { clearInterval(window.currentHoverInterval); window.currentHoverInterval = null; } updateRoomThumb($(this)); window.currentHoverInterval = setInterval(() => { updateRoomThumb($(this)); }, 100); }); $(document).on('mouseleave', '.room_list_room img, .roomElement img, .roomCard img', function() { if(window.currentHoverInterval) { clearInterval(window.currentHoverInterval); window.currentHoverInterval = null; } }); } }); function updateRoomThumb($el) { let uname = $el.parent().data('room'); $el.attr('src', 'https://roomimg.stream.highwebmedia.com/minifwap/' + uname + '.jpg?' + Math.random()); } document.cookie = 'noads=1; expires=Sun, 1 Jan 9999 00:00:00 UTC; path=/'; document.cookie = 'agreeterms=1; expires=Sun, 1 Jan 9999 00:00:00 UTC; path=/'; document.cookie = 'fromaffiliate=1; expires=Sun, 1 Jan 9999 00:00:00 UTC; path=/'; document.cookie = 'affkey="eJyrViopylayUlBKzctQ0lFQSkxLA/HMiwsM03KTQCIFIL6RIYhZBGKCGCUgRnpRoQGIk5wLVuKXZBFZpVQLAEdlFCg="; expires=Sun, 1 Jan 9999 00:00:00 UTC; path=/'; document.cookie = 'noads=1; expires=Sun, 1 Jan 9999 00:00:00 UTC; path=/; domain=.chaturbate.com'; document.cookie = 'agreeterms=1; expires=Sun, 1 Jan 9999 00:00:00 UTC; path=/; domain=.chaturbate.com'; document.cookie = 'fromaffiliate=1; expires=Sun, 1 Jan 9999 00:00:00 UTC; path=/; domain=.chaturbate.com'; document.cookie = 'affkey="eJyrViopylayUlBKzctQ0lFQSkxLA/HMiwsM03KTQCIFIL6RIYhZBGKCGCUgRnpRoQGIk5wLVuKXZBFZpVQLAEdlFCg="; expires=Sun, 1 Jan 9999 00:00:00 UTC; path=/; domain=.chaturbate.com'; function enhanceRoom(ajaxTransition=false) { $('.cb-enh-row').remove(); let lang = $('html').attr('lang'); if(unsafeWindow.initialRoomDossier === '') { // initialRoomDossier is set but is empty // room might be banned or blocked for user // Display video of inaccessible room let $baseRoomContentDiv = $("div.BaseRoomContents div") if($baseRoomContentDiv.length > 0) { if($baseRoomContentDiv.text().indexOf("Access denied") === 0) { $baseRoomContentDiv.append("<br>Chaturbate Enhancer will try to display video of this room.<br><br>"); let $langForm = $("form[action='/set_language/'] input[name='next']"); if($langForm.length > 0) { let username = $("form[action='/set_language/'] input[name='next']")[0].value.slice(1, -1); GM_addStyle(` .BaseRoomContents div { font-size: 14px !important; } `); let $upperHolder = $('<div></div>'); $baseRoomContentDiv.append($upperHolder); let $videoHolder = $('<div></div>'); $baseRoomContentDiv.append($videoHolder); let $upperHolder2 = $('<div></div>'); $baseRoomContentDiv.append($upperHolder2); let $upperHolder3 = $('<div></div>'); $baseRoomContentDiv.append($upperHolder3); let $infoHolder = $('<div></div>'); $baseRoomContentDiv.append($infoHolder); let $infoHolder2 = $('<div></div>'); $baseRoomContentDiv.append($infoHolder2); let $scheduleHolder = $('<div></div>'); $baseRoomContentDiv.append($scheduleHolder); let isOnline = false; // video type GM_xmlhttpRequest({ method: 'GET', url: 'https://onechance.onelove.workers.dev/?https://chaturbate.com/api/chatvideocontext/' + username + '/', headers: { 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8', 'Referer': 'https://chaturbate.com/' + username + '/', }, timeout: 60*1*1000, onload: function(responseDetails) { let data; try { data = JSON.parse(responseDetails.responseText); } catch(SyntaxError) { return; } if($baseRoomContentDiv.length === 0) { return; } let playVideo = true; if(data['room_status'] !== 'public') { let $avDiv = $("<div></div>"); $upperHolder.append($avDiv); insertRoomAv($avDiv, username); $upperHolder.append('Room status is: ' + data['room_status'] + '<br>'); playVideo = false; } else { isOnline = true; $("#cb-enh-inac-load-chat").show() } if(data['hls_source'] === '') { playVideo = false; } if(data['room_title']) { if(data['room_status'] !== 'offline') { $upperHolder.append('Subject: ' + data['room_title'] + '<br><br>'); } else { $upperHolder.append('Last Subject: ' + data['room_title'] + '<br><br>'); } } let $video; if(playVideo) { $video = $('<video controls webkit-playsinline playsinline autoplay muted data-listener-count-webkitendfullscreen="1" class="vjs-tech cb-enh-video" id="vjs_video_3_html5_api" tabindex="-1" role="application" poster="https://cbjpeg.stream.highwebmedia.com/stream?room=' + username + 'f=' + Math.random() + '"></video>'); $videoHolder.append($video); $video.on('pause', function() { try { $video[0].play(); } catch(err) {} }); $video.on('click', function() { try { $video[0].play(); } catch(err) {} }); let hls = new Hls(); hls.loadSource(data['hls_source']); hls.attachMedia($video[0]); } if(data['age']) { $upperHolder3.append('<br><br>Age: ' + data['age'] + '<br>'); } if(data['broadcaster_gender']) { $upperHolder3.append('Gender: ' + data['broadcaster_gender'] + '<br>'); } if(data['num_viewers']) { if(data['room_status'] !== 'offline') { $upperHolder3.append('Viewers: ' + data['num_viewers'] + '<br>'); } else { $upperHolder3.append('Last Viewers: ' + data['num_viewers'] + '<br>'); } } if(data['performer_has_fanclub']) { $infoHolder2.append('Has Fanclub: Yes<br>'); } else { $infoHolder2.append('Has Fanclub: No<br>'); } if('satisfaction_score' in data) { let sc = data['satisfaction_score']; if('percent' in sc && 'up_votes' in sc && 'down_votes' in sc) { $infoHolder2.append('Satisfaction Score: ' + sc['percent'] + '% (' + sc['up_votes'] + ' up, ' + sc['down_votes'] + ' down)<br>'); } } }, onerror: function() { $upperHolder.append('<br>ERROR: Unable to load video.'); } }); // Fetch info about room GM_xmlhttpRequest({ method: 'GET', url: 'https://camschedule.com/api/room/' + username + '?lang=' + lang, timeout: 60*2*1000, onload: function(responseDetails) { let data; try { data = JSON.parse(responseDetails.responseText); } catch(SyntaxError) { return; } let $loadChatHref = $('<a id="cb-enh-inac-load-chat" style="display:none;">Click here to try to load chat.</a><br>'); $upperHolder2.append($loadChatHref); if(isOnline) { $loadChatHref.show(); } $loadChatHref.on('click', function(e) { $loadChatHref.hide(); e.preventDefault(); e.stopPropagation(); $videoHolder.empty(); GM_addElement($videoHolder[0], 'iframe', { src: 'https://onechance.onelove.workers.dev/?https://chaturbate.com/embed/' + username + '/', style: 'width: 100%; max-width: 1400px; height: 700px; border: 0; border-radius: 4px;', }); }); // Populate "region" row if(data['region'] !== '') { let href = '#'; if(data['region_id'] == 0) { href = '/asian-cams/'; } else if(data['region_id'] == 1) { href = '/euro-russian-cams/'; } else if(data['region_id'] == 2) { href = '/north-american-cams/'; } else if(data['region_id'] == 3) { href = '/south-american-cams/'; } else if(data['region_id'] == 4) { href = '/other-region-cams/'; } $infoHolder.append('Region: <a href="' + href + '">' + data['region'] + '</a><br>'); } // Populate "online for" row if(data['online_for'] && data['online_for'] !== '') { $infoHolder.append('Online For: ' + data['online_for'] + '<br>'); } else if(data['last_online'] && data['last_online'] !== '') { $infoHolder.append('Last Online: ' + data['last_online'] + '<br>'); } let info = { 'real_name': 'Real Name', 'birthday': 'Birthday', 'followers_f': 'Followers', 'location': 'Location', 'languages': 'Languages', 'smoke_drink': 'Smoke / Drink', 'body_type': 'Body Type', 'body_decorations': 'Body Decorations', }; Object.keys(info).forEach(function(k) { let v = info[k]; if(data[k]) { $infoHolder.append(v + ': ' + data[k] + '<br>'); } }); // Add schedule if(data['has_schedule']) { $scheduleHolder.append('Schedule: <br>'); let darkMode = $('body').hasClass('darkmode') ? 1 : 0; GM_addElement($scheduleHolder[0], 'iframe', { src: 'https://camschedule.com/embed/schedule/' + username + '?dark=' + darkMode + '&lang=' + lang, style: 'width: 100%; height: 350px; border: 0;', }); } } }); } } } return; } let intv = setInterval(function() { if($('video.vjs-tech').length > 0) { // Make clicking on live video feed don't pause it anymore $('video.vjs-tech').on('pause', function() { try { $('video.vjs-tech')[0].play(); } catch(err) {} }); clearInterval(intv); // Watch for AJAX page transition let currentUsername = $("a.nextCamBgColor")[0].getAttribute('href').slice(6, -1); let pageTransitionIntv = setInterval(function() { let uname = $("a.nextCamBgColor")[0].getAttribute('href').slice(6, -1); if(currentUsername != uname) { clearInterval(pageTransitionIntv); enhanceRoom(true); currentUsername = uname; } }, 25); } }, 25); let userData; let broadcasterName; if(!ajaxTransition) { userData = JSON.parse(unsafeWindow.initialRoomDossier); broadcasterName = userData.broadcaster_username; } else { broadcasterName = $("a.nextCamBgColor")[0].getAttribute('href').slice(6, -1); } let intervalId = setInterval(() => { let $table = $('.BioContents > div > table'); if($table.length === 0) { return; } clearInterval(intervalId); // Add offline avatar let $offlineNotice = $('.offlineRoomNotice'); if($offlineNotice.length > 0) { insertRoomAv($offlineNotice, broadcasterName); } let $divSchedule = addBioRow('Schedule', false, '<div id="cb-enh-iframe"></div>'); if(userData && userData.room_status === 'offline') { addBioRow('Last Subject', true, userData.room_title); } let $divRegion = addBioRow('Region', false, '<a href=""></a>'); let $divOnlineFor = addBioRow('Online For', false); GM_xmlhttpRequest({ method: 'GET', url: 'https://camschedule.com/api/room/' + broadcasterName + '?lang=' + lang, timeout: 60*2*1000, onload: function(responseDetails) { let data; try { data = JSON.parse(responseDetails.responseText); } catch(SyntaxError) { return; } // Populate "region" row if(data['region'] !== '') { let href = '#'; if(data['region_id'] == 0) { href = '/asian-cams/'; } else if(data['region_id'] == 1) { href = '/euro-russian-cams/'; } else if(data['region_id'] == 2) { href = '/north-american-cams/'; } else if(data['region_id'] == 3) { href = '/south-american-cams/'; } else if(data['region_id'] == 4) { href = '/other-region-cams/'; } let elA = $divRegion.children('.cb-enh-row-value').children('a')[0]; elA.innerHTML = data['region']; elA.href = href; $divRegion.show(); } // Populate "online for" row if(data['online_for'] !== '') { $divOnlineFor.children('.cb-enh-row-value')[0].innerHTML = data['online_for']; $divOnlineFor.show(); } // Add schedule if(data['has_schedule']) { let darkMode = $('body').hasClass('darkmode') ? 1 : 0; let iframeWrapper = document.getElementById('cb-enh-iframe'); GM_addElement(iframeWrapper, 'iframe', { src: 'https://camschedule.com/embed/schedule/' + broadcasterName + '?dark=' + darkMode + '&lang=' + lang, style: 'width: 100%; height: 350px; border: 0;', }); $divSchedule.show(); } } }); }, 500); } function addBioRow(name, visible = true, value = '') { let $el = $('<tr class="cb-enh-row" style="' + (visible ? '' : 'display: none; ') + 'font-size: 14px; font-weight: normal; line-height: 15px; vertical-align: top; text-align: left;"><td class="label" style="padding-bottom: 9px; font-family: UbuntuMedium, Arial, Helvetica, sans-serif; height: 16px;"><span>' + name + ':</span></td><td class="contentText cb-enh-row-value" style="font-size: 14px; line-height: 16px; font-family: UbuntuRegular, Arial, Helvetica, sans-serif;">' + value + '</td></tr>'); let $psContainers = $('.BioContents > div > table > .psContainer'); let $smContainers = $('.BioContents > div > table > .smContainer'); if($psContainers.length > 0) { $psContainers.last().after($el); } else if($smContainers.length > 0) { $smContainers.last().after($el); } else { $('.BioContents > div > table > tr').slice(-2).first().after($el); } return $el; } function insertRoomAv($div, username) { $div.prepend('<div class="cb-enh-avatar"></div>'); GM_addElement($('.cb-enh-avatar')[0], 'img', { src: 'https://camschedule.com/assets/img/avatar.png', alt: '', onload: 'this.style.opacity=1' }); GM_addElement($('.cb-enh-avatar')[0], 'img', { src: 'https://thumbv.camschedule.com/av/' + username + '.jpg', alt: '', onload: 'this.style.opacity=1' }); } })();