Last active
December 22, 2024 03:46
-
-
Save qctfw/dd71a93bffee961b884fd6a16e26daa8 to your computer and use it in GitHub Desktop.
UserScript of Integrating WibuSaka into MyAnimeList for displaying available anime streaming platforms in Indonesia
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// ==UserScript== | |
// @name WibuSaka for MyAnimeList | |
// @namespace http://wibusaka.moe/ | |
// @version 0.5.0 | |
// @description Integrate Indonesian Streaming Platforms in MyAnimeList | |
// @author Azhar | |
// @homepage https://wibusaka.moe/ | |
// @match https://myanimelist.net/anime/* | |
// @match https://myanimelist.net/animelist/* | |
// @icon https://wibusaka.moe/img/favicons/wibusaka_icon-196x196.png | |
// @icon64 https://wibusaka.moe/img/favicons/wibusaka_icon-64x64.png | |
// @updateURL https://gist.github.com/raw/dd71a93bffee961b884fd6a16e26daa8/wibusaka-for-mal.user.js | |
// @downloadURL https://gist.github.com/raw/dd71a93bffee961b884fd6a16e26daa8/wibusaka-for-mal.user.js | |
// @connect api.wibusaka.moe | |
// @grant GM_xmlhttpRequest | |
// ==/UserScript== | |
(function() { | |
/* globals $ */ | |
'use strict'; | |
const malCategory = window.location.pathname.split('/')[1]; | |
const animeCategory = window.location.pathname.split('/')[2]; | |
if (malCategory === 'animelist') { | |
mainList(); | |
} | |
else if (malCategory === 'anime' && ['season', 'genre'].includes(animeCategory)) { | |
mainList(); | |
} | |
else if (malCategory === 'anime' && !Number.isNaN(+animeCategory)) { | |
mainId(animeCategory); | |
} | |
function mainId(animeId) { | |
if (!checkAiredDate()) { | |
return; | |
} | |
const resourceModalSelector = '.mal-modal .mal-modal-body .broadcasts.wibusaka'; | |
const resourceLeftSideSelector = '#wibusaka-anime-availability'; | |
let resources = []; | |
let resourceLoaded = false; | |
$('.leftside').children().last().prev().before(`<h2> | |
Streaming Platforms | |
<br> | |
<span style="font-weight: normal;font-size:9px;">Provided by <a href="https://wibusaka.moe" target="_blank">WibuSaka</a></span> | |
</h2> | |
<div id="${resourceLeftSideSelector.slice(1)}" class="broadcasts wibusaka"> | |
Loading... | |
</div>`); | |
if ($('.js-broadcast-button').length > 0) { | |
$('.js-broadcast-button').on('click', function (e) { | |
if ($(resourceModalSelector).length <= 0) { | |
$('.mal-modal .mal-modal-body').prepend(`<div style="padding:0 34px;margin-bottom:-11px;margin-top:11px;">MyAnimeList Resources</div>`); | |
$('.mal-modal .mal-modal-body').append(`<div style="padding:0 34px;">Resources Provided by <a href="https://wibusaka.moe">WibuSaka</a></div><ul class="broadcasts wibusaka" style="margin-top:0.2em;"></ul>`); | |
} | |
if (resourceLoaded) { | |
addToStreamingModal(resources); | |
} | |
}); | |
} | |
getResources(animeId, function (response) { | |
resources = response.response.data.resources; | |
resourceLoaded = true; | |
$(resourceLeftSideSelector).html(null); | |
if (resources.length == 0) { | |
$(resourceModalSelector).html('<i>No platforms available for this anime.</i>'); | |
$(resourceLeftSideSelector).html('<i>No platforms available for this anime.</i>'); | |
} | |
resources.forEach(element => { | |
const resourceLeftSide = `<div class="broadcast"> | |
<a href="${element.url}" target="_blank" title="${element.platform.name}" class="broadcast-item" data-available="1"> | |
${getIconResource(element.platform.name)} | |
<div class="caption" ${element.note ? 'style="height:unset;"' : ''}>${element.platform.name}${element.is_paid ? ' (Paid)' : ''}${element.note ? `<br /><em>(${element.note})</em>` : ''}</div> | |
</a> | |
</div>`; | |
$(resourceLeftSideSelector).append(resourceLeftSide); | |
}); | |
if (document.querySelector('.mal-modal.show')) { | |
$('.js-broadcast-button').trigger('click'); | |
} | |
}, function(response) { | |
if (response.status == 429) { | |
$(resourceModalSelector).html('<i>Too many requests. Please try again later.</i>'); | |
$(resourceLeftSideSelector).html('<i>Too many requests. Please try again later.</i>'); | |
} | |
else if (response.status == 503) { | |
$(resourceModalSelector).html('<i>API is on maintenance. Please try again later.</i>'); | |
$(resourceLeftSideSelector).html('<i>API is on maintenance. Please try again later.</i>'); | |
} | |
else { | |
$(resourceModalSelector).html('<i>An error has been occured.</i>'); | |
$(resourceLeftSideSelector).html('<i>An error has been occured.</i>'); | |
console.error('WibuSaka error: ' + response.status + ' ' + response.statusText); | |
console.error(response.response); | |
} | |
}); | |
} | |
function mainList() { | |
const allResources = new Map(); | |
$('.js-broadcast-button, [data-ga-click-type=broadcast-ownlist]').click(function (e) { | |
const animeId = $(this).data('gaClickParam').slice(4); | |
$('.mal-modal .mal-modal-body').prepend(`<div style="padding:0 34px;margin-bottom:-11px;margin-top:11px;">MyAnimeList Resources</div>`); | |
$('.mal-modal .mal-modal-body').append(`<div style="padding:0 34px;"> | |
Resources Provided by <a href="https://wibusaka.moe" target="_blank">WibuSaka</a> | |
</div> | |
<ul class="broadcasts wibusaka" style="margin-top:0.2em;">Loading...</ul>`); | |
if (allResources.has(animeId)) { | |
addToStreamingModal(allResources.get(animeId)); | |
return; | |
} | |
getResources(animeId, function (response) { | |
const resources = response.response.data.resources; | |
allResources.set(animeId, resources); | |
addToStreamingModal(resources); | |
}, function(response) { | |
$('.mal-modal .mal-modal-body .broadcasts.wibusaka').html(null); | |
if (response.status == 429) { | |
$('.mal-modal .mal-modal-body .broadcasts.wibusaka').html('<i>Too many requests. Please try again later.</i>'); | |
} | |
else if (response.status == 503) { | |
$('.mal-modal .mal-modal-body .broadcasts.wibusaka').html('<i>API is on maintenance. Please try again later.</i>'); | |
} | |
else { | |
$('.mal-modal .mal-modal-body .broadcasts.wibusaka').html('<i>An error has been occured.</i>'); | |
console.error('WibuSaka error: ' + response.status + ' ' + response.statusText); | |
console.error(response.response); | |
} | |
}); | |
}); | |
} | |
function checkAiredDate() { | |
let airedDate = $('.leftside div:contains("Aired:")').text().replace('Aired:', '').trim().split(' to ')[0]; | |
if (airedDate == 'Not available') { | |
return false; | |
} | |
airedDate = new Date(airedDate); | |
let todayDate = (new Date()).setHours(0, 0, 0, 0); | |
const difference = (airedDate.getTime() - todayDate) / (1000 * 3600 * 24); | |
return difference <= 14; | |
} | |
function addToStreamingModal(resources) { | |
$('.mal-modal .mal-modal-body .broadcasts.wibusaka').html(null); | |
if (resources.length == 0) { | |
$('.mal-modal .mal-modal-body .broadcasts.wibusaka').html('<i>No platforms available for this anime.</i>'); | |
} | |
resources.forEach(element => { | |
const resourceText = `<li class="broadcast" data-available="true"> | |
<a href="${element.url}" target="_blank"> | |
${getIconResource(element.platform.name)} | |
<div class="caption" ${element.note ? 'style="height:unset;"' : ''}>${element.platform.name}${element.is_paid ? ' (Paid)' : ''}${element.note ? `<br /><em>(${element.note})</em>` : ''}</div> | |
</a> | |
</li>`; | |
$('.mal-modal .mal-modal-body .broadcasts.wibusaka').append(resourceText); | |
}); | |
} | |
function getResources(id, success, error) { | |
GM_xmlhttpRequest({ | |
method: "GET", | |
url: `https://api.wibusaka.moe/v2/resources/anime/myanimelist/${id}`, | |
revalidate: true, | |
responseType: 'json', | |
onload: success, | |
onerror: error | |
}); | |
} | |
function getIconResource(name) { | |
name = name.toLowerCase(); | |
const availableIcons = [ | |
'crunchyroll', | |
'netflix', | |
'hidive', | |
'funimation', | |
'hulu', | |
'aisplay', | |
'animaxasia', | |
'animaxkorea', | |
'animedigitalnetwork', | |
'animeondemand', | |
'ani-oneasia', | |
'aniplusasia', | |
'aniplustv', | |
'aniverse', | |
'asiancrush', | |
'bahamutanimecrazy', | |
'bilibili', | |
'bilibiliintl', | |
'catchplay', | |
'danet', | |
'dimsument', | |
'flixer', | |
'iqiyi', | |
'laftel', | |
'museasia', | |
'pops', | |
'selectavision', | |
'shahid', | |
'starzplay', | |
'tubitv', | |
'viu', | |
'vivoplay', | |
'vvvvid', | |
'wakanim', | |
'wetv', | |
'yamatoanimation', | |
'amazonprimevideo', | |
'trueid', | |
'genflix', | |
'jonuplay', | |
'mewatch', | |
'sushiroll', | |
'upstream', | |
'animaxmongolia', | |
'disneyplus', | |
'prosiebenmaxx', | |
'disneyhotstar' | |
]; | |
const alternativeIconNames = { | |
"bstation": "bilibiliintl", | |
"catchplay+": "catchplay", | |
"prime video": "amazonprimevideo", | |
"hotstar": "disneyhotstar", | |
}; | |
const alternativeIconsUrl = { | |
"vidio": `https://assets.wibusaka.moe/img/logos/vidio.webp`, | |
"twitter": `https://cdn.myanimelist.net/img/common/external_links/101.png`, | |
"youtube": `https://cdn.myanimelist.net/img/common/external_links/102.png`, | |
} | |
if (name in alternativeIconNames) { | |
name = alternativeIconNames[name]; | |
} | |
else if (name in alternativeIconsUrl) { | |
return `<img src="${alternativeIconsUrl[name]}" class="link_icon" alt="icon" width="20" height="20" />`; | |
} | |
else if (!availableIcons.includes(name)) { | |
return `<div style="width:20px;height:17px;display:flex;align-items:center;justify-content:center;"><i class="link_icon fa-solid fa-link"></i></div>`; | |
} | |
return `<i class="spicon spicon-${name}"></i>`; | |
} | |
})(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment