diff --git a/common/components/Logout.svelte b/common/components/Logout.svelte index a8ccad2..5b58012 100644 --- a/common/components/Logout.svelte +++ b/common/components/Logout.svelte @@ -5,7 +5,7 @@ export const logout = writable(false) function confirm () { - localStorage.removeItem('ALtoken') + localStorage.removeItem('ALviewer') location.hash = '' location.reload() } diff --git a/common/components/Sidebar.svelte b/common/components/Sidebar.svelte index 8f9aa5c..a821d91 100644 --- a/common/components/Sidebar.svelte +++ b/common/components/Sidebar.svelte @@ -13,7 +13,7 @@ const links = [ { click: () => { - if (anilistClient.userID) { + if (anilistClient.userID?.viewer?.data?.Viewer) { $logout = true } else { IPC.emit('open', 'https://anilist.co/api/v2/oauth/authorize?client_id=4254&response_type=token') // Change redirect_url to miru://auth @@ -85,13 +85,9 @@ text: 'Settings' } ] - if (anilistClient.userID) { - anilistClient.userID.then(result => { - if (result?.data?.Viewer) { - links[0].image = result.data.Viewer.avatar.medium - links[0].text = 'Logout' - } - }) + if (anilistClient.userID?.viewer?.data?.Viewer) { + links[0].image = anilistClient.userID.viewer.data.Viewer.avatar.medium + links[0].text = 'Logout' } diff --git a/common/components/banner/Banner.svelte b/common/components/banner/Banner.svelte index 69e0dfa..cd30086 100644 --- a/common/components/banner/Banner.svelte +++ b/common/components/banner/Banner.svelte @@ -22,6 +22,8 @@
+ +
.
{#await data} {:then { data }} @@ -33,4 +35,7 @@ .gradient { background: linear-gradient(0deg, #17191D 0%, #0000 15%, #0000 100%), linear-gradient(90deg, #17191D 0%, rgba(23, 25, 29, 0.885417) 15%, rgba(25, 28, 32, 0) 72%); } + .opacity-0 { + opacity: 0; + } diff --git a/common/modules/al.d.ts b/common/modules/al.d.ts index 38c7ec4..15543da 100644 --- a/common/modules/al.d.ts +++ b/common/modules/al.d.ts @@ -92,21 +92,21 @@ export type Media = { } }[] } - recommendations?: { - edges?: { - node: { - media: { - id: number - title: { - userPreferred: string - } - coverImage?: { - medium: string - } - } - } - }[] - } + // recommendations?: { + // edges?: { + // node: { + // media: { + // id: number + // title: { + // userPreferred: string + // } + // coverImage?: { + // medium: string + // } + // } + // } + // }[] + // } } export type Following = { diff --git a/common/modules/anilist.js b/common/modules/anilist.js index 3328299..4dce16e 100644 --- a/common/modules/anilist.js +++ b/common/modules/anilist.js @@ -150,23 +150,24 @@ relations { } } } -}, -recommendations{ - edges{ - node{ - mediaRecommendation{ - id, - title{ - userPreferred - }, - coverImage{ - medium - } - } - } - } }` +// recommendations{ +// edges{ +// node{ +// mediaRecommendation{ +// id, +// title{ +// userPreferred +// }, +// coverImage{ +// medium +// } +// } +// } +// } +// } + class AnilistClient { limiter = new Bottleneck({ reservoir: 90, @@ -181,7 +182,7 @@ class AnilistClient { /** @type {import('simple-store-svelte').Writable>} */ userLists = writable() - userID + userID = alToken /** @type {Record} */ mediaCache = {} @@ -201,14 +202,7 @@ class AnilistClient { return time }) - if (alToken) { - this.userID = this.viewer({ token: alToken }).then(result => { - const lists = result?.data?.Viewer?.mediaListOptions?.animeList?.customLists || [] - if (!lists.includes('Watched using Miru')) { - this.customList({ lists }) - } - return result - }) + if (this.userID?.viewer?.data?.Viewer) { this.userLists.value = this.getUserLists() // update userLists every 15 mins setInterval(() => { this.userLists.value = this.getUserLists() }, 1000 * 60 * 15) @@ -250,8 +244,10 @@ class AnilistClient { * @param {Record} variables */ alRequest (query, variables) { + /** @type {RequestInit} */ const options = { method: 'POST', + credentials: 'omit', headers: { 'Content-Type': 'application/json', Accept: 'application/json' @@ -267,7 +263,8 @@ class AnilistClient { } }) } - if (alToken) options.headers.Authorization = alToken + // @ts-ignore + if (alToken?.token) options.headers.Authorization = alToken.token return this.handleRequest(options) } @@ -440,7 +437,6 @@ class AnilistClient { /** @returns {Promise>} */ viewer (variables = {}) { - variables.id = alToken const query = /* js */` query{ Viewer{ @@ -462,7 +458,7 @@ class AnilistClient { /** @returns {Promise>} */ async getUserLists (variables = {}) { - const userId = (await this.userID)?.data?.Viewer.id + const userId = this.userID?.viewer?.data?.Viewer.id variables.id = userId const query = /* js */` query($id: Int){ @@ -499,7 +495,7 @@ class AnilistClient { /** @returns {Promise>} */ async searchIDStatus (variables = {}) { - const userId = (await this.userID)?.data?.Viewer.id + const userId = this.userID?.viewer?.data?.Viewer.id variables.id = userId const query = /* js */` query($id: Int, $mediaId: Int){ diff --git a/common/modules/settings.js b/common/modules/settings.js index 73df77a..018333a 100644 --- a/common/modules/settings.js +++ b/common/modules/settings.js @@ -1,7 +1,10 @@ import { writable } from 'simple-store-svelte' import { defaults } from './util.js' import IPC from '@/modules/ipc.js' -export let alToken = localStorage.getItem('ALtoken') || null +import { anilistClient } from './anilist.js' +import { toast } from 'svelte-sonner' +/** @type {{viewer: import('./al').Query<{Viewer: import('./al').Viewer}>, token: string} | null} */ +export let alToken = JSON.parse(localStorage.getItem('ALviewer')) || null let storedSettings = { ...defaults } @@ -46,8 +49,18 @@ window.addEventListener('paste', ({ clipboardData }) => { } }) IPC.on('altoken', handleToken) -function handleToken (data) { - localStorage.setItem('ALtoken', data) - alToken = data +async function handleToken (token) { + alToken = { token, viewer: null } + const viewer = await anilistClient.viewer({ token }) + if (!viewer.data?.Viewer) { + toast.error('Failed to sign in with AniList. Please try again.', { description: JSON.stringify(viewer) }) + console.error(viewer) + return + } + const lists = viewer?.data?.Viewer?.mediaListOptions?.animeList?.customLists || [] + if (!lists.includes('Watched using Miru')) { + await anilistClient.customList({ lists }) + } + localStorage.setItem('ALviewer', JSON.stringify({ token, viewer })) location.reload() } diff --git a/common/views/Home/Home.svelte b/common/views/Home/Home.svelte index a3247c2..a55f34d 100644 --- a/common/views/Home/Home.svelte +++ b/common/views/Home/Home.svelte @@ -1,6 +1,6 @@ {#await following then res} - {@const following = res.data.Page.mediaList} - {#if following?.length && alToken} + {@const following = res?.data?.Page?.mediaList} + {#if following?.length}

Following
diff --git a/common/views/ViewAnime/ViewAnime.svelte b/common/views/ViewAnime/ViewAnime.svelte index 388239f..bfd1771 100644 --- a/common/views/ViewAnime/ViewAnime.svelte +++ b/common/views/ViewAnime/ViewAnime.svelte @@ -166,13 +166,13 @@
- edge.node.mediaRecommendation)} let:item title='Recommendations'> +

Episodes
diff --git a/common/views/WatchTogether/WatchTogether.svelte b/common/views/WatchTogether/WatchTogether.svelte index 6172b93..e9f8f91 100644 --- a/common/views/WatchTogether/WatchTogether.svelte +++ b/common/views/WatchTogether/WatchTogether.svelte @@ -26,10 +26,10 @@ atob('d3NzOi8vdHJhY2tlci5maWxlcy5mbTo3MDczL2Fubm91bmNl'), atob('d3NzOi8vdHJhY2tlci5idG9ycmVudC54eXov') ], code) - p2pt.on('peerconnect', async peer => { + p2pt.on('peerconnect', peer => { console.log(peer.id) console.log('connect') - const user = (await anilistClient.userID)?.data?.Viewer || {} + const user = anilistClient.userID?.viewer?.data?.Viewer || {} p2pt.send(peer, JSON.stringify({ type: 'init', diff --git a/electron/package.json b/electron/package.json index 7e8dffc..6007889 100644 --- a/electron/package.json +++ b/electron/package.json @@ -1,6 +1,6 @@ { "name": "Miru", - "version": "5.0.7", + "version": "5.0.8", "private": true, "author": "ThaUnknown_ ", "description": "Stream anime torrents, real-time with no waiting for downloads.", diff --git a/electron/src/main/main.js b/electron/src/main/main.js index a7040b5..e9319d1 100644 --- a/electron/src/main/main.js +++ b/electron/src/main/main.js @@ -18,6 +18,8 @@ function createWindow () { webtorrentWindow = new BrowserWindow({ show: development, webPreferences: { + webSecurity: false, + allowRunningInsecureContent: false, nodeIntegration: true, contextIsolation: false, backgroundThrottling: false @@ -36,6 +38,8 @@ function createWindow () { backgroundColor: '#17191c', autoHideMenuBar: true, webPreferences: { + webSecurity: false, + allowRunningInsecureContent: false, enableBlinkFeatures: 'FontAccess, AudioVideoTracks', backgroundThrottling: false, preload: path.join(__dirname, '/preload.js') @@ -53,12 +57,6 @@ function createWindow () { return { action: 'deny' } }) - mainWindow.webContents.session.webRequest.onHeadersReceived(({ responseHeaders }, fn) => { - delete responseHeaders['Access-Control-Allow-Origin'] - responseHeaders['access-control-allow-origin'] = ['*'] - fn({ responseHeaders }) - }) - const torrentLoad = webtorrentWindow.loadURL(development ? 'http://localhost:5000/background.html' : `file://${path.join(__dirname, '/background.html')}`) mainWindow.loadURL(development ? 'http://localhost:5000/app.html' : `file://${path.join(__dirname, '/app.html')}`) @@ -94,8 +92,8 @@ function createWindow () { mainWindow.webContents.on('render-process-gone', (e, { reason }) => { if (reason === 'crashed') { if (++crashcount > 10) { - dialog.showMessageBox({ message: 'Crashed too many times.', title: 'Miru', detail: 'App crashed too many times. For a fix visit https://github.com/ThaUnknown/miru/blob/master/docs/faq.md#miru-crashed-too-many-times', icon: '/renderer/public/logo_filled.png' }).then(() => { - shell.openExternal('https://github.com/ThaUnknown/miru/blob/master/docs/faq.md#miru-crashed-too-many-times') + dialog.showMessageBox({ message: 'Crashed too many times.', title: 'Miru', detail: 'App crashed too many times. For a fix visit https://miru.watch/faq/', icon: '/renderer/public/logo_filled.png' }).then(() => { + shell.openExternal('https://miru.watch/faq/') app.quit() }) } else { diff --git a/electron/src/main/util.js b/electron/src/main/util.js index e38161b..16c551b 100644 --- a/electron/src/main/util.js +++ b/electron/src/main/util.js @@ -5,20 +5,13 @@ export const development = process.env.NODE_ENV?.trim() === 'development' const flags = [ // not sure if safe? - ['disable-gpu-sandbox'], - // not sure if safe? - ['disable-direct-composition-video-overlays'], - // not sure if safe? - ['double-buffer-compositing'], - // not sure if safe? - ['enable-zero-copy'], - // not sure if safe? - ['ignore-gpu-blocklist'], + ['disable-gpu-sandbox'], ['disable-direct-composition-video-overlays'], ['double-buffer-compositing'], ['enable-zero-copy'], ['ignore-gpu-blocklist'], + // should be safe ['enable-hardware-overlays', 'single-fullscreen,single-on-top,underlay'], - // dv, drdc display compositor uses 2 gpu threads instead of 1, rest is safe performance - ['enable-features', 'PlatformEncryptedDolbyVision,EnableDrDc,CanvasOopRasterization,ThrottleDisplayNoneAndVisibilityHiddenCrossOriginIframes,UseSkiaRenderer,WebAssemblyLazyCompilation'], - // disabling shit, vulkan rendering, native window occlusion calculation, widget layering aka right click context menus [I think] for macOS [I think] - ['disable-features', 'Vulkan,CalculateNativeWinOcclusion,WidgetLayering'], + // safe performance stuff + ['enable-features', 'PlatformEncryptedDolbyVision,CanvasOopRasterization,ThrottleDisplayNoneAndVisibilityHiddenCrossOriginIframes,UseSkiaRenderer,WebAssemblyLazyCompilation'], + // disabling shit, vulkan rendering, widget layering aka right click context menus [I think] for macOS [I think] + ['disable-features', 'Vulkan,WidgetLayering'], // utility stuff, aka website security that's useless for a native app: ['autoplay-policy', 'no-user-gesture-required'], ['disable-notifications'], ['disable-logging'], ['disable-permissions-api'], ['no-sandbox'], ['no-zygote'], ['bypasscsp-schemes'] ]