Soundcloud:Sort comments by timestamp

Sort comments by timestamp on Soundcloud

  1. // ==UserScript==
  2. // @name Soundcloud:Sort comments by timestamp
  3. // @description Sort comments by timestamp on Soundcloud
  4. // @include *soundcloud.com/*
  5. // @grant none
  6. // @namespace https://greatest.deepsurf.us/users/4252
  7. // @version 0.0.1.20180417234419
  8. // ==/UserScript==
  9. //Note: Only been tested in firefox
  10. var SortButton = document.createElement("button");
  11. SortButton.type = "button";
  12. SortButton.className = "sc-button sc-button-medium sc-button-responsive";
  13. SortButton.innerHTML = "Sort by timestamp";
  14. SortButton.onclick = sortComments;
  15.  
  16. var CancelScrollButton = document.createElement("button");
  17. CancelScrollButton.type = "button";
  18. CancelScrollButton.className = "sc-button sc-button-medium sc-button-responsive";
  19. CancelScrollButton.innerHTML = "Cancel scrolling";
  20. CancelScrollButton.onclick = cancelLoadingComments;
  21.  
  22. var CancelScrollDiv = document.createElement("div");
  23. CancelScrollDiv.style = "display:none; position: fixed; bottom: 0; left: 0; right: 0; height: 80px; text-align:center;";
  24. CancelScrollDiv.appendChild(CancelScrollButton);
  25.  
  26.  
  27. (function() {//when page loads, add the buttons
  28. XMLHttpRequest.prototype.__open = XMLHttpRequest.prototype.open;
  29. XMLHttpRequest.prototype.open = function() {
  30. this.addEventListener('load', function() {
  31. if(this.readyState !== 4) return;
  32. if(this.status !== 200) return;
  33. if(/\/(tracks)/.test(this.responseURL)) {
  34. appendButtons();
  35. }
  36. });
  37. XMLHttpRequest.prototype.__open.apply(this, arguments);
  38. };
  39. })();
  40.  
  41. function appendButtons() {
  42. if (document.getElementsByClassName("commentsList__title").length && !document.getElementsByClassName("sort-button")[0]) {//if comment header exists and sort button hasn't already been added
  43. document.getElementsByClassName("commentsList__title")[0].appendChild(SortButton);
  44. }
  45. if (!document.body.contains(CancelScrollDiv)) {//if cancel scroll button hasn't already been added
  46. document.body.appendChild(CancelScrollDiv);
  47. }
  48. }
  49.  
  50. function loadComments(){
  51. CancelScrollDiv.style.display = "block";
  52. window.myInterval = setInterval(function(){
  53. window.scrollTo(0,document.body.scrollHeight);
  54. if(document.getElementsByClassName("paging-eof").length){
  55. cancelLoadingComments();
  56. sortComments();
  57. window.scrollTo(0,0);
  58. }
  59. }, 500);
  60. }
  61.  
  62. function cancelLoadingComments(){
  63. clearInterval(myInterval);
  64. CancelScrollDiv.style.display = "none";
  65. }
  66.  
  67. function sortComments() {
  68. if (document.getElementsByClassName("paging-eof").length === 0) {
  69. if (window.confirm("All comments must be loaded before sorting. Auto scroll to load?")) {
  70. loadComments();
  71. }
  72. return;
  73. }
  74.  
  75. var commentContainer = document.getElementsByClassName("lazyLoadingList__list")[0];
  76. var allcomments = [].slice.call(commentContainer.children);
  77. var k = 0.001; //decimal to stick at end of timestamp so that threads (replies) stay together
  78. for (i = 0; i < allcomments.length; i++) {
  79. if (allcomments[i].firstChild.classList.contains("isReply")) {
  80. allcomments[i].setAttribute("data-timestamp4sort", getTimestampInSeconds(allcomments[i]) + k);
  81. k = k + 0.001; //theoretically correctly sort 1000 consecutive replies
  82. } else {
  83. allcomments[i].setAttribute("data-timestamp4sort", getTimestampInSeconds(allcomments[i]));
  84. k = 0.001; //reset
  85. }
  86. }
  87.  
  88. allcomments.sort(compare);
  89.  
  90. while (commentContainer.lastChild) {
  91. commentContainer.removeChild(commentContainer.lastChild);
  92. }
  93.  
  94. var docFrag = document.createDocumentFragment();
  95. for (i = 0; i < allcomments.length; i++) {
  96. docFrag.appendChild(allcomments[i]);
  97. }
  98. commentContainer.appendChild(docFrag);
  99.  
  100. alert("Comments sorted successfully");
  101. }
  102.  
  103.  
  104. function compare(a, b) {
  105. var avalue = parseFloat(a.getAttribute("data-timestamp4sort"));
  106. var bvalue = parseFloat(b.getAttribute("data-timestamp4sort"));
  107. if (avalue < bvalue)
  108. return -1;
  109. if (avalue > bvalue)
  110. return 1;
  111. return 0;
  112. }
  113.  
  114. function hmsToSecondsOnly(str) { //This function handles "HH:MM:SS" as well as "MM:SS" or "SS".
  115. var p = str.split(':'),
  116. s = 0,
  117. m = 1;
  118.  
  119. while (p.length > 0) {
  120. s += m * parseInt(p.pop(), 10);
  121. m *= 60;
  122. }
  123.  
  124. return s;
  125. }
  126.  
  127. function getTimestampInSeconds(licomment) { //takes the <li> element of a comment. returns an integer
  128. if (licomment.getElementsByClassName("commentItem__timestampLink").length !== 0) {
  129. return hmsToSecondsOnly(licomment.getElementsByClassName("commentItem__timestampLink")[0].innerHTML);
  130. } else {
  131. return 0;
  132. }
  133. }