AO3: [Wrangling] When did I last wrangle?

turns the last wrangled date into a "X days ago" message, and highlights it if more than 10 days ago

当前为 2023-06-11 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name AO3: [Wrangling] When did I last wrangle?
  3. // @namespace https://greasyfork.org/en/users/906106-escctrl
  4. // @description turns the last wrangled date into a "X days ago" message, and highlights it if more than 10 days ago
  5. // @author escctrl
  6. // @version 1.0
  7. // @match *://*.archiveofourown.org/tag_wranglers/*
  8. // @license MIT
  9. // ==/UserScript==
  10.  
  11. (function() {
  12. 'use strict';
  13.  
  14. const last = document.getElementById('user-page').querySelector("span.datetime");
  15.  
  16. // skip this script if we're not looking at our own wrangling page where no date is displayed
  17. if (!last) return;
  18.  
  19. const t = last.children;
  20.  
  21. // hide the <p> containing the last wrangled time, and the intro sentence about assigned fandoms. hopefully this doesn't clash with other scripts
  22. last.parentElement.style.display = 'none';
  23. document.getElementById('user-page').querySelector('.assigned p:first-of-type').style.display = 'none';
  24.  
  25. var n = document.createElement('span');
  26. n.id = 'lastwrangled';
  27. n.style.fontSize = 'smaller';
  28. n.title = last.innerText.replace(/\s{2,}/g, ' ');
  29.  
  30. document.querySelector('head').innerHTML += `<style type="text/css">
  31. #lastwrangled { font-size: 0.7em; padding-left: 1em; }
  32. #lastwrangled span { position: relative; z-index: 1; color: white; }
  33. #lastwrangled .good::before, #lastwrangled .late::before {content: ""; position: absolute; width: calc(100% + 4px); height: 115%; right: -2px; bottom: -2px; z-index: -1; transform: rotate(-3deg); }
  34. #lastwrangled .good::before { background-color: #a4a4a4; }
  35. #lastwrangled .late::before { background-color: #e62b2b; }
  36. </style>`;
  37.  
  38. // fixing the months (from text to integer representation)
  39. const months = { 'Jan': '01', 'Feb': '02', 'Mar': '03', 'Apr': '04', 'May': '05', 'Jun': '06', 'Jul': '07', 'Aug': '08', 'Sep': '09', 'Oct': '10', 'Nov': '11', 'Dec': '12' };
  40. var month = months[t[2].innerText];
  41.  
  42. // fixing the time (from 12-hour to 24-hour, e.g. 2am -> 2 -> 02:xx, 4pm -> 16 -> 16:xx, 12am -> 12-12 = 00:xx, 12pm -> 24-12 = 12:xx
  43. var time = t[4].innerText.match(/(\d*):(\d*)(AM|PM)/i);
  44. var hour = time[3] == 'PM' ? parseInt(time[1])+12 : parseInt(time[1]);
  45. if (hour == 12 || hour == 24) hour = hour-12;
  46. time = hour.toString().padStart(2, '0') + ':' + time[2];
  47.  
  48. // switching timezone name from Ruby to UTC offset that JS understands
  49. // several timezones are output as an offset only. Plenty of timezones are missing, those are in comments (can be added if I missed one or they are supported later)
  50. // cities are listed where the TZ acronym is ambiguous
  51. const zones = new Object({
  52. '-12:00': ['-12'],
  53. '-11:00': ['-11', 'SST'], //'NUT'
  54. '-10:00': ['-10', 'HST'], //'TAHT', 'CKT'
  55. //'-09:30': ['MART'],
  56. '-09:00': ['-09', 'HDT', 'AKST'], //'GAMT'
  57. '-08:00': ['-08', 'AKDT', 'PST'],
  58. '-07:00': ['-07', 'PDT', 'MST'],
  59. '-06:00': ['-06', 'MDT', 'Central Time (US & Canada)', 'Central America', 'Chihuahua', 'Guadalajara', 'Mexico City', 'Monterrey', 'Saskatchewan'], //'EAST', 'GALT'
  60. '-05:00': ['-05', 'CDT', 'EST'], //'ECT', 'ACT', 'CIST', 'COT', 'CST', 'EASST', 'PET'
  61. '-04:00': ['-04', 'EDT', 'AST'], //'AMT', 'BOT', 'CDT', 'CIDST', 'CLT', 'FKT', 'GYT', 'PYT','VET'
  62. '-03:30': ['NST'],
  63. '-03:00': ['-03', 'ADT'], //'BRT', 'AMST', 'ART', 'CLST', 'FKST', 'GFT', 'P', 'PMST', 'PYST', 'ROTT', 'SRT', 'UYT', 'WARST', 'WGT'
  64. '-02:30': ['NDT'],
  65. '-02:00': ['-02'], //'BRST', 'GST', 'FNT', 'PMDT', 'UYST', 'WGST'
  66. '-01:00': ['-01'], //'CVT', 'AZOT', 'EGT'
  67. '+00:00': ['+00', 'UTC', 'GMT', 'WET'], //'WT', 'AZOST', 'EGST'
  68. '+01:00': ['+01', 'BST', 'WEST', 'CET', 'Dublin'], // 'WAT', 'WST'
  69. '+02:00': ['+02', 'CEST', 'EET', 'CAT', 'SAST', 'Jerusalem'],
  70. '+03:00': ['+03', 'EEST', 'IDT', 'MSK', 'EAT'], // 'AST', 'FET', 'SYOT', 'TRT'
  71. '+03:30': ['+0330'], // 'IRST'
  72. '+04:00': ['+04'], //'GST', 'AMT', 'AZT', 'D', 'GET', 'KUYT', 'MSD', 'MUT', 'RET', 'SAMT', 'SCT'
  73. '+04:30': ['+0430'], //'IRDT', 'AFT'
  74. '+05:00': ['+05', 'PKT'], //'AMST', 'AQTT', 'AZST', 'E', 'MAWT', 'MVT', 'ORAT', 'TFT', 'TJT', 'TMT', 'UZT', 'YEKT'
  75. '+05:30': ['+0530', 'Chennai', 'Kolkata', 'Mumbai', 'New Delhi'],
  76. '+05:45': ['+0545'], // 'NPT'
  77. '+06:00': ['+06'], //'ALMT', 'BST', 'BTT', 'IOT', 'KGT', 'OMST', 'QYZT', 'VOST', 'YEKST'
  78. '+06:30': ['+0630'], //'MMT', 'CCT'
  79. '+07:00': ['+07', 'WIB'], //'KRAT', 'CXT', 'DAVT', 'HOVT', 'ICT', 'NOVST', 'NOVT', 'OMSST'
  80. '+08:00': ['+08', 'Beijing', 'Chongqing', 'Taipei', 'HKT', 'AWST'], //'ULAT', 'BNT', 'CAST', 'CHOT', 'HOVST', 'IRKT', 'KRAST', 'MYT', 'PHT', 'SGT', 'WITA'
  81. //'+08:45': [], //'ACWST'
  82. '+09:00': ['+09', 'JST', 'KST'], //'CHOST', 'IRKST', 'PWT', 'TLT', 'ULAST', 'WIT'
  83. '+09:30': ['ACST'],
  84. '+10:00': ['+10', 'AEST', 'ChST'], //'CHUT', 'DDUT', 'K', 'PGT', 'VLAT', 'YAKST', 'YAPT'
  85. '+10:30': ['ACDT'], //'LHDT'
  86. '+11:00': ['+11', 'AEDT'], //'SRET', 'BST', 'KOST', 'L', 'LHDT', 'MAGT', 'NCT', 'NFT', 'PONT', 'SAKT', 'SBT', 'VLAST', 'VUT'
  87. '+12:00': ['+12', 'NZST'], //'ANAT', 'ANAST', 'FJT', 'GILT', 'M', 'MAGST', 'MHT', 'NFDT', 'NRT', 'PETST', 'PETT', 'TVT', 'WAKT', 'WFT'
  88. '+12:45': ['+1245'], //'CHAST'
  89. '+13:00': ['+13', 'NZDT'], //'TKT', 'FJST', 'PHOT', 'TOT', 'WST'
  90. '+13:45': ['+1345'], //'CHADT'
  91. '+14:00': ['+14'] //'TOST', 'LINT'
  92. });
  93. var offset = '';
  94. for (let [key, value] of Object.entries(zones)) {
  95. // Ao3 only offers the city to distinguish ambiguous acronyms. Thankfully the limited TZ set in Preferences only has that problem with IST and CST.
  96. if ((t[5].innerText == 'IST' && value.includes(t[5].title)) ||
  97. (t[5].innerText == 'CST' && value.includes(t[5].title)) ||
  98. (value.includes(t[5].innerText))) {
  99. offset = key;
  100. }
  101. // fallback in case I missed a timezone. day count could be off by a day, but better than nothing
  102. else offset = '+00:00';
  103. }
  104.  
  105. // translate last wrangled time into JS object with which we can do math
  106. const mytime = new Date(`${t[3].innerText}-${month}-${t[1].innerText}T${time}${offset}`);
  107.  
  108. const countfandoms = document.getElementById('user-page').querySelectorAll('.assigned table tbody tr').length;
  109.  
  110. // diff between now and last wrangled, turned from milliseconds into days, rounded to closest full number
  111. const indays = Math.round((new Date() - mytime) / (1000 * 3600 * 24));
  112. n.innerHTML = " (it's been <span>"+ indays + ((indays == 1) ? " day" : " days") +"</span> since you last wrangled a tag in your "+ countfandoms +" fandoms)";
  113.  
  114. // if more than 10 days ago, highlight!
  115. n.children[0].className = (indays > 10) ? 'late' : 'good';
  116.  
  117. document.querySelector('.assigned h3').appendChild(n);
  118.  
  119. })();