theYNC.com Underground bypass

Watch theYNC Underground videos without needing an account

当前为 2024-12-24 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name theYNC.com Underground bypass
  3. // @description Watch theYNC Underground videos without needing an account
  4. // @require https://update.greasyfork.org/scripts/421384/1134973/GM_fetch.js
  5. // @namespace Violentmonkey Scripts
  6. // @match *://*.theync.com/*
  7. // @match *://theync.com/*
  8. // @match *://*.theync.net/*
  9. // @match *://theync.net/*
  10. // @match *://*.theync.com/*
  11. // @match *://theync.com/*
  12. // @grant GM_xmlhttpRequest
  13. // @connect media.theync.com
  14. // @version 2.4
  15. // @license MIT
  16. // @author -
  17. // ==/UserScript==
  18.  
  19. function getTheYNCVideoURLFromThumbnail(url) {
  20. for (const [, group_url] of url.matchAll(
  21. /^https?:\/\/theync\.(?:com|org|net)\/media\/thumbs\/(.*?)\.[a-zA-Z0-9_.-]*/gm
  22. )) {
  23. return `https://media.theync.com/videos/${group_url}.mp4`;
  24. }
  25. }
  26. function waitForElement(selector) {
  27. return new Promise((resolve) => {
  28. {
  29. const element = document.querySelector(selector);
  30. if (element) {
  31. return resolve(element);
  32. }
  33. }
  34.  
  35. const observer = new MutationObserver(() => {
  36. const element = document.querySelector(selector);
  37. if (element) {
  38. observer.disconnect();
  39. resolve(element);
  40. }
  41. });
  42.  
  43. // If you get 'parameter 1 is not of type 'Node'' error, see https://stackoverflow.com/a/77855838/492336
  44. observer.observe(document.body, {
  45. childList: true,
  46. subtree: true,
  47. });
  48. });
  49. }
  50.  
  51. waitForElement('.content-block').then((contentBlock) => {
  52. for (const element of contentBlock.querySelectorAll(
  53. '.upgrade-profile > .upgrade-info-block'
  54. )) {
  55. const thumbnailURL = element.querySelector(
  56. '.image-block > .image > img'
  57. ).src;
  58. if (!thumbnailURL) continue;
  59. const videoURL = getTheYNCVideoURLFromThumbnail(thumbnailURL);
  60. if (!videoURL) continue;
  61. GM_fetch(videoURL, { method: 'HEAD' }).then((response) => {
  62. if (response.status !== 200) {
  63. return;
  64. }
  65. location.href = videoURL;
  66. });
  67.  
  68. return;
  69. }
  70. for (const element of contentBlock.querySelectorAll('.inner-block > a')) {
  71. const undergroundLogo = element.querySelector('.item-info > .border-gold');
  72. if (!undergroundLogo) continue;
  73.  
  74. const thumbnailURL = element.querySelector('.image > img').src;
  75. if (!thumbnailURL) continue;
  76. const videoURL = getTheYNCVideoURLFromThumbnail(thumbnailURL);
  77. if (!videoURL) continue;
  78.  
  79. GM_fetch(videoURL, { method: 'HEAD' }).then((response) => {
  80. if (response.status === 200) {
  81. undergroundLogo.textContent = 'BYPASSED';
  82. undergroundLogo.style.backgroundColor = 'green';
  83. element.href = videoURL;
  84. return;
  85. }
  86. GM_fetch(`https://archive.org/wayback/available?url=${element.href}`, {
  87. method: 'GET',
  88. })
  89. .then((response) => response.json())
  90. .then(({ archived_snapshots }) => {
  91. if (!archived_snapshots.closest) {
  92. return;
  93. }
  94. undergroundLogo.textContent = 'ARCHIVED';
  95. undergroundLogo.style.backgroundColor = 'blue';
  96. element.href = archived_snapshots.closest.url;
  97. });
  98. });
  99. }
  100. });