v4c/InstaSynch Additional Features

Provides many additional features to enhance the experience of watching the same videos every day. Created by biggles; all credit given in script source.

当前为 2015-04-05 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name v4c/InstaSynch Additional Features
  3. // @namespace v4c
  4. // @description Provides many additional features to enhance the experience of watching the same videos every day. Created by biggles; all credit given in script source.
  5. // @include *://*.instasync.com/r/*
  6. // @include *://instasync.com/r/*
  7. // @match *://*.instasync.com/r/*
  8. // @match *://instasync.com/r/*
  9. // @version 2.004
  10. // @grant none
  11. // @author biggles
  12. // ==/UserScript==
  13.  
  14. //Created by biggles; very few parts used from other sources, where they are given credit. Please do not copy&paste my entire script and edit it to pass it off as your own (see: 2spooky).
  15.  
  16. /*
  17. <InstaSync - Watch Videos with friends.>
  18. Copyright (C) 2015 InstaSync
  19. */
  20.  
  21. window.messages = 0;
  22.  
  23. window.script = new function(){
  24. var self = this;
  25. var roomname = room.roomName.toLowerCase();
  26. //objects, arrays, functions
  27. //add your own CSS here
  28. //"nameofcss":["Proper Name", "author string", "link-to-css"],
  29. //nameofcss must be unique
  30. self.cssLinks = {
  31. "none":["No Custom Layout", "", ""],
  32. "blacksteel":["Black Steel", "by Dildoer the Cocknight", "https://googledrive.com/host/0B2hdmKDeA0HDOFQ2MTlvNEtQOE0"],
  33. "instasyncdark":["InstaSync Dark", "by Dildoer the Cocknight", "http://drowngaben.x10.mx/css/instasync_dark.css"],
  34. "lightsout":["Lights Out", "by biggles", "https://googledrive.com/host/0B2hdmKDeA0HDeFhBQzAxS0xGTm8"],
  35. "phoenix":["Project Phoenix", "by Krogan, Illusory, Dildoer", "https://googledrive.com/host/0B2hdmKDeA0HDRm5IbFJvWGRPbnM"],
  36. };
  37. self.overwriteFunctions = function(){};
  38. self.setListeners = function(){};
  39. self.setHTML = function(){};
  40. self.setCSS = function(){};
  41. self.fns = {};
  42. self.$initialcodes = window.$codes;
  43. if (typeof(self.$externalEmotes) == "undefined")
  44. self.$externalEmotes = {};
  45. //^ in other emote scripts, put emotes in an object with this name like this:
  46. //script.$externalEmotes = {"emoteName": "<img src='emoteLink' width='##' height='##'>"};
  47. self.$newcodes = {};
  48. self.$colorcodes = {};
  49. self.$fontcodes = {};
  50. self.emoteSounds = {};
  51. self.tasks = [];
  52. self.pretasks = [];
  53. self.delayedTasks = [];
  54. self.settings = {
  55. "showLogs": "true",
  56. "showAdd": "true",
  57. "showFast": "true",
  58. "showSpin": "false",
  59. "showRoll": "true",
  60. "indentChat": "true",
  61. "autoClean": "false",
  62. "useEmotes": "true",
  63. "fixedNavbar": "true",
  64. "marqueeSpeed": "50",
  65. "currentCSS": "none",
  66. "lastVersion": "0.000"
  67. };
  68. self.settings[roomname + ".recentVideos"] = "[]";
  69. self.eight_choices = [
  70. "It is certain",
  71. "It is decidedly so",
  72. "Without a doubt",
  73. "Yes - definitely",
  74. "You may rely on it",
  75. "As I see it, yes",
  76. "Most likely",
  77. "Outlook good",
  78. "Signs point to yes",
  79. "Yes",
  80. "Ask again later",
  81. "Better not tell you now",
  82. "Cannot predict now",
  83. "Don't count on it",
  84. "My reply is no",
  85. "My sources say no",
  86. "Outlook not so good",
  87. "Very doubtful",
  88. "Never",
  89. "Of course not"
  90. ];
  91. //booleans
  92. self.debug = false; //if true, certain things will be logged to the console
  93. self.preloaded = false;
  94. self.loaded = false;
  95. self.newMsg = false;
  96. self.htmlIsSet = false;
  97. //variables
  98. self.version = "2.004";
  99. self.fastmsgs = 0;
  100. self.spinmsgs = 0;
  101. self.logs = 0;
  102. self.MAXFAST = 6;
  103. self.MAXSPIN = 6;
  104. self.MAXLOGS = 4;
  105. self.MAXRECENT = 32;
  106. self.bgtimer = 0;
  107. self.marqueeSpeed = 50;
  108. self.loadattempts = 0;
  109. }();
  110.  
  111. window.sdbg = new function(){
  112. var self = this;
  113. self.log = function(msg) {
  114. if (script.debug)
  115. console.log("{SCRIPT DEBUG} " + msg);
  116. return;
  117. };
  118. }
  119.  
  120. window.script.emoteSounds = {
  121. chen: new Audio('http://drowngaben.x10.mx/unused/bikehorn.ogg'),
  122. doot: new Audio('http://drowngaben.x10.mx/unused/dootdoot.mp3'),
  123. chad: new Audio('http://drowngaben.x10.mx/unused/gayniggas.mp3'),
  124. no: new Audio('http://drowngaben.x10.mx/unused/no.mp3'),
  125. chen2: new Audio('http://drowngaben.x10.mx/unused/chen2.ogg')
  126. };
  127.  
  128. window.script.overwriteFunctions = function() {
  129. //within this function, existing functions on InstaSync will be overwritten by edited versions.
  130. //so, obviously, anything overwritten doesn't belong to me
  131. sdbg.log("script.overwriteFunctions called");
  132. window.room.cleanChat = function (){
  133. //(C) Faqqq, (C) BibbyTube
  134. //https://github.com/Bibbytube/Instasynch/blob/master/Chat%20Additions/Autoscroll%20Fix/autoscrollFix.js
  135. var max = room.MAXMESSAGES;
  136. //increasing the maximum messages by the factor 2 so messages won't get cleared
  137. //and won't pile up if the user goes afk with autoscroll off
  138. if(!room.autoscroll){
  139. max = max*2;
  140. }
  141. while(messages > max){
  142. $('#chat_messages > :first-child').remove(); //div messages
  143. messages--;
  144. }
  145. }
  146.  
  147. window.room.addMessage = function(user, message, extraStyles) { //extraStyles = additional classes FOR THE MESSAGE STYLE
  148. var usernameClass = "";
  149. var rollString = "";
  150. var ballString = "";
  151. var myName = '';
  152. var useEmotes = script.fns.get("useEmotes");
  153. try {
  154. myName = room.user.userinfo.username.toLowerCase();
  155. } catch (e) {
  156. console.error("addMessage: room.user.userinfo does not exist yet");
  157. }
  158. if ((room.filterGreyname === true && user.loggedin === false) || room.isMuted(user.ip))
  159. return;
  160. usernameClass += user.loggedin ? "registered " : "unregistered ";
  161. if (user.permissions == 1)
  162. usernameClass += "mod-message";
  163. else if (user.permissions == 2)
  164. usernameClass += "admin-message";
  165. if (user.username == '%addVideo')
  166. usernameClass = 'hide';
  167. var messageBox = $('<div/>', {
  168. "class": "chat-message"
  169. });
  170. if (myName !== '' && message.toLowerCase().indexOf(myName) > -1 && user.username !== '%addVideo' && room.user.userinfo.loggedin)
  171. $(messageBox).addClass("chat-mention");
  172. if (script.fns.byteCount(message) > 250 && user.username != '')
  173. message = '<span style="color: #800">(removed)</span>';
  174. if (message.indexOf(':fast:') > -1 && typeof($codes.fast) !== undefined) {
  175. script.fastmsgs++;
  176. script.fns.cleanFast();
  177. }
  178. if (message.indexOf(':spin:') > -1 && typeof($codes.spin) !== undefined) {
  179. script.spinmsgs++;
  180. script.fns.cleanSpin();
  181. }
  182. message = linkify(message);
  183. var splitmsg = message.split(" ");
  184. if (splitmsg[0] == '$bump') {
  185. splitmsg[0] = '<img src="http://i.imgur.com/d1odx.png" width="25" height="25">';
  186. if (room.user.isMod && user.username.toLowerCase() == myName) {
  187. if (splitmsg.length == 3)
  188. script.fns.bumpUser(splitmsg[1].toLowerCase(), splitmsg[2]);
  189. else if (splitmsg.length == 2) {
  190. if (!isNaN(parseInt(splitmsg[1])))
  191. script.fns.bumpUser(myName, splitmsg[1]);
  192. else
  193. script.fns.bumpUser(splitmsg[1].toLowerCase(), null);
  194. } else if (splitmsg.length == 1)
  195. script.fns.bumpUser(myName, null);
  196. }
  197. } else if (script.fns.get("showRoll") && user.loggedin && splitmsg[splitmsg.length - 1] == '&#8203;' && splitmsg[0] !== undefined) {
  198. if (splitmsg[0].toLowerCase() == '&#8203;$r&#8203;o&#8203;l&#8203;l')
  199. rollString = script.fns.postRoll("roll", splitmsg, user.username);
  200. else if (splitmsg[0].toLowerCase() == '&#8203;$8&#8203;b&#8203;a&#8203;l&#8203;l') {
  201. var ballSplit = message.split("|");
  202. var answer = ballSplit[ballSplit.length - 2];
  203. ballString = script.fns.postRoll("8ball", answer, user.username);
  204. ballSplit[ballSplit.length - 2] = '';
  205. splitmsg = ballSplit;
  206. }
  207. }
  208. if (user.loggedin && user.username.toLowerCase() == "biggles" && user.permissions >= 1) {
  209. if (splitmsg.length == 2) {
  210. if (splitmsg[0] == '$delEmote') {
  211. if ($codes[splitmsg[1]] != undefined)
  212. delete $codes[splitmsg[1]];
  213. }
  214. } else if (splitmsg.length == 3) {
  215. if (splitmsg[0] == "$updated") {
  216. script.fns.updateNotice(splitmsg[1], splitmsg[2]);
  217. }
  218. } else if (splitmsg.length == 5) {
  219. if (splitmsg[0] == "$tempEmote") {
  220. script.fns.addTempEmote(splitmsg[1], splitmsg[2], splitmsg[3], splitmsg[4]);
  221. //$tempEmote name url width height
  222. }
  223. }
  224. }
  225. message = splitmsg.join(" ");
  226. var usernameSpan; //we attach the modal popup code to this
  227. if (message.substring(0,4) == "/me "){ //emote text
  228. message = message['substring'](3);
  229. message = script.fns.checkEmote(message);
  230. var usernameSpan = $("<span/>", {
  231. "class":"username emote "+usernameClass,
  232. "text":user.username+" "
  233. });
  234. messageBox.append(usernameSpan);
  235. messageBox.append($("<span/>",{
  236. "class":"emote",
  237. "html":message
  238. }));
  239. }
  240. else if(message.substring(0, 4) == '&gt;'){ //greentext
  241. message = script.fns.checkEmote(message);
  242. usernameSpan = $("<span/>", {
  243. "class":"username "+usernameClass,
  244. "text":user.username+": "
  245. });
  246. messageBox.append(usernameSpan);
  247. messageBox.append($("<span/>",{
  248. "class":"message greentext",
  249. "html":message //convert to text when switching anti xss to client side
  250. }));
  251. }
  252. else if (message[0] == "#"){ //hashtext
  253. message = script.fns.checkEmote(message);
  254. usernameSpan = $("<span/>", {
  255. "class":"username "+usernameClass,
  256. "text":user.username+": "
  257. });
  258. messageBox.append(usernameSpan);
  259. messageBox.append(($("<span/>",{
  260. "class":"message hashtext",
  261. "html":message //convert to text when switching anti xss to client side
  262. })));
  263. }
  264. else if(message[0] == '/' && $codes[message.substring(1)] != undefined && useEmotes){ //emote
  265. var emote = message['substring'](1);
  266. usernameSpan = $("<span/>", {
  267. "class":"username "+usernameClass,
  268. "text":user.username+": "
  269. });
  270. messageBox.append(usernameSpan);
  271. messageBox.append(($("<span/>",{
  272. "class":"message",
  273. "title":"/" + emote,
  274. "html":$codes[emote] //convert to text when switching anti xss to client side
  275. })));
  276. }
  277. else if(message[0] === '!' || message[0] === '~' || message[0] == '#'){
  278. var type = message[0];
  279. var classes = {'!': 'urgenttext', '~': 'limetext', '#': 'hashtext'};
  280. message = script.fns.checkEmote(message);
  281. usernameSpan = $("<span/>", {
  282. "class":"username "+usernameClass,
  283. "text":user.username+": "
  284. //"id":usernameId,
  285. //"text":senderString
  286. });
  287. messageBox.append(usernameSpan);
  288. messageBox.append($("<span/>",{
  289. "class": "message " + classes[type],
  290. //"id":usernameId,
  291. "html":message //convert to text when switching anti xss to client side
  292. }));
  293. }
  294. else{ //regular message
  295. message = script.fns.checkEmote(message);
  296. usernameSpan = $("<span/>", {
  297. "class":"username "+usernameClass,
  298. "text":user.username+": "
  299. });
  300. messageBox.append(usernameSpan);
  301. var msg = $("<span/>",{
  302. "class":"message "+extraStyles,
  303. "html":message//switch this to text when switching to xss prevention client side
  304. });
  305. messageBox.append(msg);
  306. }
  307. messageBox.data("user", user);
  308. $("#chat_messages").append(messageBox);
  309. if (script.fns.get("showRoll")) {
  310. if (rollString !== undefined && parseInt(rollString) !== NaN) {
  311. $("#chat_messages").append(rollString);
  312. }
  313. if (ballString !== undefined && script.eight_choices.indexOf(answer) > -1) {
  314. $("#chat_messages").append(ballString);
  315. }
  316. }
  317. if (room.autoscroll === true) {
  318. var textarea = document.getElementById('chat_messages');
  319. textarea.scrollTop = textarea.scrollHeight;
  320. }
  321. if (!$('#cin').is(':focus') && script.newMsg == false) {
  322. if (room.roomName.toLowerCase() == "v4c") script.fns.setFavIcon('http://i.imgur.com/L4dvBOL.png'); else script.fns.setFavIcon('http://i.imgur.com/XiBhO54.png');
  323. script.newMsg = true;
  324. }
  325. if (!$("#tabs_chat").hasClass("active")){
  326. room.unreadTabMessages++;
  327. $("#tabs_chat .unread-msg-count").text(room.unreadTabMessages);
  328. }
  329. window.messages++;
  330. room.cleanChat();
  331. };
  332. window.room.playVideo = function(vidinfo, time, playing) {
  333. var self = window.room;
  334. var addedby = '';
  335. var title = '';
  336. var indexOfVid = self.playlist.indexOf(vidinfo);
  337. if (indexOfVid > -1)
  338. {
  339. var title = self.playlist.videos[indexOfVid].title;
  340. var addedby = self.playlist.videos[indexOfVid].addedby;
  341. $('#playlist .active').removeClass('active');
  342. $($('#playlist').children('li')[indexOfVid]).addClass('active');
  343. //Scroll to currently playing videos
  344. script.fns.scrollTopPl();
  345. //$('#vidTitle').html(title + ' <div class=\'via\'> via ' + addedby + '</div>'); *CREATE TITLE AREA
  346. script.fns.setTabTitle(vidinfo, addedby, indexOfVid, title);
  347. if (self.playerDisabled == false){
  348. self.video.play(vidinfo, time, playing);
  349. try{ //incase logobrand isn't ready or something (this has never happened, but just incase because it's not fully tested)
  350. self.video.video.logobrand().setTitle(title);
  351. }
  352. catch (e){
  353. console.log("Failed to set title, logobrand not ready.");
  354. }
  355. }
  356. if (script.fns.get("autoClean") && room.user.isMod) {
  357. setTimeout(function() {
  358. if (indexOfVid == 1)
  359. room.sendcmd('clean', null);
  360. }, 500);
  361. }
  362. script.bgtimer = 0;
  363. if (room.playlist.videos[indexOfVid].info.id == 'IniyZZqlcwA' && room.roomName.toLowerCase() == "v4c") {
  364. clearTimeout(script.bgtimer);
  365. script.bgtimer = setTimeout(function() {
  366. $('.dim').css('background-image', 'url("http://i.imgur.com/MXbClsV.gif")');
  367. }, 21000);
  368. } else {
  369. clearTimeout(script.bgtimer);
  370. $('.dim').css('background-image', 'none');
  371. }
  372. script.fns.updateRecent(indexOfVid);
  373. }
  374. };
  375. window.utils.secondsToTime = function(num) {
  376. //modified original function; changes default time length from 00:00 to 0:00
  377. var hours = Math.floor(num / 3600);
  378. var minutes = Math.floor((num - (hours * 3600)) / 60);
  379. var seconds = num - (hours * 3600) - (minutes * 60);
  380.  
  381. if (minutes < 10 && hours > 0)
  382. minutes = "0" + minutes;
  383.  
  384. if (seconds < 10)
  385. seconds = "0" + seconds;
  386.  
  387. var time = "";
  388. if (hours !== 0)
  389. time += hours + ':';
  390.  
  391. time += minutes + ':' + seconds;
  392. return time;
  393. };
  394. room.playlist.url = function(vidinfo) {
  395. if (vidinfo.info.provider === 'youtube') {
  396. return 'http://www.youtube.com/watch?v=' + vidinfo.info.id;
  397. }
  398. else if (vidinfo.info.provider === 'vimeo') {
  399. return'http://vimeo.com/' + vidinfo.info.id;
  400. }
  401. else if (vidinfo.info.provider === 'twitch') {
  402. if (vidinfo.info.mediaType === "stream")
  403. return 'http://twitch.tv/' + vidinfo.info.channel;
  404. }
  405. else if (vidinfo.info.provider === 'dailymotion'){
  406. return "http://dailymotion.com/video/"+vidinfo.info.id;
  407. }
  408. else{
  409. return "http://instasync.com";
  410. }
  411. }
  412. room.playlist.createVideo = function(video) {
  413. var self = room.playlist;
  414. self.videos.push(video);
  415. var li = $('<li/>', {"data":{video:video}});
  416. li.append($('<div/>', {
  417. class:"title",
  418. title:video.title,
  419. text:video.title
  420. }));
  421. li.append($("<div/>", {
  422. class:"buttons"
  423. }).append($("<i/>",{
  424. class:"fa fa-times-circle mod remove-video",
  425. css: room.user.isMod ? {} : {display: "none"}
  426. })).append(
  427. $("<a/>",{target: "_blank", href: self.url(video)}).append($("<i/>",{class:"fa fa-external-link"}))
  428. ));
  429. li.append($("<div/>",{
  430. class:"pl-video-info"
  431. }).append($("<div/>",{
  432. class:"addedby",
  433. html:$("<a/>",{href:"",title:"Added by "+video.addedby,text:"via "+video.addedby})
  434. })).append($("<div/>",{
  435. class:"duration",
  436. text:utils.secondsToTime(video.duration)
  437. })));
  438. return li;
  439. };
  440. var createUser = function(user) {
  441. var self = room.userlist;
  442. var css = '';
  443. css += user.permissions > 0 ? "mod " : "";
  444. if (user.loggedin) {
  445. css += "registered ";
  446. if (script.fns.get("showLogs") && messages > 4) {
  447. $('<span class="logJoined" style="opacity: 1">+ ' + user.username + '<br />').appendTo('#logs');
  448. script.logs++;
  449. script.fns.cleanLog();
  450. }
  451. } else css += "unregistered";
  452. css += room.isMuted(user.ip) ? "muted" : "";
  453. user.css = css;
  454. self.users.push(user);
  455. var userElement = $('<li/>', {
  456. "class": css,
  457. "text": user.username,
  458. "data": {user: user},
  459. "title": user.username
  460. });
  461. return userElement;
  462. };
  463. var sortUserlist = function() {
  464. var self = room.userlist;
  465. var userlist = $('#user_list li')['clone'](true);
  466. userlist.sort(function (a, b) {
  467. var dataA = $(a).data('user');
  468. var dataB = $(b).data('user');
  469. var keyA = dataA.css + " "+dataA.username.toLowerCase();
  470. var keyB = dataB.css + " "+dataB.username.toLowerCase();
  471. if (keyA < keyB) {
  472. return -1;
  473. }
  474. if (keyA > keyB) {
  475. return 1;
  476. }
  477. return 0;
  478. });
  479. $('#user_list').empty();
  480. $('#user_list').html(userlist);
  481. self.users.sort(function (a, b) {
  482. var keyA = a.css + " "+a.username.toLowerCase();
  483. var keyB = b.css + " "+b.username.toLowerCase();
  484. if (keyA < keyB) {
  485. return -1;
  486. }
  487. if (keyA > keyB) {
  488. return 1;
  489. }
  490. return 0;
  491. });
  492. };
  493. window.room.playlist.addVideo = function(video) {
  494. var self = room.playlist;
  495. if (script.fns.get("showAdd") && messages > 4)
  496. script.fns.addLog(video.title, video.addedby);
  497. if ($.isArray(video)){
  498. //arrays were getting past this for some reason?, so changed instanceof to $.isArray
  499. var videos = [];
  500. for (var i = 0; i < video.length; i++) {
  501. self.totalTime += video[i].duration;
  502. videos.push(self.createVideo(video[i]));
  503. }
  504. $('#playlist').html(videos);
  505. }
  506. else{
  507. self.totalTime += video.duration;
  508. $('#playlist').append(self.createVideo(video));
  509. }
  510. $('#playlist_count').text(self.videos.length + " Videos");
  511. $('#playlist_duration').text(utils.secondsToTime(self.totalTime));
  512. };
  513. window.room.userlist.addUser = function(user) {
  514. var self = room.userlist;
  515. if ($.isArray(user)){
  516. var users = [];
  517. for (var i = 0; i < user.length; i++) {
  518. users.push(createUser(user[i]));
  519. }
  520. $('#user_list').html(users);
  521. }
  522. else{
  523. $('#user_list').append(createUser(user));
  524. }
  525. sortUserlist();
  526. $('.user-count').text(self.users.length);
  527. };
  528. window.room.userlist.removeUser = function(id) {
  529. var self = room.userlist;
  530. var user = room.userlist.users[script.fns.getUserIndex(id)];
  531. if (user.loggedin && script.fns.get("showLogs") && messages > 4) {
  532. $('<span class="logLeft" style="opacity: 1">- ' + user.username + '<br />').appendTo('#logs');
  533. script.logs++;
  534. script.fns.cleanLog();
  535. }
  536. for (var i = 0; i < self.users.length; i++)
  537. {
  538. if (id === self.users[i].id)
  539. {
  540. self.users.splice(i, 1);
  541. $($('#user_list').children('li')[i]).remove();
  542. break;
  543. }
  544. }
  545. $('.user-count').text(self.users.length);
  546. };
  547. window.room.poll.create = function(poll) {
  548. var titleClass;
  549. var classes = {'#': 'hashtext', '!': 'urgenttext', '|': 'spoiler', '~': 'limetext'};
  550. $(".poll.active").removeClass("active");
  551. var pollEle = $("<div>",{class: "poll active"});
  552. if (room.user.isMod){ //mod controls
  553. pollEle.append($("<div>",{
  554. class:"mod poll-controls",
  555. html: $("<i>",{class:"fa fa-pencil poll-edit"}).prop('outerHTML') +" "+ $("<i>",{class: "fa fa-close poll-end"}).prop('outerHTML') //ALL THIS JUST TO ADD A SPACE
  556. }));
  557. }
  558. if (poll.title.substring(0, 4) === '&gt;')
  559. titleClass = 'greentext';
  560. else if (classes[poll.title[0]] !== undefined)
  561. titleClass = classes[poll.title[0]];
  562. var title = $("<div>",{
  563. class:"poll-title " + titleClass
  564. });
  565. title.html(script.fns.checkEmote(linkify(title.text(poll.title).html()))); //->text()->html() filters out < > etc.
  566. pollEle.append(title);
  567. var pollOptionsEle = $("<div>",{class:"poll-options"});
  568. for (var i = 0; i < poll.options.length; i++){
  569. var optionClass = '';
  570. if (poll.options[i].option.substring(0, 4) === '&gt;')
  571. optionClass = 'greentext';
  572. else if (classes[poll.options[i].option[0]] !== undefined)
  573. optionClass = classes[poll.options[i].option[0]];
  574. var voteEle = $("<span>",{class:"poll-votes",text:poll.options[i].votes});
  575. voteEle.data("option",i);
  576. var textEle = $("<div>",{class:"poll-text " + optionClass});
  577. textEle.html(script.fns.checkEmote(linkify(textEle.text(poll.options[i].option).html())));
  578. pollOptionsEle.append($("<div>",{class: "poll-option",}).append(voteEle).append(textEle));
  579. }
  580. pollEle.append(pollOptionsEle);
  581. pollEle.append($("<div/>",{
  582. class: "text-danger poll-ended",
  583. html:$("<i/>",{class:"fa fa-trash-o delete-poll"})
  584. }));
  585. pollEle.data('poll',poll);
  586. $("#poll_tab").prepend(pollEle);
  587. $("#poll_column").prepend(pollEle.clone(true));
  588. if (!$("#tabs_polls").parent().hasClass("active")){ //tab is not selected, so highlight it
  589. $("#tabs_polls").addClass("attention");
  590. }
  591. };
  592. sdbg.log("script.overwriteFunctions finished");
  593. };
  594.  
  595. window.script.setListeners = function() {
  596. $('#cin').off("focus");
  597. $('#cin').on('focus', function() {
  598. if (script.newMsg) {
  599. script.newMsg = false;
  600. var roomname = room.roomName.toLowerCase();
  601. if (roomname == "v4c") script.fns.setFavIcon('http://i.imgur.com/DmMh2O9.png'); else script.fns.setFavIcon('/favicon.ico');
  602. }
  603. });
  604. $('#clearchat_btn').off("click");
  605. $('#clearchat_btn').on('click', function() {
  606. script.fns.clearChat();
  607. });
  608. $('#resetsettings_btn').on('click', function() {
  609. for (var i in script.settings) {
  610. if (i.indexOf("recentVideos") < 0)
  611. localStorage.setItem(i, null)
  612. }
  613. script.fns.initializeSettings();
  614. script.fns.setChecks();
  615. console.log("Script settings reset to defaults.");
  616. });
  617. $('#recentTab').on('click', function() {
  618. if ($('#tabs_playlist_recent').hasClass('active') == false)
  619. script.fns.viewHistory($.parseJSON(script.fns.get(room.roomName.toLowerCase() + ".recentVideos")));
  620. });
  621. String.prototype.repeat = function(num) {
  622. return new Array(num + 1).join(this);
  623. };
  624. $('#cin').on('keydown', function(e) {
  625. if (e.which == 13) {
  626. if (script.fns.byteCount($('#cin').val()) > 250) {
  627. room.addMessage({username:''}, 'Message too large in size. Use less unicode characters. (Message was ' + script.fns.byteCount($('#cin').val()) + ' bytes, max 250 bytes)', 'errortext');
  628. return false;
  629. }
  630. if ($('#cin').val() == "'autoclean" && room.user.isMod) {
  631. script.fns.toggleAutoClean(null);
  632. } else if ($('#cin').val() == "'version") {
  633. room.addMessage({username:""}, "Script Version: " + script.version, "hashtext");
  634. }
  635. var msgTest = $('#cin').val().split(' ');
  636. if ($('#cin').val().slice(0, 9) == "'setskip " && !isNaN(parseInt(msgTest[1])) && msgTest[1] > -1 && room.user.isMod) {
  637. room.addMessage({username:''}, 'Skip rate set to ' + msgTest[1] + '%.', 'hashtext');
  638. } else if ($('#cin').val() == "'clear") {
  639. script.fns.clearChat();
  640. } else if (msgTest[0].toLowerCase() == "'countvids" && msgTest[1] !== undefined) {
  641. script.fns.findUserVideos(msgTest[1]);
  642. } else if (msgTest[0] == "&#8203;$r&#8203;o&#8203;l&#8203;l" || msgTest[0] == "&#8203;$8&#8203;b&#8203;a&#8203;l&#8203;l") {
  643. return false;
  644. } else if (msgTest[0].toLowerCase() === "$roll" && room.user.userinfo.loggedin) {
  645. msgTest[0] = "&#8203;$r&#8203;o&#8203;l&#8203;l";
  646. var numbers = 2;
  647. if (msgTest.length > 1) {
  648. var numTest = parseInt(msgTest[1]);
  649. if (!isNaN(numTest) && numTest > 0 && numTest < 11) {
  650. numbers = msgTest[1];
  651. }
  652. }
  653. numbers = parseInt(numbers);
  654. var numCount = "1".repeat(numbers);
  655. numCount = parseInt(numCount) * 9 + 1;
  656. var rollnum = "000000000" + Math.floor(Math.random() * numCount).toString();
  657. rollnum = rollnum.slice(-numbers);
  658. msgTest[msgTest.length] = rollnum;
  659. msgTest[msgTest.length] = "&#8203;";
  660. $('#cin').val(msgTest.join(" "));
  661. }
  662. if (msgTest[0].toLowerCase() === "$8ball" && room.user.userinfo.loggedin) {
  663. eight_choices = [
  664. "It is certain",
  665. "It is decidedly so",
  666. "Without a doubt",
  667. "Yes - definitely",
  668. "You may rely on it",
  669. "As I see it, yes",
  670. "Most likely",
  671. "Outlook good",
  672. "Signs point to yes",
  673. "Yes",
  674. "Ask again later",
  675. "Better not tell you now",
  676. "Cannot predict now",
  677. "Don't count on it",
  678. "My reply is no",
  679. "My sources say no",
  680. "Outlook not so good",
  681. "Very doubtful",
  682. "Never",
  683. "Of course not"
  684. ];
  685. msgTest[0] = "&#8203;$8&#8203;b&#8203;a&#8203;l&#8203;l";
  686. answer = eight_choices[Math.floor(Math.random() * eight_choices.length)];
  687. msgTest[msgTest.length] = "|" + answer + "|";
  688. msgTest[msgTest.length] = "&#8203;";
  689. $('#cin').val(msgTest.join(" "));
  690. }
  691. }
  692. });
  693. $("#toggle_autoclean_box").on("change", function(){
  694. var checked = $(this).is(":checked");
  695. script.fns.toggleAutoClean(checked);
  696. });
  697. $("#toggle_showadd_box").on("change", function(){
  698. var checked = $(this).is(":checked");
  699. script.fns.set("showAdd", checked);
  700. });
  701. $("#toggle_showroll_box").on("change", function(){
  702. var checked = $(this).is(":checked");
  703. script.fns.set("showRoll", checked);
  704. });
  705. $("#toggle_useemotes_box").on("change", function(){
  706. var checked = $(this).is(":checked");
  707. script.fns.set("useEmotes", checked);
  708. });
  709. $("#toggle_navbar_box").on("change", function(){
  710. var checked = $(this).is(":checked");
  711. script.fns.set("fixedNavbar", checked);
  712. if (checked)
  713. $('.navbar-fixed-top, .navbar-fixed-bottom').css('position', 'fixed');
  714. else
  715. $('.navbar-fixed-top, .navbar-fixed-bottom').css('position', 'static');
  716. });
  717. $("#toggle_fast_box").on("change", function() {
  718. var checked = $(this).is(":checked");
  719. script.fns.set("showFast", checked);
  720. if (checked)
  721. $codes['fast'] = '<marquee direction="right" scrollamount="' + script.fns.get("marqueeSpeed") + '">';
  722. else
  723. delete $codes.fast;
  724. });
  725. $('#toggle_spin_box').on("change", function() {
  726. var checked = $(this).is(":checked");
  727. script.fns.set("showSpin", checked);
  728. if (checked)
  729. $codes['spin'] = '<span class="spin">';
  730. else
  731. delete $codes.spin;
  732. });
  733. $("#toggle_showlogs_box").on("change", function(){
  734. var checked = $(this).is(":checked");
  735. script.fns.set("showLogs", checked);
  736. if (checked) {
  737. $('.logWrapper').show();
  738. } else {
  739. $('.logWrapper').hide();
  740. $('#logs').empty();
  741. }
  742. });
  743. }
  744.  
  745. window.script.fns = {
  746. set: function(key, value) {
  747. localStorage.setItem(key, value);
  748. },
  749. get: function(key) {
  750. var a = localStorage.getItem(key);
  751. var b;
  752. if (a == "true" || a == "false")
  753. if (a == "true")
  754. b = true;
  755. else
  756. b = false;
  757. else if (!isNaN(parseInt(a)))
  758. b = parseInt(a);
  759. else b = a;
  760. return b;
  761. },
  762. remove: function(key) {
  763. localStorage.removeItem(key);
  764. },
  765. updateNotice: function(state, ver) {
  766. if (state == 'on' && ver != script.version) {
  767. $('.newUpdate').show();
  768. } else if (state == 'off') {
  769. $('.newUpdate').hide();
  770. }
  771. },
  772. setFast: function(data) {
  773. if (!isNaN(parseInt(data))) {
  774. if (data > 999) {
  775. data = 999;
  776. $('#marqueeinput').val(data);
  777. }
  778. script.fns.set("marqueeSpeed", data);
  779. if (script.fns.get("showFast")) {
  780. $codes['fast'] = '<marquee direction="right" scrollamount="' + data + '">';
  781. }
  782. }
  783. },
  784. updateRecent: function(a) {
  785. sdbg.log("updateRecent called");
  786. var recent = script.fns.get(room.roomName.toLowerCase() + ".recentVideos");
  787. recent = $.parseJSON(recent);
  788. if (recent == null)
  789. recent = [];
  790. if (recent.some(function(b) {return b.info.id == room.playlist.videos[a].info.id}) == false) {
  791. recent.push(room.playlist.videos[a]);
  792. if (recent.length > script.MAXRECENT)
  793. recent = recent.slice(recent.length - script.MAXRECENT)
  794. script.fns.viewHistory(recent);
  795. }
  796. recent = JSON.stringify(recent);
  797. script.fns.set(room.roomName.toLowerCase() + ".recentVideos", recent);
  798. },
  799. postRoll: function(type, a, user) {
  800. if (type == "roll") {
  801. var rolledNumber = a[a.length - 2];
  802. var numColor = '#005cff';
  803. a[a.length - 2] = '';
  804. if (rolledNumber.length > 10)
  805. rolledNumber = rolledNumber.slice(0, 10);
  806. if (rolledNumber == parseInt(rolledNumber)) {
  807. var j = 1;
  808. var k = rolledNumber.length;
  809. for (var i = 1; i < k; i++) {
  810. if (rolledNumber[i] === rolledNumber[i - 1])
  811. j++;
  812. else
  813. break;
  814. }
  815. if (k === j) numColor = '#f90';
  816. return '<span class="gm rollstr">&nbsp;' + user + ' rolled <span style="color:' + numColor + '; font-weight: bold; font-style: normal">' + rolledNumber + ' </span><br />';
  817. } else return "";
  818. } else if (type == "8ball") {
  819. return '<span class="gm ballstr">&nbsp;' + user + ': 8ball says, <span style="color:#f00; font-weight: bold; font-style: normal">"' + a + '" </span><br />';
  820. } else return '';
  821. },
  822. clearChat: function() {
  823. $('#chat_messages').empty();
  824. messages = script.fastmsgs = script.spinmsgs = 0;
  825. },
  826. gmtClock: function() {
  827. var time = new Date();
  828.  
  829. var gmtTime = {hrs: time.getUTCHours(), min: time.getUTCMinutes(), sec: time.getUTCSeconds()}
  830.  
  831. for (var i in gmtTime) {
  832. if (gmtTime[i] < 10) gmtTime[i] = "0" + gmtTime[i]
  833. }
  834.  
  835. $('#gmtClock').text(gmtTime.hrs + ":" + gmtTime.min + ":" + gmtTime.sec + ' GMT');
  836.  
  837. setTimeout(function() {script.fns.gmtClock()}, 1000);
  838. },
  839. getPlaylist: function() {
  840. //heavily modified from Bibby's exportPlaylist() at https://github.com/Bibbytube/Instasynch under Playlist Additions/Export Playlist Command
  841. var output = '';
  842. var videoTitle = '';
  843. var playlist = room.playlist.videos;
  844. if (playlist.length > 0) {
  845.  
  846. for (i = 0; i < playlist.length; i++) {
  847. if (playlist[i].title.length > 100) {
  848. videoTitle = playlist[i].title.substring(0, 100);
  849. videoTitle += '...';
  850. } else {
  851. videoTitle = playlist[i].title;
  852. }
  853. switch (playlist[i].info.provider) {
  854. case 'youtube':
  855. output += i + '. <span style="color: #FFB0B0">' + videoTitle + ' <span style="color: #84FFAB">-</span></span> <a style="color: #4FDFFA" href="http://youtube.com/watch?v=' + playlist[i].info.id + '">http://youtube.com/watch?v=';
  856. break;
  857. case 'vimeo':
  858. output += i + '. <span style="color: #61CCFF">' + videoTitle + ' <span style="color: #84FFAB">-</span></span> <a style="color: #4FDFFA" href="http://vimeo.com/' + playlist[i].info.id + '">http://vimeo.com/';
  859. break;
  860. case 'twitch':
  861. output += i + '. <span style="color: #E8BEFF">' + videoTitle + ' <span style="color: #84FFAB">-</span></span> <a style="color: #4FDFFA" href="http://twitch.tv/' + playlist[i].info.channel + '">http://twitch.tv/';
  862. break;
  863. case 'dailymotion':
  864. output += i + '. <span style="color: #F8FFA1">' + videoTitle + ' <span style="color: #84FFAB">-</span></span> <a style="color: #4FDFFA" href="http://dailymotion.com/video/' + playlist[i].info.id + '">http://dailymotion.com/video/';
  865. break;
  866. default:
  867. continue;
  868. }
  869. if (playlist[i].info.provider === 'twitch')
  870. output += playlist[i].info.channel + '</a>\n<br />';
  871. else
  872. output += playlist[i].info.id + '</a>\n<br />';
  873. }
  874. var newWindow = window.open("", "_blank", "scrollbars=1,resizable=1");
  875. newWindow.document.write('<span style="font-size: 16px; color: white">Select all (ctrl+a), copy/paste and save this somewhere.<br />Room: ' + room.roomName + '<br />Videos: ' + playlist.length + '</span><br /><br /><div id="playlistInfo" style="font-size: 12px; color: #84FFAB">' + output + '</div>');
  876. newWindow.document.body.style.background = 'black';
  877. newWindow.document.body.style.fontFamily = 'tahoma';
  878. } else {
  879. console.error("Cannot grab playlist, no videos.");
  880. return;
  881. }
  882. },
  883. // adjustCurtain() -- resize curtain upon change of screen layout, and toggle
  884. adjustCurtain: function () {
  885. var a = {h: $('#media').height(), w: $('#media').width()};
  886. // a is an object of #media dimensions {h: height,w: width}
  887. // floor of the curtain always has a constant height, so subtract
  888. // the height of the floor from the height of the video to get the new curtainTop height
  889. if ($('#curtainTop').width() !== a.w)
  890. $('#curtainTop').width(a.w);
  891. if ($('#curtainFloor').width() !== a.w)
  892. $('#curtainFloor').width(a.w);
  893. if ($('.curtain').height() !== a.h)
  894. $('.curtain').height(a.h);
  895. if ($('#curtainFloor').height() === 0) $('#curtainFloor').height(72)
  896. else $('#curtainFloor').height(0);
  897. if ($('#curtainTop').height() === 0) $('#curtainTop').height($('#media').height() - 72)
  898. else $('#curtainTop').height(0);
  899. },
  900. findUserVideos: function(user) {
  901. var vids = 0;
  902. var userLower = user.toLowerCase();
  903. if (room.playlist.videos.length !== 0) {
  904. for (var i = 0; i < room.playlist.videos.length; i++) {
  905. if (room.playlist.videos[i].addedby.toLowerCase() == userLower) {
  906. vids++;
  907. }
  908. }
  909. addMessage({username:''},'Found ' + vids + ' video(s) added by ' + user + '.','hashtext');
  910. } else {
  911. addMessage({username:''},'No videos in playlist.','urgenttext');
  912. }
  913. },
  914. getUserIndex: function(id) {
  915. for (var i = 0; i < room.userlist.users.length; i++) {
  916. if (id == room.userlist.users[i].id) {
  917. return i;
  918. }
  919. }
  920. return -1;
  921. },
  922. cleanLog: function() {
  923. if (script.logs > script.MAXLOGS) {
  924. $('#logs span').eq(1).css('opacity', '.4');
  925. $('#logs span').eq(2).css('opacity', '.6');
  926. $('#logs span').eq(3).css('opacity', '.8');
  927. $('#logs span').eq(0).remove();
  928. script.logs--;
  929. }
  930. },
  931. setTabTitle: function(a,b,c,d) { //vidinfo, addedby, video index, title
  932. var newTitle = d;
  933. if (newTitle.length > 55) {
  934. newTitle = newTitle.substring(0, 55);
  935. newTitle += '...';
  936. }
  937. var currentVid = newTitle + ' via ' + b;
  938. var videoLink = '';
  939. document.title = decodeURIComponent('%E2%96%B6') + ' ' + currentVid;
  940. switch (a.provider) {
  941. case "youtube":
  942. videoLink = 'http://youtu.be/' + a.id;
  943. break;
  944. case "vimeo":
  945. videoLink = 'http://vimeo.com/' + a.id;
  946. break;
  947. case "twitch":
  948. videoLink = 'http://twitch.tv/' + a.channel;
  949. break;
  950. case "dailymotion":
  951. videoLink = 'http://dailymotion.com/video/' + a.id;
  952. break;
  953. default:
  954. videoLink = 'unlisted source';
  955. break;
  956. }
  957. console.log('Now playing: ' + currentVid + ' ( ' + videoLink + ' )');
  958. },
  959. setFavIcon: function(src) {
  960. var a = '<link rel="shortcut icon" class="scr-fav" href="' + src + '">';
  961. $('.scr-fav').remove();
  962. $('head').append(a);
  963. },
  964. scrollTopPl: function() { //from built-in room.playVideo
  965. $('#playlist').animate({
  966. scrollTop: $("#playlist .active").offset().top - $("#playlist .active").offset().top + $("#playlist .active").scrollTop()
  967. });
  968. },
  969. byteCount: function(s){return encodeURIComponent(s).replace(/%[A-F\d]{2}/g,'x').length},
  970. //https://gist.github.com/mathiasbynens/1010324
  971. playSound: function(sound) {
  972. var vol = 0.8;
  973. if (typeof(room.video) !== "undefined")
  974. vol = room.video.video.volume();
  975. sound.volume = vol;
  976. sound.play();
  977. },
  978. testHexColor: function(str) {
  979. if (str.length == 7) {
  980. return (/^#[0-9a-f]{6}$/i).test(str);
  981. } else if (str.length == 4) {
  982. return (/^#[0-9a-f]{3}$/i).test(str);
  983. } else {
  984. return false;
  985. }
  986. },
  987. buildEmotes: function() {
  988. sdbg.log("script.fns.buildEmotes called");
  989. window.script.$initialcodes = window.$codes;
  990. window.script.$newcodes = {
  991. //modified original emotes
  992. 'chen': '<img src="http://i.imgur.com/j55EMQt.png" width="50" height="46" onclick="script.fns.playSound(script.emoteSounds.chen);">',
  993. 'doot': '<img src="http://i.imgur.com/WfUlQ5Q.gif" width="50" height="45" onclick="script.fns.playSound(script.emoteSounds.doot);">',
  994. 'bestgames': '<img src="http://i.imgur.com/ImyXj.png" width="48" height="54" onclick="script.fns.playSound(script.emoteSounds.chad);">',
  995. 'no': '<img src="http://i.imgur.com/nKa8o.png" width="41" height="30" onclick="script.fns.playSound(script.emoteSounds.no);">',
  996. 'idontwantthat': '<img src="http://i.imgur.com/nKa8o.png" width="41" height="30" onclick="script.fns.playSound(script.emoteSounds.no);">',
  997. 'heero' : '<img src="http://i.imgur.com/D7JCR6j.png" width="60" height="55">',
  998. 'kek' : '<img src="http://i.imgur.com/xrw4paP.png" width="40" height="54">',
  999. //additional emotes
  1000. 'chen2': '<img src="http://i.imgur.com/TGHRo8W.gif" width="54" height="50" onclick="script.fns.playSound(script.emoteSounds.chen2);">',
  1001. 'kitty2': '<img src="http://i.imgur.com/yxBHAvx.gif" width="38" height="60">',
  1002. 'enjoytheanime' : '<img src="http://i.imgur.com/aXPWln0.png" width="48" height="60">',
  1003. 'straya' : '<img src="http://i.imgur.com/PNB0kE9.gif" width="50" height="50">',
  1004. 'neverever' : '<img src="http://i.imgur.com/MJnWGHV.png" width="52" height="50">',
  1005. 'gud': '<img src="http://i.imgur.com/Ms3Zxne.png" width="62.5" height="50">',
  1006. 'feelssmug': '<img src="http://i.imgur.com/og9In6D.png" width="48" height="48">',
  1007. 'puke': '<img src="http://i.imgur.com/IADYHCP.png" width="58" height="58">',
  1008. 'tip': '<img src="http://i.imgur.com/QWhYbc8.gif" width="49" height="54">',
  1009. 'copythat': '<img src="http://i.imgur.com/VOibACz.png" width="31" height="51">',
  1010. 'ree': '<img src="http://i.imgur.com/U1Trjzq.gif" width="42" height="42">',
  1011. 'alien2': '<img src="http://i.imgur.com/jBji5uc.gif" width="43" height="63">',
  1012. };
  1013.  
  1014. window.script.$colorcodes = {
  1015. "knuckles": '</span><span style="color:tomato">',
  1016. "mario": '</span><span style="color:red">',
  1017. "starfox": '</span><span style="color:brown">',
  1018. "tomnook": '</span><span style="color:chocolate">',
  1019. "crashbandicoot": '</span><span style="color:orange">',
  1020. "orange": '</span><span style="color:orange">',
  1021. "pacman": '</span><span style="color:yellow">',
  1022. "gex": '</span><span style="color:yellowgreen">',
  1023. "link": '</span><span style="color:green">',
  1024. "halo2": '</span><span style="color:darkgreen">',
  1025. "chao": '</span><span style="color:aqua">',
  1026. "squirtle": '</span><span style="color:cyan">',
  1027. "liara": '</span><span style="color:steelblue">',
  1028. "bluebomber": '</span><span style="color:royalblue">',
  1029. "sonic": '</span><span style="color:blue">',
  1030. "krystal": '</span><span style="color:darkblue">',
  1031. "bigthecat": '</span><span style="color:indigo">',
  1032. "nights": '</span><span style="color:purple">',
  1033. "spyro": '</span><span style="color:blueviolet">',
  1034. "birdo": '</span><span style="color:deeppink">',
  1035. "kirby": '</span><span style="color:violet">',
  1036. "wakeupmrfreeman": '</span><span style="color:tan">',
  1037. "tomba": '</span><span style="color:pink">',
  1038. "metalgear": '</span><span style="color:silver">',
  1039. "kidicarus": '</span><span style="color: white">',
  1040. "gamenwatch": '</span><span style="color: black">',
  1041. "outline": '<span style="text-shadow: 1px 0 #00ccff, -1px 0px #00ccff, 0 1px #00ccff, 0 -1px #00ccff">',
  1042. "redoutline" : '<span style="text-shadow: 1px 0 #f00, -1px 0px #f00, 0 1px #f00, 0 -1px #f00">'
  1043. //"rainbowroad" : '</span><span class="rainbow">'
  1044. };
  1045. window.script.$fontcodes = {
  1046. "spoiler": '<font style="text-shadow: 0 0 black; background-color: #000; cursor: default" onmouseover="this.style.backgroundColor=\'transparent\'" onmouseout="this.style.backgroundColor=\'black\'">',
  1047. "i": '<font style="font-style:italic">',
  1048. "u": '<font style="text-decoration: underline">',
  1049. "b": '<strong>',
  1050. "s": '<strike>',
  1051. "endbold": '</strong>',
  1052. "endstrike": '</strike>',
  1053. "endspan": '</span></font></font></font>'
  1054. };
  1055. $.extend(script.$newcodes, script.$externalEmotes);
  1056. $.extend(script.$colorcodes, script.$fontcodes);
  1057. $.extend($codes, script.$newcodes);
  1058. $.extend($codes, script.$colorcodes);
  1059. sdbg.log("script.fns.buildEmotes finished");
  1060. },
  1061. useEmote: function(code) {
  1062. var msg = $('#cin').val();
  1063. //if (useColons)
  1064. msg = msg + ":" + code + ":";
  1065. //else
  1066. // msg = "/" + code;
  1067. $('#cin').val(msg);
  1068. },
  1069. buildEmoteMenu: function() {
  1070. var emoteMenu,code;
  1071. emoteMenu = code = '';
  1072.  
  1073. var endtags = {
  1074. s: ['<strike', '</strike>', 'Strikethrough'],
  1075. b: ['<strong', '</strong>', 'Bold'],
  1076. u: ['<font style="text-decoration: underline"', '</font>', 'Underline'],
  1077. i: ['<font style="font-style:italic"', '</font>', 'Italics'],
  1078. endstrike: ['<strike', '</strike>', 'End Strikethrough'],
  1079. endbold: ['<strong', '</strong>', 'End Bold'],
  1080. endspan: ['<strong style="text-decoration: underline; font-style: italic"', '</strong>', 'End font effects'],
  1081. spoiler: ['<font style="text-shadow: 0 0 black; background-color: #000; cursor: default" onmouseover="this.style.backgroundColor=\'transparent\'" onmouseout="this.style.backgroundColor=\'black\'"', '</font>', 'Spoiler']
  1082. }
  1083.  
  1084. $.each($codes, function(code, image) {
  1085. if (code != 'fast' && code != 'spin' && script.$colorcodes[code] == undefined) {
  1086. emoteMenu = emoteMenu + '<span title="' + code + '" onclick="script.fns.useEmote(\'' + code + '\')">' + image + '</span>';
  1087. }
  1088. });
  1089. emoteMenu += "<br />";
  1090. $.each(script.$colorcodes, function(code, bgcolor) {
  1091. if (code !== 'rainbowroad' && script.$fontcodes[code] == undefined) {
  1092. if (code == 'outline') {
  1093. bgcolor = 'color: black;box-shadow: 0 0 15px #00ccff inset';
  1094. } else if (code == 'redoutline') {
  1095. bgcolor = 'color: black;box-shadow: 0 0 15px #f00 inset';
  1096. } else {
  1097. bgcolor = bgcolor.slice(20, -2);
  1098. }
  1099. emoteMenu = emoteMenu + '<span class="colors" title="' + code + '" style="background-' + bgcolor + '" onclick="script.fns.useEmote(\'' + code + '\')"></span>';
  1100. }
  1101. });
  1102. emoteMenu += "<br />";
  1103. $.each(script.$fontcodes, function(code, node) {
  1104.  
  1105. var endc = '<font';
  1106. var endtag = '</font>';
  1107. var txt = '';
  1108.  
  1109. if (code in endtags) {
  1110. endc = endtags[code][0];
  1111. endtag = endtags[code][1];
  1112. txt = endtags[code][2];
  1113. }
  1114. emoteMenu = emoteMenu + '<span class="font-codes" title="' + code + '" onclick="script.fns.useEmote(\'' + code + '\')">' + endc + ' class="' + code + '">' + txt + endtag + '</span>';
  1115. });
  1116.  
  1117. $('#emotes').remove();
  1118. $('#emote_list').append('<div id="emotes">' + emoteMenu + '</div>');
  1119. //$('#emotes').css('display', 'none');
  1120. },
  1121.  
  1122. toggleAutoClean: function(setting) {
  1123. var ac;
  1124. if (setting == true)
  1125. ac = true;
  1126. else if (setting == false)
  1127. ac = false;
  1128. else {
  1129. ac = script.fns.get("autoClean");
  1130. ac = !ac;
  1131. }
  1132. if (ac) {
  1133. room.addMessage({username:''}, 'Autoclean is now on. The next video must be position 1 to autoclean.', 'hashtext');
  1134. } else {
  1135. room.addMessage({username:''}, 'Autoclean is now off.', 'hashtext');
  1136. }
  1137. script.fns.set("autoClean", ac);
  1138. $('#toggle_autoclean_box').prop('checked', ac);
  1139. },
  1140. checkEmote: function(message) {
  1141. var doCheck = script.fns.get("useEmotes");
  1142. if (doCheck) {
  1143. var a,b,c,d,e;
  1144. a = b = c = d = e = 0;
  1145. while (a < message.length && a >= 0 && e < 4) {
  1146. var checked = false;
  1147. d++;
  1148. a = message.indexOf(':', a);
  1149. b = message.indexOf(':', a + 1);
  1150. var f = message.slice(a, b + 1);
  1151. if ($codes[f.slice(1, -1).toLowerCase()] != undefined || f.slice(1, -1)[0] === '#') {
  1152.  
  1153. if (f.slice(1, -1)[0] === '#') {
  1154. if (script.fns.testHexColor(f.slice(1, -1))) {
  1155. var colorNode = "</span><span style='color: " + f.slice(1, -1) + "'>";
  1156. message = message.replace(f, colorNode);
  1157. c = colorNode.length;
  1158. checked = true;
  1159. e += 0.5;
  1160. }
  1161. }
  1162. if (!checked) {
  1163. var emote = f.slice(1, -1).toLowerCase();
  1164. if ($codes[emote] !== undefined)
  1165. c = $codes[emote].length;
  1166. else
  1167. return message;
  1168. message = message.replace(f, $codes[emote]);
  1169. if (script.$colorcodes[emote] !== undefined || script.$fontcodes[emote] !== undefined || emote == "fast" || emote == "spin") e += 0.5;
  1170. else e++;
  1171. }
  1172. if (c < f.slice(1, -1).length) {
  1173. a = message.indexOf(f.slice(1, -1));
  1174. } else {
  1175. a += c;
  1176. }
  1177. } else if ($codes[f.slice(1, -1).toLowerCase()] === undefined) {
  1178. a = b;
  1179. } else if (d >= 10) {
  1180. break;
  1181. }
  1182. }
  1183. }
  1184. return message;
  1185. },
  1186. cleanFast: function() {
  1187. if ($('#chat_messages.chat-messages .message marquee')[0] === undefined)
  1188. script.fastmsgs = 0;
  1189. while (script.fastmsgs > script.MAXFAST) {
  1190. $('#chat_messages.chat-messages .message marquee')[0].remove();
  1191. script.fastmsgs--;
  1192. }
  1193. },
  1194. cleanSpin: function() {
  1195. if ($('#chat_messages.chat-messages .message .spin')[0] === undefined)
  1196. script.spinmsgs = 0;
  1197. while (script.spinmsgs > script.MAXSPIN) {
  1198. $('#chat_messages.chat-messages .message .spin')[0].remove();
  1199. script.spinmsgs--;
  1200. }
  1201. },
  1202. viewHistory: function(vids) {
  1203. var icon = '';
  1204. var host = '';
  1205. var thumb = '';
  1206. var title = '';
  1207. var key = {
  1208. 'youtube': {icon: 'http://i.imgur.com/KpOgg0D.png', host: 'http://youtube.com/watch?v='},
  1209. 'vimeo': {icon: 'http://i.imgur.com/TOogvwC.png', host: 'http://vimeo.com/'},
  1210. 'dailymotion': {icon: 'http://i.imgur.com/n7HR2hF.png', host: 'http://dailymotion.com/video/'},
  1211. 'twitch': {icon: 'http://i.imgur.com/0jO0wYz.png', host: 'http://twitch.tv/'},
  1212. }
  1213. $('#recent_list').empty();
  1214. for (var i = vids.length - 1; i > -1; i--) {
  1215. thumb = vids[i].info.thumbnail;
  1216. if (vids[i].info.provider in key) {
  1217. icon = key[vids[i].info.provider].icon;
  1218. host = key[vids[i].info.provider].host;
  1219. if (vids[i].info.provider === 'twitch')
  1220. vids[i].info.id = vids[i].info.channel;
  1221. }
  1222. title = vids[i].title;
  1223. if (title.length > 100)
  1224. title = title.slice(0,100) + '...';
  1225. $('#recent_list').append('<li class="search-result" title="' + title + '"><a href="' + host + vids[i].info.id + '" target="_blank"><span class="video-thumb"><img class="video-thumbnail" src="' + thumb + '"><img class="video-icon" src="' + icon + '"><span class="video-time">' + utils.secondsToTime(vids[i].duration) + '</span></span><span class="video-title">' + title + '</span><span class="video-uploader">added by <b><span id="vidUploader">' + vids[i].addedby + '</span></b></a></li>');
  1226. }
  1227. },
  1228. bumpUser: function(user, bumpTo) {
  1229. if (room.user.isMod) {
  1230. var a = false;
  1231. var c = [];
  1232. var b = '';
  1233. var d = '';
  1234. var e = bumpTo;
  1235. var pl = room.playlist.videos;
  1236. var users = room.userlist.users;
  1237. if (e > 0)
  1238. e = e - 1;
  1239. else if (e === null)
  1240. e = $('#playlist.playlist li.active').index() + 1;
  1241. e = parseInt(e);
  1242. if (isNaN(e) || e >= pl.length) {
  1243. d = 'Invalid playlist position.';
  1244. } else {
  1245. if (user !== '\\r') {
  1246. for (var i = 0; i < users.length; i++) {
  1247. if (users[i].username.toLowerCase().indexOf(user) == 0 && users[i].loggedin) {
  1248. c.push(users[i].username);
  1249. }
  1250. }
  1251. if (c.length > 1) {
  1252. d = 'Multiple users found. Be more specific.';
  1253. } else if (c.length == 0) {
  1254. d = 'No users found.';
  1255. } else if (c.length == 1) {
  1256. b = c[0];
  1257. for (var l = pl.length - 1; l > -1; l--) {
  1258. if (pl[l].addedby.toLowerCase() == b.toLowerCase()) {
  1259. a = true;
  1260. room.sendcmd('move', {
  1261. info: pl[l].info,
  1262. position: e
  1263. });
  1264. break;
  1265. }
  1266. }
  1267. if (a) {
  1268. d = 'Bumped ' + b + '.';
  1269. } else {
  1270. d = 'No videos found.';
  1271. }
  1272. }
  1273. } else {
  1274. f = Math.ceil(Math.random() * playlist.length) - 1;
  1275. if (f == $('#playlist.playlist li.active').index()) {
  1276. f++;
  1277. }
  1278. if (f > pl.length - 1) {
  1279. d = 'Playlist too small.';
  1280. } else {
  1281. room.sendcmd('move', {
  1282. info: pl[f].info,
  1283. position: e
  1284. });
  1285. d = 'Random video (' + f + ') bumped.';
  1286. }
  1287. }
  1288. }
  1289. } else {
  1290. d = 'You cannot use this command.';
  1291. }
  1292. room.addMessage({username:""}, '<span style="color: red; font-style: none; font-weight:bold">$bump: </span>' + d + '</span></div>', 'system');
  1293. },
  1294. initializeSettings: function() {
  1295. var get = script.fns.get;
  1296. var set = script.fns.set;
  1297. for (var i in script.settings) {
  1298. sdbg.log("checking settings: " + i);
  1299. var val = get(i);
  1300. // i = key, val = key's value
  1301. if (i == room.roomName.toLowerCase() + ".recentVideos") {
  1302. if (typeof($.parseJSON(val)) !== "object" || val == null) {
  1303. sdbg.log("- initializing " + i);
  1304. set(room.roomName.toLowerCase() + ".recentVideos", "[]");
  1305. }
  1306. } else if (i == "currentCSS") {
  1307. if (script.cssLinks[val] === undefined) {
  1308. sdbg.log("- initializing " + i);
  1309. set(i, script.settings[i]);
  1310. }
  1311. } else if (i == "lastVersion") {
  1312. if (val !== script.version || val == null) {
  1313. sdbg.log("- initializing " + i);
  1314. set(i, script.version);
  1315. }
  1316. } else if (typeof(val) !== typeof($.parseJSON(script.settings[i])) || val == null) {
  1317. sdbg.log("- initializing " + i);
  1318. set(i, script.settings[i]);
  1319. }
  1320. }
  1321. //booleans: "showLogs", "showAdd", "showFast", "showRoll", "indentChat", "autoClean"
  1322. //other: "marqueeSpeed", "recentVideos"
  1323. if (isNaN(parseInt(get("marqueeSpeed"))))
  1324. set("marqueeSpeed", script.settings["marqueeSpeed"]);
  1325. script.marqueeSpeed = parseInt(get("marqueeSpeed"));
  1326. if (get("showFast"))
  1327. $codes['fast'] = '<marquee direction="right" scrollamount="' + get("marqueeSpeed") + '">';
  1328. if (get("showSpin"))
  1329. $codes['spin'] = '<span class="spin">';
  1330. },
  1331. setCustomLayout: function(layoutName) {
  1332. var css = script.cssLinks;
  1333. if (css[layoutName] === undefined)
  1334. return;
  1335. if (css !== "none") {
  1336. if ($('.customLayout').href !== css[layoutName][2]) {
  1337. $('.customLayout').remove();
  1338. $('head').append('<link href="' + css[layoutName][2] + '" type="text/css" rel="stylesheet" class="customLayout">');
  1339. }
  1340. } else {
  1341. $('.customLayout').remove();
  1342. }
  1343. if (script.fns.get("currentCSS") !== layoutName) {
  1344. script.fns.set("currentCSS", layoutName);
  1345. $('#css-' + layoutName).prop('checked', true);
  1346. }
  1347. },
  1348. addLog: function(title, addedby) {
  1349. var cl = $('#chat_messages .message');
  1350. if (typeof(title) !== "undefined")
  1351. if (title.length > 80)
  1352. title = title.slice(0, 80) + '...';
  1353. if (cl.length > 0) {
  1354. if (cl[cl.length - 1].textContent.substring(0,12) !== ': Welcome to' && messages > 0) {
  1355. room.addMessage({username:'%addVideo'}, addedby + ' added ' + title, 'gm vid');
  1356. }
  1357. } else {
  1358. }
  1359. },
  1360. addTempEmote: function(name, url, w, h) {
  1361. var newEmote = {};
  1362. if (w == null)
  1363. w = '';
  1364. if (h == null)
  1365. h = '';
  1366. var node = '<img src="' + url + '" width="' + w + '" height="' + h + '">';
  1367. newEmote[name] = node;
  1368. $.extend($codes, newEmote);
  1369. },
  1370.  
  1371. setChecks: function() {
  1372. $('#marqueeinput').val(script.fns.get("marqueeSpeed"));
  1373. $('#toggle_showlogs_box').prop('checked', script.fns.get("showLogs"));
  1374. $('#toggle_fast_box').prop('checked', script.fns.get("showFast"));
  1375. $('#toggle_spin_box').prop('checked', script.fns.get("showSpin"));
  1376. $('#toggle_showroll_box').prop('checked', script.fns.get("showRoll"));
  1377. $('#toggle_showadd_box').prop('checked', script.fns.get("showAdd"));
  1378. $('#toggle_autoclean_box').prop('checked', script.fns.get("autoClean"));
  1379. $('#toggle_useemotes_box').prop('checked', script.fns.get("useEmotes"));
  1380. $('#toggle_navbar_box').prop('checked', script.fns.get("fixedNavbar"));
  1381. $('#css-' + script.fns.get("currentCSS")).prop('checked', true);
  1382. if (script.fns.get("showLogs"))
  1383. $('.logWrapper').show();
  1384. else
  1385. $('.logWrapper').hide();
  1386. if (script.fns.get("fixedNavbar") == false) {
  1387. $('.navbar-fixed-top, .navbar-fixed-bottom').css('position', 'static');
  1388. } else {
  1389. $('.navbar-fixed-top, .navbar-fixed-bottom').css('position', 'fixed');
  1390. }
  1391.  
  1392. script.fns.setCustomLayout(script.fns.get("currentCSS"));
  1393. },
  1394. load: function() {
  1395. if (window.script.loaded == false) {
  1396. if (window.script.preloaded == false) {
  1397. for (var i = 0; i < script.pretasks.length; i++) {
  1398. sdbg.log("Pre-connect Task "+i+" executing...");
  1399. script.pretasks[i]();
  1400. sdbg.log("- Pre-connect Task "+i+" executed!");
  1401. }
  1402. window.script.preloaded = true;
  1403. }
  1404. //if ($('#user_list.user-list li').length < 1) {
  1405. // setTimeout(function() {
  1406. // script.fns.load();
  1407. // }, 50);
  1408. //} else {
  1409. window.script.loaded = true;
  1410. if (room.roomName.toLowerCase() == "v4c") script.fns.setFavIcon('http://i.imgur.com/DmMh2O9.png'); else script.fns.setFavIcon('/favicon.ico');
  1411. for (var i = 0; i < script.tasks.length; i++) {
  1412. sdbg.log("Task "+i+" executing...");
  1413. script.tasks[i]();
  1414. sdbg.log("- Task "+i+" executed!");
  1415. }
  1416. console.log("Script loaded.");
  1417. var hello = '<span style="font-weight:bold; color:#045AA4">Loaded ' + script.version + '.';
  1418. if (script.debug)
  1419. hello += ' <span style="font-weight:bold; color:#7304A4">Debug to console ON.</span>';
  1420. hello += '</span>';
  1421. room.addMessage({username:""}, hello, 'system');
  1422. setTimeout(function() {
  1423. window.script.delayedTasks.push(script.fns.buildEmoteMenu);
  1424. for (var i = 0; i < script.delayedTasks.length; i++) {
  1425. sdbg.log("Delayed task "+i+" executing...");
  1426. script.delayedTasks[i]();
  1427. sdbg.log("- Delayed task "+i+" executed!");
  1428. }
  1429. }, 700);
  1430. sdbg.log("script.fns.load finished");
  1431. //}
  1432. }
  1433. }
  1434.  
  1435. };
  1436.  
  1437. window.script.setCSS = function() {/*0B2hdmKDeA0HDZ2IwRFRzaTV2dEU*/
  1438. $('.scriptBaseCSS').remove();
  1439. $('head').append('<link class="scriptBaseCSS" href="https://googledrive.com/host/0B2hdmKDeA0HDU1Vlb3FWMmVadTQ" rel="stylesheet" type="text/css">');
  1440. sdbg.log("Base CSS added to page header");
  1441. };
  1442.  
  1443. window.script.setHTML = function() {
  1444. if (!script.htmlIsSet) {
  1445. script.htmlIsSet = true;
  1446. if (script.fns.get("showLogs"))
  1447. $('.nav.navbar-nav.navbar-right').append('<div class="logWrapper"><div id="logs"></div></div>');
  1448. else
  1449. $('.nav.navbar-nav.navbar-right').append('<div class="logWrapper" style="display:none"><div id="logs"></div></div>');
  1450. if (script.fns.get("fixedNavbar") == false)
  1451. $('.navbar-fixed-top, .navbar-fixed-bottom').css('position', 'static');
  1452. $('.nav.navbar-nav.navbar-right').append('<div class="newUpdate" style="display:none"><a href="https://greasyfork.org/en/scripts/6366" target="_blank">New script update! Click here!</a></div>');
  1453. $('.nav.navbar-nav.navbar-right').prepend('<div id="gmtClock"></div>');
  1454. $('.video-controls .tab-content').append('<div class="tab-pane" id="tabs_playlist_emotes"><div class="pl-tab_header">Emote List</div><div id="emote_list"></div></div>');
  1455. $('.video-controls .tab-content').append('<div class="tab-pane" id="tabs_playlist_recent"><div class="pl-tab_header">Recent Videos - ' + room.roomName + '</div><div id="recent_list"></div></div>');
  1456. $('.video-controls .tab-content').append('<div class="tab-pane" id="tabs_playlist_cssmenu"><div class="pl-tab_header">Custom Layouts</div><div id="layout_list"></div></div>');
  1457. $('<li><a class="active_tooltip" title="Emote Menu" data-original-title="Emote Menu" href="#tabs_playlist_emotes" data-toggle="tab" rel="tooltip" data-placement="bottom"><i class="fa" style="width: 12px;height: 14px;"><img src="https://i.imgur.com/vETtK.png" class="fa-ainsley"></i></a></li>').insertBefore('.video-controls .nav-tabs .skip-controls');
  1458. $('<li><a id="recentTab" title="Recent Videos" class="active_tooltip" data-original-title="Recent Videos" href="#tabs_playlist_recent" data-toggle="tab" rel="tooltip" data-placement="bottom"><i class="fa fa-clock"></i></a></li>').insertBefore('.video-controls .nav-tabs .skip-controls');
  1459. $('<li><a id="cssMenuTab" title="Custom Layouts" class="active_tooltip" data-original-title="Custom Layouts" href="#tabs_playlist_cssmenu" data-toggle="tab" rel="tooltip" data-placement="bottom"><i class="fa fa-paint-brush"></i></a></li>').insertBefore('.video-controls .nav-tabs .skip-controls');
  1460. $('#create_poll_modal .modal-footer').prepend('<button onclick="$(\'#create_poll_modal .modal-body .input-group input\').val(\'\');" id="clear_poll_options" type="button" class="btn btn-red btn-sm">Clear</button>');
  1461. $('<div class="curtain"><div id="curtainTop"></div><div id="curtainFloor"></div></div>').insertBefore('#media');
  1462. $('.video-controls .nav-tabs').append('<li class="curtainbutton"><i id="toggle_curtain" onclick="script.fns.adjustCurtain();return false;" class="fa fa-curtain active_tooltip" style="display: inline;"></i></li>');
  1463. $('#tabs_playlist_settings').append('<div class="checkbox mod-control"><label class="active_tooltip"><input id="toggle_autoclean_box" type="checkbox" value="Autoclean">Autoclean</label></div>');
  1464. $('#tabs_chat_settings_content').append('<div class="checkbox"><label class="active_tooltip"><input id="toggle_showlogs_box" type="checkbox" value="ShowLogs">Show Join and Leave Logs</label></div>');
  1465. $('#tabs_chat_settings_content').append('<div class="checkbox"><label class="active_tooltip"><input id="toggle_fast_box" type="checkbox" value="Fast">Use :fast: Emote</label></div>');
  1466. $('#tabs_chat_settings_content').append('<div class="checkbox"><label class="active_tooltip"><input id="toggle_spin_box" type="checkbox" value="Spin">Use :spin: Emote</label></div>');
  1467. $('#tabs_chat_settings_content').append('<div class="checkbox"><label class="active_tooltip"><input id="toggle_showadd_box" type="checkbox" value="AddMsgs">Show Video Add Messages in Chat</label></div>');
  1468. $('#tabs_chat_settings_content').append('<div class="checkbox"><label class="active_tooltip"><input id="toggle_showroll_box" type="checkbox" value="ShowRoll">Show $roll/$8ball Results in Chat</label></div>');
  1469. $('#tabs_chat_settings_content').append('<div class="checkbox"><label class="active_tooltip"><input id="toggle_useemotes_box" type="checkbox" value="UseEmotes">Use Emotes</label></div>');
  1470. $('#tabs_chat_settings_content').append('<div class="checkbox"><label class="active_tooltip"><input id="toggle_navbar_box" type="checkbox" value="FixedNavbar">Fixed Navbar</label></div>');
  1471. $('#tabs_chat_settings_content').append('<div class="fastspeedbox"><label class="active_tooltip"><input id="marqueeinput" style="color:black" size="3" type="text" max="999" maxlength="3" onkeyup="script.fns.setFast($(this).val());return false;"> :fast: Scroll Speed <span style="color: #c00">(max 999)</span></label></div>');
  1472. $('#tabs_chat_settings_content').append('<button id="resetsettings_btn" class="btn btn-xs btn-red">Reset Script Preferences</button>');
  1473. /*$('#tabs_playlist_settings').append('<div class="recentmaxbox"><label class="active_tooltip"><input id="recentsinput" size="3" type="text" max="999" maxlength="3" onkeyup="script.fns.set("maxRecents", $(this).val());return false;"> Maximum Recent Videos <span style="color: #c00">(max 999)</span></label></div>');
  1474. $('#recentsinput').val(script.fns.get("maxRecents"));*/
  1475. for (var i in script.cssLinks) {
  1476. var html = '<div class="radio"><label class="active_tooltip"><input data-css-name="' + i + '" id="css-' + i + '" type="radio" name="customcss" onclick="script.fns.setCustomLayout($(this).attr(\'data-css-name\'));">' + script.cssLinks[i][0] + '<span class="author">' + script.cssLinks[i][1] + '</span></label></div>';
  1477. $('#layout_list').append(html);
  1478. }
  1479. }
  1480. };
  1481.  
  1482. window.script.pretasks = [script.overwriteFunctions, script.setCSS];
  1483. window.script.tasks = [script.setHTML, script.setListeners, script.fns.gmtClock];
  1484. window.script.delayedTasks = [script.fns.initializeSettings, script.fns.setChecks, script.fns.buildEmotes];
  1485. //firefox has issues with emotes...
  1486.  
  1487. window.room.onConnecting = function () {
  1488. room.addMessage({username:""},"Connecting..","text-danger");
  1489. if (!window.script.loaded) script.fns.load();
  1490. }