From 1f9872aded9295426a8a62ec616b3beed757022a Mon Sep 17 00:00:00 2001 From: lovegaoshi <106490582+lovegaoshi@users.noreply.github.com> Date: Tue, 3 Dec 2024 16:03:25 -0800 Subject: [PATCH 1/2] fix: ytm auth header https://github.com/sigma67/ytmusicapi/blob/9ce284a7eae9c4cdc04bb098f7549cc5f1c80e22/ytmusicapi/ytmusic.py#L213 --- src/components/login/google/YTM.tsx | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/components/login/google/YTM.tsx b/src/components/login/google/YTM.tsx index cea232de..1258066c 100644 --- a/src/components/login/google/YTM.tsx +++ b/src/components/login/google/YTM.tsx @@ -6,12 +6,14 @@ import { useFocusEffect } from '@react-navigation/native'; import CookieManager from '@react-native-cookies/cookies'; import { get_option, get_current_user } from 'libmuse'; import { useTranslation } from 'react-i18next'; +import crypto from 'expo-crypto'; import { saveSecure as saveItem } from '@utils/ChromeStorageAPI'; import { StorageKeys } from '@enums/Storage'; import { User, UseYTMLogin } from './useYTMLogin'; import { museStore } from '@utils/muse'; import useCollapsible from '../useCollapsible'; +import { getSecure as getItem } from '@utils/ChromeStorageAPI'; const jsCode = 'window.ReactNativeWebView.postMessage(document.cookie)'; const auth = get_option('auth'); @@ -21,7 +23,13 @@ const clearCookies = () => { saveItem(StorageKeys.YTMCOOKIES, null); }; -const checkYTM = async () => console.log(await get_current_user()); +const checkYTM = async () => { + const cookies = await getItem(StorageKeys.YTMCOOKIES); + console.log(cookies); + console.log( + await crypto.digestStringAsync(crypto.CryptoDigestAlgorithm.SHA1, ''), + ); +}; const Login = () => { const { t } = useTranslation(); From 7bb68604febdae72f0855620b3feda8e4b83aad8 Mon Sep 17 00:00:00 2001 From: lovegaoshi <106490582+lovegaoshi@users.noreply.github.com> Date: Wed, 4 Dec 2024 10:24:08 -0800 Subject: [PATCH 2/2] fix: ytm login --- src/components/login/google/YTM.tsx | 21 +++------- src/stores/initializeStores.ts | 4 +- src/utils/muse.ts | 59 ++++++++++++++--------------- 3 files changed, 37 insertions(+), 47 deletions(-) diff --git a/src/components/login/google/YTM.tsx b/src/components/login/google/YTM.tsx index 1258066c..892a7bf4 100644 --- a/src/components/login/google/YTM.tsx +++ b/src/components/login/google/YTM.tsx @@ -4,31 +4,24 @@ import { Button, Avatar, Text, ActivityIndicator } from 'react-native-paper'; import { WebView } from 'react-native-webview'; import { useFocusEffect } from '@react-navigation/native'; import CookieManager from '@react-native-cookies/cookies'; -import { get_option, get_current_user } from 'libmuse'; +import { get_current_user } from 'libmuse'; import { useTranslation } from 'react-i18next'; -import crypto from 'expo-crypto'; import { saveSecure as saveItem } from '@utils/ChromeStorageAPI'; import { StorageKeys } from '@enums/Storage'; import { User, UseYTMLogin } from './useYTMLogin'; -import { museStore } from '@utils/muse'; import useCollapsible from '../useCollapsible'; -import { getSecure as getItem } from '@utils/ChromeStorageAPI'; +import { initMuse } from '@utils/muse'; const jsCode = 'window.ReactNativeWebView.postMessage(document.cookie)'; -const auth = get_option('auth'); const clearCookies = () => { - museStore.reset(); saveItem(StorageKeys.YTMCOOKIES, null); }; const checkYTM = async () => { - const cookies = await getItem(StorageKeys.YTMCOOKIES); - console.log(cookies); - console.log( - await crypto.digestStringAsync(crypto.CryptoDigestAlgorithm.SHA1, ''), - ); + await initMuse(); + get_current_user().then(console.log).catch(console.log); }; const Login = () => { @@ -43,7 +36,7 @@ const Login = () => { const onMessage = (event: any) => { const { data } = event.nativeEvent; - setCookies(data?.split(';')); + setCookies(data?.split('; ')); }; useFocusEffect( @@ -133,9 +126,7 @@ const Explore = ({ ytmLogin }: Props) => { { - saveItem(StorageKeys.YTMCOOKIES, null); - museStore.set('token', null); - auth.token = null; + saveItem(StorageKeys.YTMCOOKIES, null).then(initMuse); clear(); }} /> diff --git a/src/stores/initializeStores.ts b/src/stores/initializeStores.ts index d262a011..a8aaf8e7 100644 --- a/src/stores/initializeStores.ts +++ b/src/stores/initializeStores.ts @@ -7,7 +7,7 @@ import { initialize as initializeAppStore } from './appStore'; import { initialize as initializeRegexStore } from './regexStore'; import { initializeR128Gain } from '../utils/ffmpeg/r128Store'; import { dataSaverPlaylist, initCache } from '../utils/Cache'; -import { initialize as initializeMuse } from '@utils/muse'; +import { initMuse } from '../utils/muse'; import { useAPM } from './usePersistStore'; const { NoxModule } = NativeModules; @@ -42,7 +42,7 @@ export const initializeStores = async ({ default: break; } - await initializeMuse(); + await initMuse(); await initializeAppStore(); await initializeRegexStore(); await initializeR128Gain(); diff --git a/src/utils/muse.ts b/src/utils/muse.ts index 87fc6c81..112d93e0 100644 --- a/src/utils/muse.ts +++ b/src/utils/muse.ts @@ -1,34 +1,33 @@ -import { setup, MemoryStore } from 'libmuse'; +import * as crypto from 'expo-crypto'; +import { get_option } from 'libmuse'; -import { - getSecure as getItem, - saveSecure as setItem, -} from '@utils/ChromeStorageAPI'; +import { getSecure as getItem } from '@utils/ChromeStorageAPI'; +import { StorageKeys } from '@enums/Storage'; -const MUSE_KEY = 'museStore'; -class MyStore extends MemoryStore { - set(key: string, value: unknown) { - super.set(key, value); - setItem(MUSE_KEY, JSON.stringify(Object.fromEntries(this.map))); - } - async init() { - const v = await getItem(MUSE_KEY); - try { - this.map = new Map(Object.entries(JSON.parse(v ?? '{}'))); - } catch { - this.map = new Map(); - } - } - - reset() { - this.map = new Map(); - setItem(MUSE_KEY, null); - } -} - -export const museStore = new MyStore(); +const findCookie = (cookies: string, match: string) => { + const cookieArr = cookies.split('; ').map(v => v.split('=')); + return cookieArr.find(cookie => cookie[0] === match)?.[1]; +}; -export const initialize = async () => { - await museStore.init(); - setup({ store: museStore }); +export const initMuse = async ( + cookies: Promise = getItem(StorageKeys.YTMCOOKIES), +) => { + const sapisid = findCookie(await cookies, 'SAPISID') ?? ''; + // https://github.com/sigma67/ytmusicapi/blob/9ce284a7eae9c4cdc04bb098f7549cc5f1c80e22/ytmusicapi/helpers.py#L52 + const get_headers = async () => { + const now = new Date(); + const timems = now.getTime() + now.getTimezoneOffset() * 60 * 1000; + const timesec = Math.round(timems / 1000); + const SAPISIDHASH = await crypto.digestStringAsync( + crypto.CryptoDigestAlgorithm.SHA1, + `${timesec} ${sapisid} https://music.youtube.com`, + ); + return { + Authorization: `SAPISIDHASH ${timesec}_${SAPISIDHASH}`, + Cookie: await cookies, + }; + }; + const auth = get_option('auth'); + auth.get_headers = get_headers; + auth.requires_login = async () => false; };