Skip to content

Commit

Permalink
fix(myCANAL): implement better detection + crop thumbnail (#8940)
Browse files Browse the repository at this point in the history
Signed-off-by: Arias800 <24809312+Arias800@users.noreply.github.com>
  • Loading branch information
Arias800 authored Dec 9, 2024
1 parent dc59c51 commit 20da1db
Show file tree
Hide file tree
Showing 2 changed files with 142 additions and 16 deletions.
8 changes: 6 additions & 2 deletions websites/M/myCANAL/metadata.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@
{
"name": "Dark_Ville",
"id": "638080361179512853"
},
{
"name": "Arias800",
"id": "341235976766488576"
}
],
"service": "myCANAL",
Expand All @@ -22,7 +26,7 @@
"nl": "Canal + is een Franse abonnementsaanbieder die is gekoppeld aan het kanaal met dezelfde naam. Het is eigendom van Vivendi met een aandeel van honderd procent."
},
"url": "www.canalplus.com",
"version": "2.0.11",
"version": "2.0.12",
"logo": "https://cdn.rcd.gg/PreMiD/websites/M/myCANAL/assets/logo.png",
"thumbnail": "https://cdn.rcd.gg/PreMiD/websites/M/myCANAL/assets/thumbnail.png",
"color": "#000",
Expand All @@ -40,4 +44,4 @@
"value": true
}
]
}
}
150 changes: 136 additions & 14 deletions websites/M/myCANAL/presence.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,131 @@ const presence = new Presence({
browsingTimestamp = Math.floor(Date.now() / 1000),
containsTerm = (term: string) => document.location.pathname.includes(term);

const enum Assets {
enum myCANALAssets {
Logo = "https://cdn.rcd.gg/PreMiD/websites/M/myCANAL/assets/0.png",
}

// Resize fonction made by pierrequiroul https://github.com/PreMiD/Presences/pull/8910

export const cropPreset = {
// Crop values in percent correspond to Left, Right, Top, Bottom.
squared: [0, 0, 0, 0],
vertical: [0.22, 0.22, 0, 0.3],
horizontal: [0.425, 0.025, 0, 0],
};

export async function getThumbnail(
src: string = myCANALAssets.Logo,
cropPercentages: typeof cropPreset.squared = cropPreset.squared,
progress = 2,
borderWidth = 15
): Promise<string> {
return new Promise(resolve => {
const img = new Image(),
wh = 320; // Size of the square thumbnail

img.crossOrigin = "anonymous";
img.src = src;

img.onload = function () {
let croppedWidth,
croppedHeight,
cropX = 0,
cropY = 0;

// Determine if the image is landscape or portrait
const isLandscape = img.width > img.height;

if (isLandscape) {
// Landscape mode: use left and right crop percentages
const cropLeft = img.width * cropPercentages[0];
croppedWidth = img.width - cropLeft - img.width * cropPercentages[1];
croppedHeight = img.height;
cropX = cropLeft;
} else {
// Portrait mode: use top and bottom crop percentages
const cropTop = img.height * cropPercentages[2];
croppedWidth = img.width;
croppedHeight = img.height - cropTop - img.height * cropPercentages[3];
cropY = cropTop;
}

// Determine the scale to fit the cropped image into the square canvas
let newWidth, newHeight, offsetX, offsetY;

if (isLandscape) {
newWidth = wh - 2 * borderWidth;
newHeight = (newWidth / croppedWidth) * croppedHeight;
offsetX = borderWidth;
offsetY = (wh - newHeight) / 2;
} else {
newHeight = wh - 2 * borderWidth;
newWidth = (newHeight / croppedHeight) * croppedWidth;
offsetX = (wh - newWidth) / 2;
offsetY = borderWidth;
}

const tempCanvas = document.createElement("canvas");
tempCanvas.width = wh;
tempCanvas.height = wh;
const ctx = tempCanvas.getContext("2d"),
// Remap progress from 0-1 to 0.03-0.97 (smallImageKey borders)
remappedProgress = 0.07 + progress * (0.93 - 0.07);

// 1. Fill the canvas with a black background
ctx.fillStyle = "#172e4e";
ctx.fillRect(0, 0, wh, wh);

// 2. Draw the radial progress bar
if (remappedProgress > 0) {
ctx.beginPath();
ctx.moveTo(wh / 2, wh / 2);
const startAngle = Math.PI / 4; // 45 degrees in radians, starting from bottom-right

ctx.arc(
wh / 2,
wh / 2,
wh,
startAngle,
startAngle + 2 * Math.PI * remappedProgress
);
ctx.lineTo(wh / 2, wh / 2);

// Create a triangular gradient
const gradient = ctx.createLinearGradient(0, 0, wh, wh);
gradient.addColorStop(0, "rgba(245, 3, 26, 1)");
gradient.addColorStop(0.5, "rgba(63, 187, 244, 1)");
gradient.addColorStop(1, "rgba(164, 215, 12, 1)");
ctx.fillStyle = gradient;

ctx.fill();
}

// 3. Draw the cropped image centered and zoomed out based on the borderWidth
ctx.drawImage(
img,
cropX,
cropY,
croppedWidth,
croppedHeight,
offsetX,
offsetY,
newWidth,
newHeight
);

resolve(tempCanvas.toDataURL("image/png"));
};

img.onerror = function () {
resolve(src);
};
});
}

presence.on("UpdateData", async () => {
const presenceData: PresenceData = {
largeImageKey: Assets.Logo,
largeImageKey: myCANALAssets.Logo,
},
video = document.querySelector<HTMLVideoElement>(".iIZX3IGkM2eBzzWle1QQ"),
showCover = await presence.getSetting<boolean>("cover"),
Expand All @@ -37,6 +155,9 @@ presence.on("UpdateData", async () => {
case "/series/":
presenceData.state = "Séries";
break;
case "/jeunesse/":
presenceData.state = "Jeunesse";
break;
case "/live/":
presenceData.state = "Chaînes en direct";
break;
Expand All @@ -61,8 +182,8 @@ presence.on("UpdateData", async () => {
presenceData.largeImageKey = showCover
? document.querySelector<HTMLImageElement>(
`#\\3${channelID}_onclick > div > div.card__content_0dae1b.cardContent___DuNAN.ratio--169 > div[class*="cardLogoChannel"] > div > img`
)?.src
: Assets.Logo;
).src
: myCANALAssets.Logo;
presenceData.smallImageKey = Assets.Live;
presenceData.smallImageText = "En direct";
delete presenceData.startTimestamp;
Expand All @@ -76,27 +197,28 @@ presence.on("UpdateData", async () => {
[presenceData.startTimestamp, presenceData.endTimestamp] =
presence.getTimestamps(video.currentTime, video.duration);
presenceData.largeImageKey = showCover
? (presenceData.largeImageKey =
document.querySelector<HTMLMetaElement>(
"[property='og:image']"
)?.content)
: Assets.Logo;
? (presenceData.largeImageKey = await getThumbnail(
document.querySelector<HTMLMetaElement>("[property='og:image']")
?.content
))
: myCANALAssets.Logo;
presenceData.smallImageKey = video.paused ? Assets.Pause : Assets.Play;
presenceData.smallImageText = video.paused
? (await strings).pause
: (await strings).play;
break;
case containsTerm("series"):
case containsTerm("jeunesse"):
presenceData.details = titleTvShows[0].textContent.trim();
presenceData.state = titleTvShows[1].textContent.trim();
[presenceData.startTimestamp, presenceData.endTimestamp] =
presence.getTimestamps(video.currentTime, video.duration);
presenceData.largeImageKey = showCover
? (presenceData.largeImageKey =
document.querySelector<HTMLMetaElement>(
"[property='og:image']"
)?.content)
: Assets.Logo;
? (presenceData.largeImageKey = await getThumbnail(
document.querySelector<HTMLMetaElement>("[property='og:image']")
?.content
))
: myCANALAssets.Logo;
presenceData.smallImageKey = video.paused ? Assets.Pause : Assets.Play;
presenceData.smallImageText = video.paused
? (await strings).pause
Expand Down

0 comments on commit 20da1db

Please sign in to comment.