Created
November 22, 2023 00:45
-
-
Save A1ex-N/0b6c94954cf1754f23f370af2aa81cd1 to your computer and use it in GitHub Desktop.
This file contains 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 Lookmovie premium | |
// @namespace https://lookmovie2.to | |
// @version 0.1 | |
// @description allows you to copy stream (m3u8) URLs to clipboard | |
// @author https://github.com/A1ex-N | |
// @match *://www.lookmovie2.to/* | |
// @icon https://www.google.com/s2/favicons?sz=64&domain=lookmovie169.xyz | |
// @grant GM.xmlHttpRequest | |
// @grant unsafeWindow | |
// @grant GM_setClipboard | |
// @grant GM_addElement | |
// @grant GM_addStyle | |
// @run-at document-idle | |
// ==/UserScript== | |
// styles for the URL copy buttons | |
GM_addStyle(` | |
.copy-url-btn { | |
margin-right: 10px; /* Adds space between buttons */ | |
padding: 0.6em 2em; | |
border: none; | |
margin: 5px; | |
outline: none; | |
color: rgb(255, 255, 255); | |
background: #111; | |
cursor: pointer; | |
position: relative; | |
z-index: 0; | |
border-radius: 10px; | |
user-select: none; | |
-webkit-user-select: none; | |
touch-action: manipulation; | |
} | |
.copy-url-btn:before { | |
content: ""; | |
background: linear-gradient( | |
45deg, | |
#ff0000, | |
#ff7300, | |
#fffb00, | |
#48ff00, | |
#00ffd5, | |
#002bff, | |
#7a00ff, | |
#ff00c8, | |
#ff0000 | |
); | |
position: absolute; | |
top: -2px; | |
left: -2px; | |
background-size: 400%; | |
z-index: -1; | |
filter: blur(5px); | |
-webkit-filter: blur(5px); | |
width: calc(100% + 4px); | |
height: calc(100% + 4px); | |
animation: glowing-button-85 20s linear infinite; | |
transition: opacity 0.3s ease-in-out; | |
border-radius: 10px; | |
} | |
@keyframes glowing-button-85 { | |
0% { | |
background-position: 0 0; | |
} | |
50% { | |
background-position: 400% 0; | |
} | |
100% { | |
background-position: 0 0; | |
} | |
} | |
.copy-url-btn:after { | |
z-index: -1; | |
content: ""; | |
position: absolute; | |
width: 100%; | |
height: 100%; | |
background: #222; | |
left: 0; | |
top: 0; | |
border-radius: 10px; | |
} | |
.copy-url-btn:active { | |
transform: scale(0.95); /* Reduce size slightly on click */ | |
box-shadow: 0 0 5px rgba(0, 0, 0, 0.3); /* Add a box-shadow on click */ | |
} | |
.copy-btn-div { | |
display: flex; | |
width: fit-content; | |
} | |
`) | |
class ElementFactory { | |
static clearPremiumAdvertisement() { | |
let displayElement = document.querySelector("#app > div.view-movie > div > div.container > div:nth-child(3)"); | |
displayElement.innerHTML = ""; | |
} | |
static createUrlCopyButtons(streams) { | |
let htmlToInsert = `<div class="copy-btn-div"><ul>`; | |
for (let stream of Object.keys(streams)) { | |
htmlToInsert += `<li><button class="copy-url-btn" onclick="window.setClipboardText('${streams[stream]}')">${stream}</button></li>`; | |
} | |
// element already on the page, below the video player | |
let displayElement = document.querySelector("#app > div.view-movie > div > div.container > div:nth-child(3)"); | |
htmlToInsert += "</ul></div>"; | |
// changing += to = will get rid of the copy stream buttons | |
displayElement.innerHTML += htmlToInsert; | |
} | |
static createButtonWithTextAndCallback(text, callback, id = "") { | |
let htmlToInsert = `<button id="${id}" class="copy-url-btn" onclick="${callback}">${text}</button>`; | |
// element already on the page, below the video player | |
let displayElement = document.querySelector("#app > div.view-movie > div > div.container > div:nth-child(3)"); | |
displayElement.innerHTML += htmlToInsert; | |
} | |
} | |
let moviesAlreadyFetched = false; | |
unsafeWindow.Movie = class { | |
static setup() { | |
console.log("This is a movie") | |
ElementFactory.clearPremiumAdvertisement(); | |
ElementFactory.createButtonWithTextAndCallback("Get movie stream URLs", "Movie.displayUrlCopyButtons()", "get-streams-btn"); | |
} | |
static getStorage() { | |
return { | |
id: unsafeWindow.movie_storage.id_movie, | |
hash: unsafeWindow.movie_storage.hash, | |
expires: unsafeWindow.movie_storage.expires | |
} | |
} | |
static async displayUrlCopyButtons() { | |
if (moviesAlreadyFetched) { return } | |
const streams = await this.getStreams(); | |
ElementFactory.createUrlCopyButtons(streams); | |
console.log(streams); | |
} | |
static async getStreams() { | |
if (moviesAlreadyFetched) { return } | |
const movieStorage = this.getStorage(); | |
let r = await GM.xmlHttpRequest({ | |
url: `/api/v1/security/movie-access?id_movie=${movieStorage.id}&hash=${movieStorage.hash}&expires=${movieStorage.expires}` | |
}).catch(e => alert(e)); | |
moviesAlreadyFetched = true; | |
return JSON.parse(r.response).streams; // {1080p: "url", 720p: "url", ...} | |
} | |
} | |
unsafeWindow.Show = class { | |
static setup() { | |
console.log("This is a show"); | |
const showStorage = this.getStorage(); | |
let buttonText = `S${showStorage.zeroPaddedSeasonNumber}E${showStorage.zeroPaddedEpisodeNumber}`; | |
ElementFactory.clearPremiumAdvertisement(); | |
ElementFactory.createButtonWithTextAndCallback(`Get ${buttonText} stream URLs`, "Show.displayUrlCopyButtons()"); | |
Show.createGetAllStreamsInSeasonBtn(); | |
unsafeWindow.addEventListener("ChangedEpisodeHash", () => { | |
this.setup(); | |
}) | |
} | |
static getStorage() { | |
const currentSeason_ = unsafeWindow.currentSeason; | |
const allEpisodes_ = unsafeWindow.show_storage.seasons; | |
return { | |
currentSeason: currentSeason_, | |
allEpisodes: allEpisodes_, | |
allEpisodesInCurrentSeason: this.getAllEpisodesForSeason(allEpisodes_, currentSeason_), | |
totalEpisodes: unsafeWindow.show_storage.total_episodes, | |
currentEpisodeNumber: unsafeWindow.currentEpisode, | |
zeroPaddedSeasonNumber: unsafeWindow.currentSeason.toString().padStart(2, '0'), | |
zeroPaddedEpisodeNumber: unsafeWindow.currentEpisode.toString().padStart(2, '0'), | |
scriptFriendlyTitle: unsafeWindow.show_storage.title.split(' ').join('.').toLowerCase(), | |
currentEpisodeID: unsafeWindow.currentEpisodeID, | |
currentEpisodeIndex: unsafeWindow.currentEpisodeIndex, | |
showTitle: unsafeWindow.show_storage.title, | |
hash: unsafeWindow.show_storage.hash, | |
expires: unsafeWindow.show_storage.expires | |
} | |
} | |
static getAllEpisodesForSeason(allEpisodes, seasonNumber) { | |
let allEpisodesInSeason = []; | |
for (const episode of allEpisodes) { | |
if (episode.season == seasonNumber) { | |
allEpisodesInSeason.push(episode); | |
} | |
} | |
return allEpisodesInSeason; | |
} | |
static async displayUrlCopyButtons() { | |
const streams = await this.getStreamsForCurrentEpisode(); | |
ElementFactory.createUrlCopyButtons(streams); | |
console.log(streams); | |
} | |
static async copyAllStreamsToClipboard() { | |
let storage = this.getStorage(); | |
let allStreams = await this.getAllStreamsInSeason(storage); | |
setClipboardText(allStreams.join('\n')); | |
} | |
static createGetAllStreamsInSeasonBtn() { | |
let storage = this.getStorage(); | |
let initialButtonText = `Copy all streams in season ${storage.currentSeason} to clipboard`; | |
ElementFactory.createButtonWithTextAndCallback(initialButtonText, "Show.copyAllStreamsToClipboard()", "get-all-streams-btn"); | |
let getAllStreamsBtn = document.getElementById("get-all-streams-btn"); | |
document.addEventListener("fetching-streams", (e) => { | |
getAllStreamsBtn.innerText = `Fetching... ${e.detail}/${storage.allEpisodesInCurrentSeason.length}`; | |
getAllStreamsBtn.disabled = true; | |
}); | |
document.addEventListener("done-fetching", () => { | |
getAllStreamsBtn.innerText = initialButtonText; | |
getAllStreamsBtn.disabled = false; | |
}); | |
} | |
static async getStreamsForCurrentEpisode() { | |
const showStorage = this.getStorage(); | |
let r = await GM.xmlHttpRequest({ | |
url: `/api/v1/security/episode-access?id_episode=${showStorage.currentEpisodeID}&hash=${showStorage.hash}&expires=${showStorage.expires}` | |
}).catch(e => alert(e)); | |
return JSON.parse(r.response).streams; // {1080p: "url", 720p: "url", ...} | |
} | |
static async getStreamsForSpecificEpisode(episode) { | |
const showStorage = this.getStorage(); | |
console.log(`Trying to get info for episode ${episode.episode}`); | |
let r = await GM.xmlHttpRequest({ | |
url: `/api/v1/security/episode-access?id_episode=${episode.id_episode}&hash=${showStorage.hash}&expires=${showStorage.expires}` | |
}).catch(e => console.log(e)); | |
return JSON.parse(r.response).streams; // {1080p: "url", 720p: "url", ...} | |
} | |
static async getAllStreamsInSeason(storage) { | |
let allEpisodeStreams = []; | |
for (const episode of storage.allEpisodesInCurrentSeason) { | |
let fetchingEvent = new CustomEvent("fetching-streams", { detail: episode.episode }); | |
document.dispatchEvent(fetchingEvent); | |
let streams = await this.getStreamsForSpecificEpisode(episode); | |
// Only get the highest quality stream | |
let highestQualityKey = Object.keys(streams)[Object.keys(streams).length - 1]; | |
let highestQualityStream = streams[highestQualityKey]; | |
let formattedString = `${highestQualityStream},${storage.scriptFriendlyTitle}.S${zeroPad(episode.season)}E${zeroPad(episode.episode)}.mp4`; | |
allEpisodeStreams.push(formattedString); | |
} | |
let doneEvent = new CustomEvent("done-fetching"); | |
document.dispatchEvent(doneEvent); | |
return allEpisodeStreams; | |
} | |
} | |
function zeroPad(string) { | |
return string.padStart(2, '0'); | |
} | |
unsafeWindow.setClipboardText = (data) => { | |
GM_setClipboard(data, "text", () => { console.log(`${data} copied to clipboard`); alert("url(s) copied to clipboard") }); | |
} | |
function urlIncludes(str) { | |
return unsafeWindow.location.href.includes(str); | |
} | |
const IS_SHOW = urlIncludes("shows/play"); | |
const IS_MOVIE = urlIncludes("movies/play"); | |
(function () { | |
'use strict'; | |
//Yii2App.userStatus = "paid" | |
if (IS_MOVIE) { | |
Movie.setup(); | |
} else if (IS_SHOW) { | |
Show.setup(); | |
} else { | |
console.log("This ain't a movie or a show"); | |
} | |
})(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment