diff --git a/README.md b/README.md index b664519..5cc1f28 100644 --- a/README.md +++ b/README.md @@ -28,9 +28,9 @@ This project requires you to install the latestst versions of [Node.js](https:// Minimum required versions: | Tool | Version | |-|-| -| node.js | => 12.18.x | -| npm | => 6.14.x | -| gulp | => 4.0.x | +| node.js | ^14.x.x | +| npm | ^6.x.x | +| gulp | ^4.x.x | ### Build diff --git a/package.json b/package.json index 370d7f0..d4751f6 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "aniwatch-plus", - "version": "0.2.1-beta.0", + "version": "0.3.0-beta", "description": "Aniwatch Plus is a browser extension for https://aniwatch.me/", "main": "index.js", "scripts": { diff --git a/src/javascript/enhancements/anilyr.js b/src/javascript/enhancements/anilyr.js new file mode 100644 index 0000000..f80ebd8 --- /dev/null +++ b/src/javascript/enhancements/anilyr.js @@ -0,0 +1,48 @@ +import * as core from '../utils/aniwatchCore'; +import * as helper from '../utils/helpers'; + +const SCREENSHOT_TOOLTIP_ID = 'anilyr-screenshots-tooltip'; +const PLAYER_ID = 'player'; + +export function init() { + core.registerScript(node => { + if (helper.isHtmlElement(node) && node.id === SCREENSHOT_TOOLTIP_ID) { + observeScreenshotTooltip(node); + } + }, "^/anime/[0-9]*/[0-9]*$"); +} + +function observeScreenshotTooltip(tooltip) { + let observer = new MutationObserver(mutations => { + mutations.forEach(mutation => { + // Switched to invisible + if (!mutation.oldValue.includes('display: none') && mutation.target.style.display == 'none') { + let player = findPlayer(); + if(typeof player !== 'undefined'){ + resumePlayer(player); + } + } + }); + }); + + observer.observe(tooltip, { + attributes: true, + attributeOldValue: true, + attributeFilter: ['style'], + }); +} + +function findPlayer() { + const PLAYER_TAG_NAME = 'VIDEO'; // tagName gives UpperCase + + let playerCandidate = document.getElementById(PLAYER_ID); + if (playerCandidate.tagName === PLAYER_TAG_NAME) { + return playerCandidate; + } + + return undefined; +} + +function resumePlayer(player) { + player.play(); +} \ No newline at end of file diff --git a/src/javascript/enhancements/notifications.js b/src/javascript/enhancements/notifications.js new file mode 100644 index 0000000..e97e530 --- /dev/null +++ b/src/javascript/enhancements/notifications.js @@ -0,0 +1,33 @@ +import * as core from '../utils/aniwatchCore'; +import * as helper from '../utils/helpers'; + +export function init() { + core.runAfterLoad(() => { + updateNotificationsInTitle(); + }, ".*"); + + core.runAfterLocationChange(() => { + updateNotificationsInTitle(); + }, ".*"); +} + +function getNotificationCount() { + if (core.isLoggedIn()) { + let menuUserText = document.getElementById('materialize-menu-dropdown').innerText.split('\n')[4]; + let notificationCount = menuUserText.match(/\d+/)?.[0] ?? 0; + return notificationCount; + } else { + return 0; + } +} + +function updateNotificationsInTitle() { + let count = getNotificationCount(); + + if (helper.assigned(count) && count > 0) { + // document.title is updated after the event is triggered, so we delay our title update by a reasonable time + setTimeout(() => { + document.title = `(${count}) ${document.title}`; + }, 100); + } +} \ No newline at end of file diff --git a/src/javascript/index.js b/src/javascript/index.js index f09fe58..d1e9a7e 100644 --- a/src/javascript/index.js +++ b/src/javascript/index.js @@ -3,8 +3,10 @@ import { initCore } from './utils/aniwatchCore'; // helper import { initHelpers } from './utils/helpers'; // enhancements +import { init as anilyr } from './enhancements/anilyr'; import { init as animeRequests } from './enhancements/animeRequests'; import { init as languageDisplay } from './enhancements/languageDisplay'; +import { init as notifications } from './enhancements/notifications'; import { init as quickSearch } from './enhancements/quickSearch'; import { init as watch2getherChat } from './enhancements/watch2getherChat'; @@ -15,7 +17,8 @@ initCore(); initHelpers(); // enhancements +anilyr(); animeRequests(); languageDisplay(); -quickSearch(); +notifications();quickSearch(); watch2getherChat(); \ No newline at end of file diff --git a/src/javascript/utils/aniwatchCore.js b/src/javascript/utils/aniwatchCore.js index abe5afa..db6c599 100644 --- a/src/javascript/utils/aniwatchCore.js +++ b/src/javascript/utils/aniwatchCore.js @@ -1,7 +1,9 @@ import * as helper from './helpers'; +/* SCRIPT LOGICS */ let __scripts = []; let __afterLoadScripts = []; +let __afterLocationChangeScripts = []; export function initCore() { let observer = new MutationObserver(mutations => { @@ -18,6 +20,29 @@ export function initCore() { attributes: true }); + runAfterLoad(() => { + let loadingBar = document.getElementById('enable-ani-cm'); + let loadingBarObserver = new MutationObserver(mutations => { + mutations.forEach(mutation => { + // enable-ani-cm node changes from display:none to display:block after loading + if (mutation.oldValue.includes('display: none')) { + __afterLocationChangeScripts.forEach(script => { + if (window.location.pathname.match(script.pattern)) { + script.function(); + } + }); + } + }) + }); + + loadingBarObserver.observe(loadingBar, { + attributes: true, + attributeOldValue: true, + attributeFilter: ['style'], + }); + + }, '.*') + helper.onReady(() => awaitPageLoaded()); } @@ -63,10 +88,30 @@ function awaitPageLoaded() { } let loop = setInterval(() => { - if (preLoader.style.display === "none") { + if (preLoader.style.display === "none" && document.readyState === 'complete') { clearInterval(loop); runScripts(); } }, 100); +} + +/* PATHNAME LOGIC */ +export function runAfterLocationChange(func, pattern = '.*') { + __afterLocationChangeScripts.push({ "function": func, "pattern": pattern }); +} + +/* LOGIN LOGIC */ +export function isLoggedIn() { + let menu = document.getElementById('materialize-menu-dropdown'); + let result = true; + + menu.innerText.split('\n').forEach(item => { + if (item === 'Login') { + result = false; + return; + } + }); + + return result; } \ No newline at end of file diff --git a/src/javascript/utils/helpers.js b/src/javascript/utils/helpers.js index a52968e..053aa18 100644 --- a/src/javascript/utils/helpers.js +++ b/src/javascript/utils/helpers.js @@ -18,6 +18,10 @@ export function onReady(fn) { } } +export function assigned(obj) { + return !(typeof obj === 'undefined' || obj === null); +} + function handleKeyDown(event) { handleKeyToggle(event, true); } diff --git a/src/manifests/manifest.template.json b/src/manifests/manifest.template.json index ba1031b..f2d1e2a 100644 --- a/src/manifests/manifest.template.json +++ b/src/manifests/manifest.template.json @@ -1,8 +1,8 @@ { "name": "Aniwatch Plus", "short_name": "AW+", - "version": "0.2.1.0", - "version_name": "0.2.1 Beta", + "version": "0.3.0.0", + "version_name": "0.3.0 Beta", "description": "Aniwatch Plus is an unofficial extension which provides several UI improvments for https://aniwatch.me.", "permissions": [ "*://aniwatch.me/*" diff --git a/src/stylesheets/aniwatchplus.scss b/src/stylesheets/aniwatchplus.scss index 0fcd7c1..67a2367 100644 --- a/src/stylesheets/aniwatchplus.scss +++ b/src/stylesheets/aniwatchplus.scss @@ -3,4 +3,5 @@ // enhancements @import './enhancements/lists'; -@import './enhancements/watch2gether' \ No newline at end of file +@import './enhancements/tabs'; +@import './enhancements/watch2gether'; \ No newline at end of file diff --git a/src/stylesheets/enhancements/_tabs.scss b/src/stylesheets/enhancements/_tabs.scss new file mode 100644 index 0000000..0bcc731 --- /dev/null +++ b/src/stylesheets/enhancements/_tabs.scss @@ -0,0 +1,7 @@ +md-tab-item{ + + // hide disabled tabs + &.md-disabled { + display: none; + } +} \ No newline at end of file diff --git a/src/stylesheets/enhancements/_watch2gether.scss b/src/stylesheets/enhancements/_watch2gether.scss index 731dc5e..c5d5ed5 100644 --- a/src/stylesheets/enhancements/_watch2gether.scss +++ b/src/stylesheets/enhancements/_watch2gether.scss @@ -1,3 +1,9 @@ +.material-icons { + // Fix icon position for room creator + &[aria-label="Room creator"] { + vertical-align: text-top; + } +} .awp { &-w2g { &-chatCounter {