AO3: Get Current Chapter Word Count

Counts and displays the number of words in the current chapter

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

  1. // ==UserScript==
  2. // @name AO3: Get Current Chapter Word Count
  3. // @namespace https://github.com/w4tchdoge
  4. // @version 1.1.2-20240405_035735
  5. // @description Counts and displays the number of words in the current chapter
  6. // @author w4tchdoge
  7. // @homepage https://github.com/w4tchdoge/MISC-UserScripts
  8. // @match *://archiveofourown.org/*works/*
  9. // @exclude *://archiveofourown.org/*works/*/bookmarks
  10. // @icon https://archiveofourown.org/favicon.ico
  11. // @license AGPL-3.0-or-later
  12. // @history 1.1.2 — Switch to using Intl.NumberFormat for making the word count thousands separated
  13. // @history 1.1.1 — Modify the match rule so that it matches collections/*/works URLs as well; Add an exlude role so it doesn't work on works/*/bookmarks pages as it isn't designed to
  14. // @history 1.1.0 — Implement a counting method that uses an attempted conversion of the Ruby regex code used by AO3 to JavaScript
  15. // ==/UserScript==
  16.  
  17. (function () {
  18. 'use strict';
  19.  
  20. // Save current page URL to a var
  21. const currPG_URL = window.location.href;
  22.  
  23. // Execute script only on multi-chapter works AND only when a single chapter is being viewed
  24. if (currPG_URL.includes('works') && currPG_URL.includes('chapters')) {
  25.  
  26. // Attempted conversion of the Ruby regex code AO3 uses to JavaScript by looking at:
  27. // https://github.com/otwcode/otwarchive/blob/943f585818005be8df269d84ca454af478150e75/config/config.yml#L453
  28. // https://github.com/otwcode/otwarchive/blob/943f585818005be8df269d84ca454af478150e75/lib/word_counter.rb#L26
  29. // https://github.com/otwcode/otwarchive/blob/943f585818005be8df269d84ca454af478150e75/lib/word_counter.rb#L30C9-L31C95
  30. // Has not been tested on non-English works, feedback would be appreciated
  31. const word_count_regex = /\p{Script=Han}|\p{Script=Hiragana}|\p{Script=Katakana}|\p{Script=Thai}|((?!\p{Script=Han}|\p{Script=Hiragana}|\p{Script=Katakana}|\p{Script=Thai})\w)+/gu;
  32.  
  33.  
  34. // Get the HTML element containing the chapter's text content
  35. var text_node = document.querySelector('[role="article"]');
  36.  
  37. // Extract the text content from the HTML element
  38. var text = text_node.innerText.replace(/chapter text\n\n/gmi, '');
  39.  
  40. // Count the number of words
  41. // Counting method from:
  42. // https://stackoverflow.com/a/76673564/11750206
  43. // Regex substitutions from:
  44. // https://github.com/otwcode/otwarchive/blob/943f585818005be8df269d84ca454af478150e75/lib/word_counter.rb#L30C33-L30C68
  45. var word_count = [...text.replaceAll(/--/g, '—').replaceAll(/['’‘-]/g, '').matchAll(word_count_regex)].length;
  46.  
  47. // Format the integer number to a thousands separated string
  48. // Reference for Intl.NumberFormat: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/NumberFormat
  49. word_count = new Intl.NumberFormat({ style: "decimal" }).format(word_count);
  50.  
  51. // Code for Debugging
  52. // console.log(`Chapter Text:\n${text}\n\n`);
  53. console.log(`Word Count: ${word_count} words`);
  54.  
  55. // Create element with the text "Words in Chapter"
  56. var chap_word_count_text = Object.assign(document.createElement('dt'), {
  57. id: 'chapter_words_text',
  58. className: 'chapter_words',
  59. innerText: 'Words in Chapter:'
  60. });
  61.  
  62. // Create element with the word count of the chapter
  63. var chap_word_count_num = Object.assign(document.createElement('dd'), {
  64. id: 'chapter_words_num',
  65. className: 'chapter_words',
  66. innerText: word_count
  67. });
  68.  
  69. // Get the element where the stats are displayed
  70. const stats_elem = document.querySelector('#main dl.work.meta.group dl.stats');
  71.  
  72. // Append the created elements after the element containing the total word count of the fic
  73. stats_elem.querySelector('dd.words').after(chap_word_count_text, chap_word_count_num);
  74. }
  75. })();