New
May 13, 2023 6:34 AM
#1
MyAiringList - a new web app using the MAL API MyAiringList is a weekly calendar that reads your airing anime in your list and print them day by day plus some information. Features in the current version:
My own calendar sample: This was actually a project for personal use, but if someone want to use it, you can give me some feedback! |
MorteuxMar 18, 2024 4:36 AM
MyAiringList - Your currently airing animes in a calendar view. MySeasonalList - Personal stats for your completed anime sorted by seasons. Official Club for MyAiringList and MySeasonalList. |
May 23, 2023 7:47 AM
#2
| I don't really watch seasonals but your site seems helpful for those who do. I know there are sites like LiveChart.me (you can view a general anime timetable without signing up but you may sign up for a personal one) and AniChart (can be connected to your AniList account and there's also a MAL option in the Outgoing Anime Links). Its nice that we can connect our username hence the calendar is personalized. And there's even a dark mode! |
May 23, 2023 12:21 PM
#3
| Nice!, I usually use Taiga.moe for seeing how many episodes I am behind but this could be useful visually, but unfortunately doesn't seem to work for my list atm. |
![]() My Userscripts - Themes - Userstyles - Extensions (Chrome/Firefox) [API CSS] MAL-Scraper-API Cover/CSS Generator |
May 23, 2023 12:48 PM
#4
| It also doesn't work for me at the moment since I'm not watching any airing shows right now. I wish we could still see a calendar even for those in our On-Hold or PTW and not just for those in Currently Watching. Oh, I also just discovered AnimeSchedule and Anime Countdown. |
May 23, 2023 12:50 PM
#5
| This is neat! If you ever want to improve it for others, would be great if you could add an option to convert the time of the episode releases to different timezones |
9cycle |
May 23, 2023 12:51 PM
#6
IridescentJaune said: I don't really watch seasonals but your site seems helpful for those who do. I know there are sites like LiveChart.me (you can view a general anime timetable without signing up but you may sign up for a personal one) and AniChart (can be connected to your AniList account and there's also a MAL option in the Outgoing Anime Links). Its nice that we can connect our username hence the calendar is personalized. And there's even a dark mode! Thank you for your info! Didn't know about LiveChart.me, it looks pretty helpful. (And yes, dark mode was mandatory in my todo list! xD) ShaggyZE said: Nice!, I usually use Taiga.moe for seeing how many episodes I am behind but this could be useful visually, but unfortunately doesn't seem to work for my list atm. Hello! Thank you for your comment and your feedback! I just fixed the error with your list, so now it works! Feel free to use it: ShaggyZE's Airing List |
MyAiringList - Your currently airing animes in a calendar view. MySeasonalList - Personal stats for your completed anime sorted by seasons. Official Club for MyAiringList and MySeasonalList. |
May 23, 2023 1:07 PM
#7
IridescentJaune said: It also doesn't work for me at the moment since I'm not watching any airing shows right now. I wish we could still see a calendar even for those in our On-Hold or PTW and not just for those in Currently Watching. Actually, this quick fix make it works for you too: https://myairinglist.vercel.app/MyAiringList/IridescentJaune What do you mean by calendar for On-Hold or PTW? Now, the calendar get all your anime in your watching list and for your currently airing animes, it get next episode from Anilist next episode date. That said, how do you think it could show PTW anime? Ty in advanced! Hero_of_My_Story said: This is neat! If you ever want to improve it for others, would be great if you could add an option to convert the time of the episode releases to different timezones It get the next episode airing time from Anilist, I did an automatic timezone conversor and reverted it, because I tested that Anilist returned the correct airing hour. Still I need more testing on this. |
MyAiringList - Your currently airing animes in a calendar view. MySeasonalList - Personal stats for your completed anime sorted by seasons. Official Club for MyAiringList and MySeasonalList. |
May 23, 2023 1:32 PM
#8
Morteux said: What do you mean by calendar for On-Hold or PTW? Now, the calendar get all your anime in your watching list and for your currently airing animes, it get next episode from Anilist next episode date. That said, how do you think it could show PTW anime? Ty in advanced! I just thought MyAiringList is exclusive to the currently airing anime in my Currently Watching (CW) list and that those in my On-Hold or Plan to Watch (PTW) won't appear in my personalized calendar even if they're currently airing. I mean I'm not watching anything airing right now but have some in my On-Hold and PTW and the site isn't showing me anything so I just assumed that. So it's supposed to show me every airing anime in my entire anime list regardless if I marked them as CW, On-Hold or PTW? |
IridescentJauneMay 23, 2023 1:45 PM
May 23, 2023 1:39 PM
#9
IridescentJaune said: Morteux said: What do you mean by calendar for On-Hold or PTW? Now, the calendar get all your anime in your watching list and for your currently airing animes, it get next episode from Anilist next episode date. That said, how do you think it could show PTW anime? Ty in advanced! I just thought MyAiringList is exclusive to the currently airing anime in my Currently Watching (CW) list and that those in my On-Hold or Plant to Watch (PTW) won't appear in my personalized calendar even if they're currently airing. I mean I'm not watching anything airing right now but have some in my On-Hold and PTW and the site isn't showing me anything so I just assumed that. So it's supposed to show me every airing anime in my entire anime list regardless if I marked them as CW, On-Hold or PTW? :O, actually it is a good idea. I will give it a think, it looks easy. I guess it must filter some animes because some people (for example, me :P) has hundred or thousand animes in their PTW list. Very ty for your ideas, I truly appreciate your feedback! |
MyAiringList - Your currently airing animes in a calendar view. MySeasonalList - Personal stats for your completed anime sorted by seasons. Official Club for MyAiringList and MySeasonalList. |
May 23, 2023 2:11 PM
#10
Morteux said: Oooh, now that I checked it, the timers are actually right for my timezone. I didn't notice. Thank you It get the next episode airing time from Anilist, I did an automatic timezone conversor and reverted it, because I tested that Anilist returned the correct airing hour. Still I need more testing on this. |
9cycle |
May 23, 2023 2:28 PM
#11
Jun 3, 2023 7:21 AM
#12
Morteux said: IridescentJaune said: Morteux said: What do you mean by calendar for On-Hold or PTW? Now, the calendar get all your anime in your watching list and for your currently airing animes, it get next episode from Anilist next episode date. That said, how do you think it could show PTW anime? Ty in advanced! I just thought MyAiringList is exclusive to the currently airing anime in my Currently Watching (CW) list and that those in my On-Hold or Plant to Watch (PTW) won't appear in my personalized calendar even if they're currently airing. I mean I'm not watching anything airing right now but have some in my On-Hold and PTW and the site isn't showing me anything so I just assumed that. So it's supposed to show me every airing anime in my entire anime list regardless if I marked them as CW, On-Hold or PTW? :O, actually it is a good idea. I will give it a think, it looks easy. I guess it must filter some animes because some people (for example, me :P) has hundred or thousand animes in their PTW list. Very ty for your ideas, I truly appreciate your feedback! Cool! I tried it again and it's working for me now. Yey! Thanks! I love it! I just added it to my profile page's index. Do you have any plans for a manga counterpart like a MyPublishingList? Something similar to the WEBTOONS daily schedule or calendar for example? Maybe data from MangaUpdates' New Releases section could help? |
IridescentJauneJun 3, 2023 7:37 AM
Jun 3, 2023 1:06 PM
#13
IridescentJaune said: Morteux said: IridescentJaune said: Morteux said: What do you mean by calendar for On-Hold or PTW? Now, the calendar get all your anime in your watching list and for your currently airing animes, it get next episode from Anilist next episode date. That said, how do you think it could show PTW anime? Ty in advanced! I just thought MyAiringList is exclusive to the currently airing anime in my Currently Watching (CW) list and that those in my On-Hold or Plant to Watch (PTW) won't appear in my personalized calendar even if they're currently airing. I mean I'm not watching anything airing right now but have some in my On-Hold and PTW and the site isn't showing me anything so I just assumed that. So it's supposed to show me every airing anime in my entire anime list regardless if I marked them as CW, On-Hold or PTW? :O, actually it is a good idea. I will give it a think, it looks easy. I guess it must filter some animes because some people (for example, me :P) has hundred or thousand animes in their PTW list. Very ty for your ideas, I truly appreciate your feedback! Cool! I tried it again and it's working for me now. Yey! Thanks! I love it! I just added it to my profile page's index. Do you have any plans for a manga counterpart like a MyPublishingList? Something similar to the WEBTOONS daily schedule or calendar for example? Maybe data from MangaUpdates' New Releases section could help? Really appreciate it! In fact, a "MyPublishingList" is quite simple to develop given the actual state of MyAiringList. I am not a big fan of manga, but it's a good idea and it looks pretty simple. Actually, I am thinking on new features for the next MyAiringList version and this could be a good addition. Ty very much for your ideas! |
MyAiringList - Your currently airing animes in a calendar view. MySeasonalList - Personal stats for your completed anime sorted by seasons. Official Club for MyAiringList and MySeasonalList. |
Jun 7, 2023 6:58 AM
#14
Morteux said: This was actually a project for personal use, but if someone want to use it, you can give me some feedback! I've just discovered this and I like it, but it would be better if in addition to the anime I'm watching, I could also watch the anime that are on hold and PTW in a separate section, so I don't mix them up with the ones I'm watching, although thinking about it a bit, it wouldn't be that necessary. What I would like to be able to do is to be able to customize the time zone. I think it uses my PC's time zone (UTC -3), but sometimes I watch anime with friends from other countries like Peru (UTC -5), Portugal (UTC +0/1), Spain (UTC +1/2) Kazakhstan (UTC +5 and +6), Russia (it has a lot of time zones) or Armenia (UTC +4/5). It's complicated to coordinate schedules and being able to customize time zones and add more than one time zone per anime could help me a lot to coordinate anime to watch in a group. |
Jun 7, 2023 11:29 AM
#15
Morteux said: IridescentJaune said: Morteux said: IridescentJaune said: Morteux said: What do you mean by calendar for On-Hold or PTW? Now, the calendar get all your anime in your watching list and for your currently airing animes, it get next episode from Anilist next episode date. That said, how do you think it could show PTW anime? Ty in advanced! I just thought MyAiringList is exclusive to the currently airing anime in my Currently Watching (CW) list and that those in my On-Hold or Plant to Watch (PTW) won't appear in my personalized calendar even if they're currently airing. I mean I'm not watching anything airing right now but have some in my On-Hold and PTW and the site isn't showing me anything so I just assumed that. So it's supposed to show me every airing anime in my entire anime list regardless if I marked them as CW, On-Hold or PTW? :O, actually it is a good idea. I will give it a think, it looks easy. I guess it must filter some animes because some people (for example, me :P) has hundred or thousand animes in their PTW list. Very ty for your ideas, I truly appreciate your feedback! Cool! I tried it again and it's working for me now. Yey! Thanks! I love it! I just added it to my profile page's index. Do you have any plans for a manga counterpart like a MyPublishingList? Something similar to the WEBTOONS daily schedule or calendar for example? Maybe data from MangaUpdates' New Releases section could help? Really appreciate it! In fact, a "MyPublishingList" is quite simple to develop given the actual state of MyAiringList. I am not a big fan of manga, but it's a good idea and it looks pretty simple. Actually, I am thinking on new features for the next MyAiringList version and this could be a good addition. Ty very much for your ideas! Excited and looking forward to your future updates. But take your time. 😊 |
Jun 7, 2023 2:18 PM
#16
ANormalUser said: Morteux said: This was actually a project for personal use, but if someone want to use it, you can give me some feedback! I've just discovered this and I like it, but it would be better if in addition to the anime I'm watching, I could also watch the anime that are on hold and PTW in a separate section, so I don't mix them up with the ones I'm watching, although thinking about it a bit, it wouldn't be that necessary. What I would like to be able to do is to be able to customize the time zone. I think it uses my PC's time zone (UTC -3), but sometimes I watch anime with friends from other countries like Peru (UTC -5), Portugal (UTC +0/1), Spain (UTC +1/2) Kazakhstan (UTC +5 and +6), Russia (it has a lot of time zones) or Armenia (UTC +4/5). It's complicated to coordinate schedules and being able to customize time zones and add more than one time zone per anime could help me a lot to coordinate anime to watch in a group. I am already thinking on showing anime airing in PTW/On-Hold and adding some options to show and hide them. But I am not into adding news separate section for non airing at all. Still I am taking my time to think what new to add. For timezones, I have plan to add a list for manually choose any timezone (or directly input a +/- hour counter). There is already an unused feature to change timezones so it just need some adjustment. Ty for your comments! |
MyAiringList - Your currently airing animes in a calendar view. MySeasonalList - Personal stats for your completed anime sorted by seasons. Official Club for MyAiringList and MySeasonalList. |
Jun 7, 2023 6:58 PM
#17
| That is really cool! I'll definitely use it when I start watching seasonal anime |
Jan 13, 2024 6:01 PM
#18
| That's pretty cool! If only there could be notifications on there lol. Anyways, I will refer to this from now on! |
Jan 14, 2024 1:24 AM
#19
| broken....................... |
| Click here to see My Tampermonkey Scripts For MAL If you like my work, please consider supporting it! Cryptos / Patreon / Ko-Fi / BuyMeaCoffee https://cyber-sec0.github.io |
Jan 14, 2024 1:44 AM
#20
Reply to hacker09
broken.......................
| @hacker09 Fixed! :D Your watching list is pretty large haha. Added some checks and it's working now. I hope you enjoy it! |
MyAiringList - Your currently airing animes in a calendar view. MySeasonalList - Personal stats for your completed anime sorted by seasons. Official Club for MyAiringList and MySeasonalList. |
Jan 15, 2024 1:09 PM
#21
Reply to Morteux
@hacker09 Fixed! :D
Your watching list is pretty large haha. Added some checks and it's working now. I hope you enjoy it!
Your watching list is pretty large haha. Added some checks and it's working now. I hope you enjoy it!
| @Morteux Yh that is true, I forgot that many apps have that issue. |
| Click here to see My Tampermonkey Scripts For MAL If you like my work, please consider supporting it! Cryptos / Patreon / Ko-Fi / BuyMeaCoffee https://cyber-sec0.github.io |
Nov 9, 2024 7:52 PM
#22
| Hey I have been using it for a while and it is awesome I really love it, but today the site showed a error/cant use it and probably things only you should be seeing since you are the owner of the site. Just wanted to know if you are still gonna up keep this awesome site. |
IronWolf269Nov 9, 2024 7:58 PM
Nov 10, 2024 2:45 AM
#23
Reply to IronWolf269
Hey I have been using it for a while and it is awesome I really love it, but today the site showed a error/cant use it and probably things only you should be seeing since you are the owner of the site. Just wanted to know if you are still gonna up keep this awesome site.
| @IronWolf269 Hey! I am glad you can enjoy my work! Lately, AniList API is going under maintenance. Since MyAiringList use both MAL and AL APIs, if one of them is down, then MyAiringList can't work properly. You can see those errors because I am little too lazy about properly managing them hahaha. In fact, there are no critical site info that can be gathered from that error screen so it is safe. That said, we just can wait some days until AniList ends their stuff. EDIT: A little update and more info here: https://myanimelist.net/forum/?goto=post&topicid=2158220&id=71966408 |
MorteuxNov 10, 2024 8:01 AM
MyAiringList - Your currently airing animes in a calendar view. MySeasonalList - Personal stats for your completed anime sorted by seasons. Official Club for MyAiringList and MySeasonalList. |
Feb 2, 2025 11:50 AM
#24
| I didn't know there's a club. I just joined. So there's also a MySeasonalList. Cool! I could use the MyAiringList with both my MAL and AL just fine. But I'm getting this message with MAL on MySeasonalList (while AL works fine): This Serverless Function has timed out. Your connection is working correctly. Vercel is working correctly. 504: GATEWAY_TIMEOUT Code: FUNCTION_INVOCATION_TIMEOUT ID: hkg1::n4dt6-1738524632429-84efdb7187cf If you are a visitor, contact the website owner or try again later. If you are the owner, learn how to fix the error and check the logs. |
Feb 2, 2025 3:17 PM
#25
Reply to IridescentJaune
I didn't know there's a club. I just joined. So there's also a MySeasonalList. Cool!
I could use the MyAiringList with both my MAL and AL just fine. But I'm getting this message with MAL on MySeasonalList (while AL works fine):
I could use the MyAiringList with both my MAL and AL just fine. But I'm getting this message with MAL on MySeasonalList (while AL works fine):
This Serverless Function has timed out.
Your connection is working correctly.
Vercel is working correctly.
504: GATEWAY_TIMEOUT Code: FUNCTION_INVOCATION_TIMEOUT ID: hkg1::n4dt6-1738524632429-84efdb7187cf
If you are a visitor, contact the website owner or try again later.
If you are the owner, learn how to fix the error and check the logs.
Your connection is working correctly.
Vercel is working correctly.
504: GATEWAY_TIMEOUT Code: FUNCTION_INVOCATION_TIMEOUT ID: hkg1::n4dt6-1738524632429-84efdb7187cf
If you are a visitor, contact the website owner or try again later.
If you are the owner, learn how to fix the error and check the logs.
| @IridescentJaune Hello! I am glad you like both MyAiringList and MySeasonalList! Already fixed the issue. A bunch of errors stacked because your list is pretty large and unusual. Also, I added a bug report post in the club hahaha. I should give the club a bit of spam! x) Thank you for the bug report. |
MyAiringList - Your currently airing animes in a calendar view. MySeasonalList - Personal stats for your completed anime sorted by seasons. Official Club for MyAiringList and MySeasonalList. |
Feb 2, 2025 3:50 PM
#26
Reply to Morteux
@IridescentJaune Hello! I am glad you like both MyAiringList and MySeasonalList!
Already fixed the issue. A bunch of errors stacked because your list is pretty large and unusual.
Also, I added a bug report post in the club hahaha. I should give the club a bit of spam! x)
Thank you for the bug report.
Already fixed the issue. A bunch of errors stacked because your list is pretty large and unusual.
Also, I added a bug report post in the club hahaha. I should give the club a bit of spam! x)
Thank you for the bug report.
| @Morteux Yeah, a bit large with all the PTW. How unusual? Haha. Welp. 😆 I don't see anything with my list. LOL. So that means I should watch more seasonals when they're airing? Or I can just watch anytime? I don't watch much seasonals but I've completed some so I don't get why mine is empty. Haha. Alright, I'll report there if ever I encounter a bug in the future. |
Feb 2, 2025 10:11 PM
#27
Reply to Morteux
@IridescentJaune Hello! I am glad you like both MyAiringList and MySeasonalList!
Already fixed the issue. A bunch of errors stacked because your list is pretty large and unusual.
Also, I added a bug report post in the club hahaha. I should give the club a bit of spam! x)
Thank you for the bug report.
Already fixed the issue. A bunch of errors stacked because your list is pretty large and unusual.
Also, I added a bug report post in the club hahaha. I should give the club a bit of spam! x)
Thank you for the bug report.
| @Morteux I also had the same issue, but mostly used MyAiringList so never brought it to your attention, however now it does work, but takes upwards of 5 minutes to fully load, assuming due to size of list or the API you are using, not sure if it'll help or be faster but you could try my api as it uses cache's and doesn't rate limit https://shaggyze.website/msa/userlist?u=ShaggyZE |
![]() My Userscripts - Themes - Userstyles - Extensions (Chrome/Firefox) [API CSS] MAL-Scraper-API Cover/CSS Generator |
Feb 3, 2025 1:54 AM
#28
Reply to IridescentJaune
@Morteux Yeah, a bit large with all the PTW. How unusual? Haha.
Welp. 😆 I don't see anything with my list. LOL.
So that means I should watch more seasonals when they're airing? Or I can just watch anytime? I don't watch much seasonals but I've completed some so I don't get why mine is empty. Haha.
Alright, I'll report there if ever I encounter a bug in the future.
Welp. 😆 I don't see anything with my list. LOL.
So that means I should watch more seasonals when they're airing? Or I can just watch anytime? I don't watch much seasonals but I've completed some so I don't get why mine is empty. Haha.
Alright, I'll report there if ever I encounter a bug in the future.
| @IridescentJaune IridescentJaune said: Yeah, a bit large with all the PTW. How unusual? Haha. Previously, MySeasonalList just count until 1960 animes. However, you have some pretty old animes, being the oldest one from 1917 hahaha. Never expected that tbh. IridescentJaune said: Welp. 😆 I don't see anything with my list. LOL. You have the older version cached in your browser. Typically, just use Shift+F5 to reload the website ignoring your cache. IridescentJaune said: So that means I should watch more seasonals when they're airing? Or I can just watch anytime? No. MySeasonalList just read all your completed anime, whenever you complete them. Your personal start and end dates do not matter for all the info and charts. IridescentJaune said: Alright, I'll report there if ever I encounter a bug in the future. You can leave suggestions on the club too :D I will check and implement them if it is an easy work x) |
MyAiringList - Your currently airing animes in a calendar view. MySeasonalList - Personal stats for your completed anime sorted by seasons. Official Club for MyAiringList and MySeasonalList. |
Feb 3, 2025 2:14 AM
#29
Reply to ShaggyZE
@Morteux I also had the same issue, but mostly used MyAiringList so never brought it to your attention, however now it does work, but takes upwards of 5 minutes to fully load, assuming due to size of list or the API you are using, not sure if it'll help or be faster but you could try my api as it uses cache's and doesn't rate limit https://shaggyze.website/msa/userlist?u=ShaggyZE
| @ShaggyZE Hey! Thank you for using MyAiringList! ShaggyZE said: I also had the same issue, but mostly used MyAiringList so never brought it to your attention, however now it does work I am pretty sure now that some of the errors were common for veterans anime watchers. ShaggyZE said: but takes upwards of 5 minutes to fully load Wow, MySeasonalList have some heavy calculations, but 5 minutes? I use the website weekly or monthly and never takes more than 1 minute. I am taking note for this. I have to check it with patience. Thank you anyway, not so much people give feedback about MySeasonalList. ShaggyZE said: not sure if it'll help or be faster but you could try my api as it uses cache's and doesn't rate limit https://shaggyze.website/msa/userlist?u=ShaggyZE Since MAL API is a mess, I have thought in swap both sites to a newer and faster API. However, this would take some time that I don't have now. I have to check this further. But thank you for the suggestions, I am not into alternatives API for MAL API. |
MyAiringList - Your currently airing animes in a calendar view. MySeasonalList - Personal stats for your completed anime sorted by seasons. Official Club for MyAiringList and MySeasonalList. |
Nov 2, 2025 5:37 PM
#30
Due to some like myself loving countdowns just going to plop this down here.
// ==UserScript==
// @name MyAiringList Countdown
// @namespace http://tampermonkey.net/
// @version 1.2
// @description Replaces static airing hours with a live countdown timer showing days, hours, minutes, and seconds until the next episode, with a user-adjustable timezone offset.
// @author Gemini
// @match *://myairinglist.vercel.app/MyAiringList/*
// @grant GM_addStyle
// @grant GM_getValue
// @grant GM_setValue
// @run-at document-idle
// ==/UserScript==
(function() {
'use strict';
// --- CONFIGURATION ---
const DAY_OFFSETS = [1, 2, 3, 4, 5, 6, 0]; // Mon-Sun -> JS Days 1-6, 0
const DAY_NAMES = ['sunday', 'monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday'];
// --- GLOBAL STATE ---
let timezoneOffsetHours = parseFloat(GM_getValue('timezoneOffsetHours', 0));
let isUiSetup = false;
let globalIntervalId = null; // ID for the single central update interval
const activeCountdownElements = new Set(); // Stores all elements that need updating
// --- STYLES ---
GM_addStyle(`
/* The .airing_hour container is now a block to ensure it fills the available space */
.airing_hour {
display: block !important; /* Ensure it behaves like a block element */
width: 100% !important; /* Force it to take full width of its parent */
box-sizing: border-box;
}
/* Countdown Timer Styles (This is the element replacing the time text) */
.countdown-timer {
font-family: 'Inter', sans-serif;
font-weight: 700;
text-align: center;
padding: 2px 0;
color: #d1d5db;
font-size: 16px;
display: block;
min-height: 20px;
text-shadow: 1px 1px 2px rgba(0, 0, 0, 0.5);
transition: color 0.3s ease;
width: 100%; /* Ensure the timer itself takes the full width of the .airing_hour parent */
}
.countdown-timer.airing-soon {
color: #fca5a5;
}
.countdown-timer.airing-now {
color: #34d399;
font-weight: 900;
animation: pulse 1s infinite alternate;
}
.countdown-timer .label {
font-weight: 400;
font-size: 0.65em;
opacity: 0.7;
}
@keyframes pulse {
from { transform: scale(1); opacity: 1; }
to { transform: scale(1.05); opacity: 0.9; }
}
/* Settings UI Styles */
#gm-settings-toggle {
position: fixed;
top: 10px;
right: 10px;
z-index: 10001;
padding: 5px 10px;
background: #3552a1;
color: #fff;
border: none;
border-radius: 4px;
cursor: pointer;
font-size: 14px;
font-weight: 600;
box-shadow: 0 2px 5px rgba(0,0,0,0.3);
}
#gm-countdown-settings {
position: fixed;
top: 50px;
right: 10px;
z-index: 10000;
background: rgba(30, 30, 30, 0.95);
padding: 15px;
border-radius: 8px;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.5);
color: #fff;
font-family: 'Inter', sans-serif;
border: 1px solid #444;
display: none;
/* Added Max Width for better UI control */
max-width: 250px;
min-width: 200px;
}
#gm-countdown-settings.visible {
display: block;
}
`);
// --- CORE LOGIC FUNCTIONS ---
/**
* Attempts to determine the day index of the column containing the element
*/
function getAiringColumnIndex(element) {
let current = element;
while (current.parentElement) {
const parent = current.parentElement;
for (let i = 0; i < DAY_NAMES.length; i++) {
const day = DAY_NAMES[i];
if (parent.classList.contains(`${day}_container`)) {
return (i === 0) ? 6 : i - 1; // Sun -> 6, Mon -> 0, Tue -> 1, etc.
}
}
current = parent;
if (current === document.body) break;
}
return null;
}
/**
* Calculates the next date/time the show airs, applying the user's timezone offset.
*/
function getNextAiringDate(targetDay, timeString) {
const [hours, minutes] = timeString.split(':').map(Number);
if (isNaN(hours) || isNaN(minutes)) return null;
const now = new Date();
const nowDay = now.getDay();
let daysUntil = targetDay - nowDay;
if (daysUntil < 0) daysUntil += 7;
const targetDate = new Date(now.getFullYear(), now.getMonth(), now.getDate() + daysUntil, hours, minutes, 0, 0);
const offsetMilliseconds = timezoneOffsetHours * 60 * 60 * 1000;
targetDate.setTime(targetDate.getTime() + offsetMilliseconds);
// If adjusted time is in the past, move to next week.
if (targetDate.getTime() < now.getTime()) {
targetDate.setDate(targetDate.getDate() + 7);
}
return targetDate;
}
/**
* Logic to update the display for a SINGLE element.
* This function is now called from the global interval.
*/
function updateSingleCountdown(element) {
let distance = element.__targetDate.getTime() - new Date().getTime();
const countdownSpan = element.querySelector('.countdown-text');
if (!countdownSpan) {
activeCountdownElements.delete(element);
return;
}
// If time has passed the buffer, re-initialize the element to find the next week's date.
if (distance < -(5 * 60 * 1000)) {
activeCountdownElements.delete(element);
initializeCountdown(element); // Re-initialize to calculate next week
return;
}
const days = Math.floor(distance / (1000 * 60 * 60 * 24));
const hours = Math.floor((distance % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60));
const minutes = Math.floor((distance % (1000 * 60 * 60)) / (1000 * 60));
const seconds = Math.floor((distance % (1000 * 60)) / 1000);
const countdownContainer = element.querySelector('.countdown-timer');
countdownContainer.classList.remove('airing-soon', 'airing-now');
if (distance <= 0) {
countdownSpan.innerHTML = 'AIRING NOW!';
countdownContainer.classList.add('airing-now');
} else if (distance < (1 * 60 * 60 * 1000)) { // Less than 1 hour
countdownContainer.classList.add('airing-soon');
countdownSpan.innerHTML = `${String(hours).padStart(2, '0')}:${String(minutes).padStart(2, '0')}:${String(seconds).padStart(2, '0')} <span class="label">HRS:MIN:SEC</span>`;
} else if (days > 0) {
countdownSpan.innerHTML = `${days}<span class="label">d</span> ${String(hours).padStart(2, '0')}<span class="label">h</span> ${String(minutes).padStart(2, '0')}<span class="label">m</span>`;
} else {
countdownSpan.innerHTML = `${String(hours).padStart(2, '0')}:${String(minutes).padStart(2, '0')}:${String(seconds).padStart(2, '0')}`;
}
}
/**
* The single global function that updates all timers.
*/
function globalUpdateLoop() {
if (activeCountdownElements.size === 0) {
// If no elements, stop the loop to save resources
if (globalIntervalId) {
clearInterval(globalIntervalId);
globalIntervalId = null;
}
return;
}
// Iterate through all tracked elements and update their display
activeCountdownElements.forEach(element => {
updateSingleCountdown(element);
});
}
/**
* Starts the single central update interval if it's not already running.
*/
function startGlobalUpdateLoop() {
if (globalIntervalId === null) {
// Run every 1000ms (1 second)
globalIntervalId = setInterval(globalUpdateLoop, 1000);
}
}
/**
* Sets up the countdown for a single element.
*/
function initializeCountdown(element) {
// 1. Get the time string and day index
const timeString = element.textContent.trim().match(/\d{2}:\d{2}/)?.[0];
if (!timeString) return;
const columnIndex = getAiringColumnIndex(element);
if (columnIndex === null) return;
const targetDay = DAY_OFFSETS[columnIndex];
// 2. Calculate the next airing date with offset
const targetDate = getNextAiringDate(targetDay, timeString);
if (!targetDate) return;
// 3. Transform the element's content if not already transformed
if (!element.querySelector('.countdown-timer')) {
element.setAttribute('data-original-time', element.textContent.trim());
element.innerHTML = `<div class="countdown-timer" id="${element.id}_countdown"><span class="countdown-text">...</span></div>`;
}
// 4. Track the element for the global update loop
element.__targetDate = targetDate;
activeCountdownElements.add(element);
// 5. Ensure the global update loop is running
startGlobalUpdateLoop();
// Run immediately to populate the timer
updateSingleCountdown(element);
}
/**
* Clears all countdowns (by stopping the global loop) and resets the element tracking.
*/
function clearAllTimers() {
if (globalIntervalId) {
clearInterval(globalIntervalId);
globalIntervalId = null;
}
activeCountdownElements.clear();
}
// --- UI SETUP & MAIN EXECUTION ---
function setupSettingsUI() {
// --- Settings Panel ---
const settingsContainer = document.createElement('div');
settingsContainer.id = 'gm-countdown-settings';
settingsContainer.innerHTML = `
<div style="font-size: 13px;">
<label for="tz-offset" style="display: block; margin-bottom: 5px; font-weight: 600;">
Countdown Time Offset (Hours):
</label>
<input type="text" id="tz-offset" value="${timezoneOffsetHours.toFixed(1)}" placeholder="e.g. -2 or -2.5"
style="
width: 100%;
padding: 6px;
border: 1px solid #555;
background: #1e1e1e;
color: #fff;
border-radius: 4px;
text-align: center;
font-size: 14px;
">
<button id="tz-save"
style="
margin-top: 8px;
width: 100%;
padding: 8px;
background: #3552a1;
color: #FFFF;
border: none;
border-radius: 4px;
cursor: pointer;
font-weight: 700;
transition: background 0.2s;
">
Save & Apply Offset
</button>
<p style="margin-top: 6px; opacity: 0.8; font-size: 11px;">
Offset is added to the site's displayed time. Use negative for earlier times.
</p>
</div>
`;
document.body.appendChild(settingsContainer);
// --- Toggle Button ---
const toggleButton = document.createElement('button');
toggleButton.id = 'gm-settings-toggle';
toggleButton.textContent = 'Countdown Settings';
document.body.appendChild(toggleButton);
// --- Event Listeners ---
toggleButton.addEventListener('click', () => {
settingsContainer.classList.toggle('visible');
});
document.getElementById('tz-save').addEventListener('click', () => {
const input = document.getElementById('tz-offset');
const newOffset = parseFloat(input.value);
const button = document.getElementById('tz-save');
if (!isNaN(newOffset)) {
GM_setValue('timezoneOffsetHours', newOffset);
timezoneOffsetHours = newOffset;
// Clear and re-run main logic
clearAllTimers();
main(true);
input.style.borderColor = '#34d399';
button.textContent = 'Offset Applied!';
button.style.backgroundColor = '#10b981';
setTimeout(() => {
button.textContent = 'Save & Apply Offset';
button.style.backgroundColor = '#34d399';
}, 1500);
} else {
input.style.borderColor = '#f87171';
button.textContent = 'Invalid Number!';
setTimeout(() => {
button.textContent = 'Save & Apply Offset';
}, 1500);
}
});
}
function main(isReinitialization = false) {
if (!isReinitialization && !isUiSetup) {
setupSettingsUI();
isUiSetup = true;
}
const calendarContainer = document.getElementById('calendar_container');
const scope = calendarContainer || document;
const airingHourDivs = scope.querySelectorAll('.airing_hour');
if (airingHourDivs.length === 0) {
// Safely retry only if the calendar container hasn't been loaded yet.
if (!isReinitialization) {
setTimeout(main, 500);
}
return;
}
// Initialize any new elements found
airingHourDivs.forEach(div => {
if (isReinitialization || !div.querySelector('.countdown-timer')) {
initializeCountdown(div);
}
});
console.log(`Initialized countdown for ${activeCountdownElements.size} elements with offset ${timezoneOffsetHours} hour(s).`);
}
// Start the safe loading process
main();
})();
|
ShaggyZENov 6, 2025 6:34 AM
![]() My Userscripts - Themes - Userstyles - Extensions (Chrome/Firefox) [API CSS] MAL-Scraper-API Cover/CSS Generator |
Nov 3, 2025 4:08 AM
#31
Reply to ShaggyZE
Due to some like myself loving countdowns just going to plop this down here.
// ==UserScript==
// @name MyAiringList Countdown
// @namespace http://tampermonkey.net/
// @version 1.2
// @description Replaces static airing hours with a live countdown timer showing days, hours, minutes, and seconds until the next episode, with a user-adjustable timezone offset.
// @author Gemini
// @match *://myairinglist.vercel.app/MyAiringList/*
// @grant GM_addStyle
// @grant GM_getValue
// @grant GM_setValue
// @run-at document-idle
// ==/UserScript==
(function() {
'use strict';
// --- CONFIGURATION ---
const DAY_OFFSETS = [1, 2, 3, 4, 5, 6, 0]; // Mon-Sun -> JS Days 1-6, 0
const DAY_NAMES = ['sunday', 'monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday'];
// --- GLOBAL STATE ---
let timezoneOffsetHours = parseFloat(GM_getValue('timezoneOffsetHours', 0));
let isUiSetup = false;
let globalIntervalId = null; // ID for the single central update interval
const activeCountdownElements = new Set(); // Stores all elements that need updating
// --- STYLES ---
GM_addStyle(`
/* The .airing_hour container is now a block to ensure it fills the available space */
.airing_hour {
display: block !important; /* Ensure it behaves like a block element */
width: 100% !important; /* Force it to take full width of its parent */
box-sizing: border-box;
}
/* Countdown Timer Styles (This is the element replacing the time text) */
.countdown-timer {
font-family: 'Inter', sans-serif;
font-weight: 700;
text-align: center;
padding: 2px 0;
color: #d1d5db;
font-size: 16px;
display: block;
min-height: 20px;
text-shadow: 1px 1px 2px rgba(0, 0, 0, 0.5);
transition: color 0.3s ease;
width: 100%; /* Ensure the timer itself takes the full width of the .airing_hour parent */
}
.countdown-timer.airing-soon {
color: #fca5a5;
}
.countdown-timer.airing-now {
color: #34d399;
font-weight: 900;
animation: pulse 1s infinite alternate;
}
.countdown-timer .label {
font-weight: 400;
font-size: 0.65em;
opacity: 0.7;
}
@keyframes pulse {
from { transform: scale(1); opacity: 1; }
to { transform: scale(1.05); opacity: 0.9; }
}
/* Settings UI Styles */
#gm-settings-toggle {
position: fixed;
top: 10px;
right: 10px;
z-index: 10001;
padding: 5px 10px;
background: #3552a1;
color: #fff;
border: none;
border-radius: 4px;
cursor: pointer;
font-size: 14px;
font-weight: 600;
box-shadow: 0 2px 5px rgba(0,0,0,0.3);
}
#gm-countdown-settings {
position: fixed;
top: 50px;
right: 10px;
z-index: 10000;
background: rgba(30, 30, 30, 0.95);
padding: 15px;
border-radius: 8px;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.5);
color: #fff;
font-family: 'Inter', sans-serif;
border: 1px solid #444;
display: none;
/* Added Max Width for better UI control */
max-width: 250px;
min-width: 200px;
}
#gm-countdown-settings.visible {
display: block;
}
`);
// --- CORE LOGIC FUNCTIONS ---
/**
* Attempts to determine the day index of the column containing the element
*/
function getAiringColumnIndex(element) {
let current = element;
while (current.parentElement) {
const parent = current.parentElement;
for (let i = 0; i < DAY_NAMES.length; i++) {
const day = DAY_NAMES[i];
if (parent.classList.contains(`${day}_container`)) {
return (i === 0) ? 6 : i - 1; // Sun -> 6, Mon -> 0, Tue -> 1, etc.
}
}
current = parent;
if (current === document.body) break;
}
return null;
}
/**
* Calculates the next date/time the show airs, applying the user's timezone offset.
*/
function getNextAiringDate(targetDay, timeString) {
const [hours, minutes] = timeString.split(':').map(Number);
if (isNaN(hours) || isNaN(minutes)) return null;
const now = new Date();
const nowDay = now.getDay();
let daysUntil = targetDay - nowDay;
if (daysUntil < 0) daysUntil += 7;
const targetDate = new Date(now.getFullYear(), now.getMonth(), now.getDate() + daysUntil, hours, minutes, 0, 0);
const offsetMilliseconds = timezoneOffsetHours * 60 * 60 * 1000;
targetDate.setTime(targetDate.getTime() + offsetMilliseconds);
// If adjusted time is in the past, move to next week.
if (targetDate.getTime() < now.getTime()) {
targetDate.setDate(targetDate.getDate() + 7);
}
return targetDate;
}
/**
* Logic to update the display for a SINGLE element.
* This function is now called from the global interval.
*/
function updateSingleCountdown(element) {
let distance = element.__targetDate.getTime() - new Date().getTime();
const countdownSpan = element.querySelector('.countdown-text');
if (!countdownSpan) {
activeCountdownElements.delete(element);
return;
}
// If time has passed the buffer, re-initialize the element to find the next week's date.
if (distance < -(5 * 60 * 1000)) {
activeCountdownElements.delete(element);
initializeCountdown(element); // Re-initialize to calculate next week
return;
}
const days = Math.floor(distance / (1000 * 60 * 60 * 24));
const hours = Math.floor((distance % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60));
const minutes = Math.floor((distance % (1000 * 60 * 60)) / (1000 * 60));
const seconds = Math.floor((distance % (1000 * 60)) / 1000);
const countdownContainer = element.querySelector('.countdown-timer');
countdownContainer.classList.remove('airing-soon', 'airing-now');
if (distance <= 0) {
countdownSpan.innerHTML = 'AIRING NOW!';
countdownContainer.classList.add('airing-now');
} else if (distance < (1 * 60 * 60 * 1000)) { // Less than 1 hour
countdownContainer.classList.add('airing-soon');
countdownSpan.innerHTML = `${String(hours).padStart(2, '0')}:${String(minutes).padStart(2, '0')}:${String(seconds).padStart(2, '0')} <span class="label">HRS:MIN:SEC</span>`;
} else if (days > 0) {
countdownSpan.innerHTML = `${days}<span class="label">d</span> ${String(hours).padStart(2, '0')}<span class="label">h</span> ${String(minutes).padStart(2, '0')}<span class="label">m</span>`;
} else {
countdownSpan.innerHTML = `${String(hours).padStart(2, '0')}:${String(minutes).padStart(2, '0')}:${String(seconds).padStart(2, '0')}`;
}
}
/**
* The single global function that updates all timers.
*/
function globalUpdateLoop() {
if (activeCountdownElements.size === 0) {
// If no elements, stop the loop to save resources
if (globalIntervalId) {
clearInterval(globalIntervalId);
globalIntervalId = null;
}
return;
}
// Iterate through all tracked elements and update their display
activeCountdownElements.forEach(element => {
updateSingleCountdown(element);
});
}
/**
* Starts the single central update interval if it's not already running.
*/
function startGlobalUpdateLoop() {
if (globalIntervalId === null) {
// Run every 1000ms (1 second)
globalIntervalId = setInterval(globalUpdateLoop, 1000);
}
}
/**
* Sets up the countdown for a single element.
*/
function initializeCountdown(element) {
// 1. Get the time string and day index
const timeString = element.textContent.trim().match(/\d{2}:\d{2}/)?.[0];
if (!timeString) return;
const columnIndex = getAiringColumnIndex(element);
if (columnIndex === null) return;
const targetDay = DAY_OFFSETS[columnIndex];
// 2. Calculate the next airing date with offset
const targetDate = getNextAiringDate(targetDay, timeString);
if (!targetDate) return;
// 3. Transform the element's content if not already transformed
if (!element.querySelector('.countdown-timer')) {
element.setAttribute('data-original-time', element.textContent.trim());
element.innerHTML = `<div class="countdown-timer" id="${element.id}_countdown"><span class="countdown-text">...</span></div>`;
}
// 4. Track the element for the global update loop
element.__targetDate = targetDate;
activeCountdownElements.add(element);
// 5. Ensure the global update loop is running
startGlobalUpdateLoop();
// Run immediately to populate the timer
updateSingleCountdown(element);
}
/**
* Clears all countdowns (by stopping the global loop) and resets the element tracking.
*/
function clearAllTimers() {
if (globalIntervalId) {
clearInterval(globalIntervalId);
globalIntervalId = null;
}
activeCountdownElements.clear();
}
// --- UI SETUP & MAIN EXECUTION ---
function setupSettingsUI() {
// --- Settings Panel ---
const settingsContainer = document.createElement('div');
settingsContainer.id = 'gm-countdown-settings';
settingsContainer.innerHTML = `
<div style="font-size: 13px;">
<label for="tz-offset" style="display: block; margin-bottom: 5px; font-weight: 600;">
Countdown Time Offset (Hours):
</label>
<input type="text" id="tz-offset" value="${timezoneOffsetHours.toFixed(1)}" placeholder="e.g. -2 or -2.5"
style="
width: 100%;
padding: 6px;
border: 1px solid #555;
background: #1e1e1e;
color: #fff;
border-radius: 4px;
text-align: center;
font-size: 14px;
">
<button id="tz-save"
style="
margin-top: 8px;
width: 100%;
padding: 8px;
background: #3552a1;
color: #FFFF;
border: none;
border-radius: 4px;
cursor: pointer;
font-weight: 700;
transition: background 0.2s;
">
Save & Apply Offset
</button>
<p style="margin-top: 6px; opacity: 0.8; font-size: 11px;">
Offset is added to the site's displayed time. Use negative for earlier times.
</p>
</div>
`;
document.body.appendChild(settingsContainer);
// --- Toggle Button ---
const toggleButton = document.createElement('button');
toggleButton.id = 'gm-settings-toggle';
toggleButton.textContent = 'Countdown Settings';
document.body.appendChild(toggleButton);
// --- Event Listeners ---
toggleButton.addEventListener('click', () => {
settingsContainer.classList.toggle('visible');
});
document.getElementById('tz-save').addEventListener('click', () => {
const input = document.getElementById('tz-offset');
const newOffset = parseFloat(input.value);
const button = document.getElementById('tz-save');
if (!isNaN(newOffset)) {
GM_setValue('timezoneOffsetHours', newOffset);
timezoneOffsetHours = newOffset;
// Clear and re-run main logic
clearAllTimers();
main(true);
input.style.borderColor = '#34d399';
button.textContent = 'Offset Applied!';
button.style.backgroundColor = '#10b981';
setTimeout(() => {
button.textContent = 'Save & Apply Offset';
button.style.backgroundColor = '#34d399';
}, 1500);
} else {
input.style.borderColor = '#f87171';
button.textContent = 'Invalid Number!';
setTimeout(() => {
button.textContent = 'Save & Apply Offset';
}, 1500);
}
});
}
function main(isReinitialization = false) {
if (!isReinitialization && !isUiSetup) {
setupSettingsUI();
isUiSetup = true;
}
const calendarContainer = document.getElementById('calendar_container');
const scope = calendarContainer || document;
const airingHourDivs = scope.querySelectorAll('.airing_hour');
if (airingHourDivs.length === 0) {
// Safely retry only if the calendar container hasn't been loaded yet.
if (!isReinitialization) {
setTimeout(main, 500);
}
return;
}
// Initialize any new elements found
airingHourDivs.forEach(div => {
if (isReinitialization || !div.querySelector('.countdown-timer')) {
initializeCountdown(div);
}
});
console.log(`Initialized countdown for ${activeCountdownElements.size} elements with offset ${timezoneOffsetHours} hour(s).`);
}
// Start the safe loading process
main();
})();
| @ShaggyZE This is actually great! I’ve had this on my to-do list for so long that I almost gave up on implementing it. I’m really glad you took the time to add this awesome feature to my work! :D Maybe, when I have some time, I’ll steal your script and add it as a built-in feature — giving you proper credit, of course, if you agree. Again, thank you for your contribution! |
MyAiringList - Your currently airing animes in a calendar view. MySeasonalList - Personal stats for your completed anime sorted by seasons. Official Club for MyAiringList and MySeasonalList. |
Nov 3, 2025 8:37 AM
#32
Reply to Morteux
@ShaggyZE This is actually great! I’ve had this on my to-do list for so long that I almost gave up on implementing it.
I’m really glad you took the time to add this awesome feature to my work! :D
Maybe, when I have some time, I’ll steal your script and add it as a built-in feature — giving you proper credit, of course, if you agree.
Again, thank you for your contribution!
I’m really glad you took the time to add this awesome feature to my work! :D
Maybe, when I have some time, I’ll steal your script and add it as a built-in feature — giving you proper credit, of course, if you agree.
Again, thank you for your contribution!
| @Morteux it's okay it took like 20 seconds, as you can see by the author being Gemini AI, but yea it should run fine with your other backend JS. |
![]() My Userscripts - Themes - Userstyles - Extensions (Chrome/Firefox) [API CSS] MAL-Scraper-API Cover/CSS Generator |
More topics from this board
» Have you ever generated anime images with AI software?DesuMaiden - Today |
3 |
by jiv123
»»
38 minutes ago |
|
» Have you ever used a fountain pen for drawing?DesuMaiden - Jan 2 |
14 |
by anen0me
»»
Today, 6:29 AM |
|
» AI-Powered Anime Recommendations + Stats ( 1 2 )ameo___ - May 23, 2022 |
95 |
by therex55213
»»
Today, 5:57 AM |
|
» Have you ever used a dip pen for drawing?DesuMaiden - Today |
0 |
by DesuMaiden
»»
Today, 5:01 AM |
|
» ♥Rena Saotome♥ (VOLKS DDP "Ribbon")MasterTasuke - Dec 31, 2025 |
5 |
by Retro8bit
»»
Yesterday, 5:27 PM |
