diff --git a/android/app/build.gradle b/android/app/build.gradle index 5e558cd..ac7b2af 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -86,8 +86,8 @@ android { applicationId "com.vega" minSdkVersion rootProject.ext.minSdkVersion targetSdkVersion rootProject.ext.targetSdkVersion - versionCode 54 - versionName "2.4.1" + versionCode 55 + versionName "2.4.2" } signingConfigs { release { diff --git a/package.json b/package.json index ac81d74..e39e5bb 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "vega", - "version": "2.4.1", + "version": "2.4.2", "private": true, "scripts": { "android": "react-native run-android", diff --git a/src/app.json b/src/app.json index 441f6ec..d70e3b8 100644 --- a/src/app.json +++ b/src/app.json @@ -22,12 +22,12 @@ ] ], "slug": "vega", - "version": "2.4.0", + "version": "2.4.2", "sdkVersion": "51.0.0", "android": { "minSdkVersion": 24, "package": "com.vega", - "versionCode": 53 + "versionCode": 55 }, "platforms": ["ios", "android"] } diff --git a/src/components/DownloadBottomSheet.tsx b/src/components/DownloadBottomSheet.tsx index d33e70c..5883dc9 100644 --- a/src/components/DownloadBottomSheet.tsx +++ b/src/components/DownloadBottomSheet.tsx @@ -4,12 +4,15 @@ import { Pressable, TouchableOpacity, Dimensions, + ToastAndroid, } from 'react-native'; import React, {useEffect, useRef} from 'react'; import {Stream} from '../lib/providers/types'; import BottomSheet, {BottomSheetScrollView} from '@gorhom/bottom-sheet'; import {GestureHandlerRootView} from 'react-native-gesture-handler'; import SkeletonLoader from './Skeleton'; +import RNReactNativeHapticFeedback from 'react-native-haptic-feedback'; +import {Clipboard} from 'react-native'; type Props = { data: Stream[]; @@ -49,7 +52,7 @@ const DownloadBottomSheet = ({ { + RNReactNativeHapticFeedback.trigger('effectTick', { + enableVibrateFallback: true, + ignoreAndroidSystemSettings: false, + }); + Clipboard.setString(item.link); + ToastAndroid.show('Link copied', ToastAndroid.SHORT); + }} onPress={() => { onPress(item); bottomSheetRef.current?.close(); diff --git a/src/components/Hero.tsx b/src/components/Hero.tsx index 48f5267..fcfd285 100644 --- a/src/components/Hero.tsx +++ b/src/components/Hero.tsx @@ -11,17 +11,29 @@ import {HomeStackParamList, SearchStackParamList} from '../App'; import useContentStore from '../lib/zustand/contentStore'; import useHeroStore from '../lib/zustand/herostore'; import {Skeleton} from 'moti/skeleton'; -import {MmmkvCache} from '../lib/Mmkv'; +import {MMKV, MmmkvCache} from '../lib/Mmkv'; import {manifest} from '../lib/Manifest'; import {Info} from '../lib/providers/types'; import {Feather} from '@expo/vector-icons'; +import Ionicons from '@expo/vector-icons/Ionicons'; +import {DrawerLayout} from 'react-native-gesture-handler'; -function Hero() { +function Hero({ + isDrawerOpen, + drawerRef, +}: { + isDrawerOpen: boolean; + drawerRef: React.RefObject; +}) { const [post, setPost] = useState(); const [loading, setLoading] = useState(true); const [searchActive, setSearchActive] = useState(false); const {provider} = useContentStore(state => state); const {hero} = useHeroStore(state => state); + const [showHamburgerMenu] = useState( + MMKV.getBool('showHamburgerMenu') || false, + ); + const [isDrawerDisabled] = useState(MMKV.getBool('disableDrawer') || false); const navigation = useNavigation>(); const searchNavigation = @@ -74,7 +86,23 @@ function Hero() { }); return ( - + + {!searchActive && ( + + { + drawerRef.current?.openDrawer(); + }}> + + + + )} {searchActive && ( )} {!searchActive && ( - setSearchActive(true)}> + setSearchActive(true)}> )} + {/* episodesLinks */} - { + {episodeList.length > 0 && !episodeLoading && ( item.link + index} @@ -280,84 +280,86 @@ const SeasonList = ({ ); }} /> - } + )} {/* directLinks */} - {ActiveSeason?.directLinks && ActiveSeason?.directLinks.length > 0 && ( - - item.link + index} - renderItem={({item, index}) => { - // set titleSide to justify-center if title is too long - ActiveSeason?.directLinks?.length && - ActiveSeason?.directLinks?.length > 1 && - item?.title?.length > 27 && - setTitleSide('justify-start'); - return ( - 0 && + !episodeLoading && ( + + item.link + index} + renderItem={({item, index}) => { + // set titleSide to justify-center if title is too long + ActiveSeason?.directLinks?.length && + ActiveSeason?.directLinks?.length > 1 && + item?.title?.length > 27 && + setTitleSide('justify-start'); + return ( + - - - playHandler({ - link: item.link, - type: item.type || 'series', - primaryTitle: metaTitle, - secondaryTitle: item.title, - file: ( - metaTitle + - ActiveSeason.title + - item.title - ).replaceAll(/[^a-zA-Z0-9]/g, '_'), - }) - } - onLongPress={() => - onLongPressHandler(true, item.link, 'series') - }> - + + playHandler({ + link: item.link, + type: item.type || 'series', + primaryTitle: metaTitle, + secondaryTitle: item.title, + file: ( + metaTitle + + ActiveSeason.title + + item.title + ).replaceAll(/[^a-zA-Z0-9]/g, '_'), + }) + } + onLongPress={() => + onLongPressHandler(true, item.link, 'series') + }> + + + {ActiveSeason?.directLinks?.length && + ActiveSeason?.directLinks?.length > 1 + ? item.title?.length > 27 + ? item.title.slice(0, 27) + '...' + : item.title + : 'Play'} + + + 30 + ? metaTitle.slice(0, 30) + '... ' + item.title + : metaTitle + ' ' + item.title + } + fileName={( + metaTitle + + ActiveSeason.title + + item.title + ).replaceAll(/[^a-zA-Z0-9]/g, '_')} /> - - {ActiveSeason?.directLinks?.length && - ActiveSeason?.directLinks?.length > 1 - ? item.title?.length > 27 - ? item.title.slice(0, 27) + '...' - : item.title - : 'Play'} - - - 30 - ? metaTitle.slice(0, 30) + '... ' + item.title - : metaTitle + ' ' + item.title - } - fileName={( - metaTitle + - ActiveSeason.title + - item.title - ).replaceAll(/[^a-zA-Z0-9]/g, '_')} - /> + - - ); - }} - /> - - )} + ); + }} + /> + + )} {episodeLoading && ( + + )} {LinkList?.length === 0 && ( diff --git a/src/lib/Manifest.ts b/src/lib/Manifest.ts index 15f4b80..582f124 100644 --- a/src/lib/Manifest.ts +++ b/src/lib/Manifest.ts @@ -25,6 +25,7 @@ import {HiAnime} from './providers/hiAnime'; import {vadapavProvider} from './providers/vadapav'; import {netflixMirror} from './providers/netflixMirror'; import {kissKhProvider} from './providers/kissKh'; +import {cinemaLuxe} from './providers/cinemaLuxe'; export interface ProviderType { searchFilter?: string; @@ -82,4 +83,5 @@ export const manifest: Manifest = { hiAnime: HiAnime, vadapav: vadapavProvider, kissKh: kissKhProvider, + cinemaLuxe: cinemaLuxe, }; diff --git a/src/lib/constants.ts b/src/lib/constants.ts index 750bfab..b62bdf2 100644 --- a/src/lib/constants.ts +++ b/src/lib/constants.ts @@ -61,6 +61,12 @@ export const providersList: ProvidersList[] = [ type: 'global', flag: '🌏', }, + { + name: 'CinemaLuxe', + value: 'cinemaLuxe', + type: 'global', + flag: '🌏', + }, { name: 'NetflixMirror', value: 'netflixMirror', diff --git a/src/lib/downloader.ts b/src/lib/downloader.ts index b0466ed..9b85725 100644 --- a/src/lib/downloader.ts +++ b/src/lib/downloader.ts @@ -142,7 +142,7 @@ export const downloadManager = async ({ onlyAlertOnce: true, progress: { max: 100, - current: progress * 100, + current: Math.abs(progress) * 100, indeterminate: false, }, pressAction: { diff --git a/src/lib/providers/autoEmbed/allGetStream.ts b/src/lib/providers/autoEmbed/allGetStream.ts index a8bf96d..5d9abd2 100644 --- a/src/lib/providers/autoEmbed/allGetStream.ts +++ b/src/lib/providers/autoEmbed/allGetStream.ts @@ -54,17 +54,17 @@ export const allGetStream = async ( } ///// flimxy - // const flimxyStream = await getFlimxyStream(imdbId, season, episode, type); - // if (flimxyStream) { - // for (const quality in flimxyStream?.qualities) { - // streams.push({ - // server: 'Flimxy-' + quality, - // link: flimxyStream?.qualities?.[quality]?.url, - // type: flimxyStream?.qualities?.[quality]?.type || 'mp4', - // quality: quality as any, - // }); - // } - // } + const flimxyStream = await getFlimxyStream(imdbId, season, episode, type); + if (flimxyStream) { + for (const quality in flimxyStream?.qualities) { + streams.push({ + server: 'Flimxy-' + quality, + link: flimxyStream?.qualities?.[quality]?.url, + type: flimxyStream?.qualities?.[quality]?.type || 'mp4', + quality: quality as any, + }); + } + } // whvx orion const whvxStreamOrion = await getWhvxStream( @@ -153,7 +153,7 @@ export const allGetStream = async ( } ///// rive - await getRiveStream(tmdbId, episode, season, type, streams); + // await getRiveStream(tmdbId, episode, season, type, streams); ///// vidsrcrip await getVidSrcRip(tmdbId, season, episode, streams); diff --git a/src/lib/providers/autoEmbed/getRiveStream.ts b/src/lib/providers/autoEmbed/getRiveStream.ts index 1670222..7fa0f58 100644 --- a/src/lib/providers/autoEmbed/getRiveStream.ts +++ b/src/lib/providers/autoEmbed/getRiveStream.ts @@ -12,15 +12,15 @@ export async function getRiveStream( ) { const servers = ['vidcloud', 'upcloud', 'nova']; const baseUrl = await getBaseUrl('rive'); - const pxy = 'aHR0cHM6Ly9jcnMuMXByb3h5LndvcmtlcnMuZGV2Lz91cmw9'; + const cors = 'aHR0cHM6Ly9jcnMuMXByb3h5LndvcmtlcnMuZGV2Lz91cmw9'; const route = type === 'series' ? `/api/backendfetch?requestID=tvVideoProvider&id=${tmdId}&season=${season}&episode=${episode}&service=` : `/api/backendfetch?requestID=movieVideoProvider&id=${tmdId}&service=`; - const url = atob(pxy) + encodeURIComponent(baseUrl + route); + const url = atob(cors) + encodeURIComponent(baseUrl + route); await Promise.all( servers.map(async server => { - // console.log('Rive: ' + url + server); + console.log('Rive: ' + url + server); try { const res = await axios.get(url + server, {timeout: 4000}); console.log('Rive Stream: ' + url + server); @@ -37,6 +37,7 @@ export async function getRiveStream( }); }); } + console.log('Rive res: ', res.data?.data?.sources); res.data?.data?.sources.forEach((source: any) => { Streams.push({ server: source?.source + '-' + source?.quality, diff --git a/src/lib/providers/cinemaLuxe/clCatalog.ts b/src/lib/providers/cinemaLuxe/clCatalog.ts new file mode 100644 index 0000000..fc8ff8c --- /dev/null +++ b/src/lib/providers/cinemaLuxe/clCatalog.ts @@ -0,0 +1,20 @@ +export const clCatalog = [ + { + title: 'Trending', + filter: '/genre/latest-trending-releases/', + }, + { + title: 'Netflix', + filter: '/network/netflix/', + }, + { + title: 'Amazon Prime', + filter: '/network/prime-video/', + }, + { + title: 'Animation', + filter: '/genre/anime/', + }, +]; + +export const clGenresList = []; diff --git a/src/lib/providers/cinemaLuxe/clGetEpisodes.ts b/src/lib/providers/cinemaLuxe/clGetEpisodes.ts new file mode 100644 index 0000000..f770938 --- /dev/null +++ b/src/lib/providers/cinemaLuxe/clGetEpisodes.ts @@ -0,0 +1,46 @@ +import axios from 'axios'; +import * as cheerio from 'cheerio'; +import {headers} from '../headers'; +import {EpisodeLink} from '../types'; + +export const clsEpisodeLinks = async function ( + url: string, +): Promise { + try { + if (!url.includes('luxelinks')) { + const res = await axios.get(url, {headers}); + const data = res.data; + const encodedLink = data.match(/"link":"([^"]+)"/)[1]; + url = encodedLink ? atob(encodedLink) : url; + } + const res = await axios.get(url, {headers}); + const html = res.data; + let $ = cheerio.load(html); + const episodeLinks: EpisodeLink[] = []; + + $('.mb-center.maxbutton-1-center') + .first() + .parent() + .children() + .map((i, element) => { + const title = $(element).find('a').text(); + const link = $(element).find('a').attr('href'); + if (title && link && !title.includes('Batch')) { + episodeLinks.push({ + title: title + .replace(/\(\d{4}\)/, '') + .replace('Download', 'Movie') + .replace('⚡', '') + .trim(), + link, + }); + } + }); + + // console.log(episodeLinks); + return episodeLinks; + } catch (err) { + console.error(err); + return []; + } +}; diff --git a/src/lib/providers/cinemaLuxe/clGetMeta.ts b/src/lib/providers/cinemaLuxe/clGetMeta.ts new file mode 100644 index 0000000..08bd075 --- /dev/null +++ b/src/lib/providers/cinemaLuxe/clGetMeta.ts @@ -0,0 +1,70 @@ +import axios from 'axios'; +import * as cheerio from 'cheerio'; +import {headers} from '../headers'; +import {Info, Link} from '../types'; + +export const clGetInfo = async function (link: string): Promise { + try { + const url = link; + // console.log('url', url); + const res = await axios.get(url, {headers}); + const data = res.data; + const $ = cheerio.load(data); + const type = url.includes('tvshows') ? 'series' : 'movie'; + const imdbId = ''; + const title = url.split('/')[4].replace(/-/g, ' '); + const image = $('.g-item').find('a').attr('href') || ''; + const synopsis = $('.wp-content').text().trim(); + const tags = $('.sgeneros') + .children() + .map((i, element) => $(element).text()) + .get() + .slice(3); + const rating = Number($('#repimdb').find('strong').text()) + .toFixed(1) + .toString(); + + // console.log(title, image, synopsis); + + // Links + const links: Link[] = []; + + $('.mb-center.maxbutton-5-center').map((i, element) => { + const title = $(element) + .prev() + .text() + .replace('⬇Download', '') + .replace('⬇ Download', '') + .trim(); + const link = $(element).find('a').attr('href'); + if (title && link) { + links.push({ + title, + episodesLink: link, + quality: title?.match(/\d+P\b/)?.[0].replace('P', 'p') || '', + }); + } + }); + + return { + title, + tags, + rating, + synopsis, + image, + imdbId, + type, + linkList: links, + }; + } catch (err) { + console.error(err); + return { + title: '', + synopsis: '', + image: '', + imdbId: '', + type: 'movie', + linkList: [], + }; + } +}; diff --git a/src/lib/providers/cinemaLuxe/clGetPosts.ts b/src/lib/providers/cinemaLuxe/clGetPosts.ts new file mode 100644 index 0000000..215c8dc --- /dev/null +++ b/src/lib/providers/cinemaLuxe/clGetPosts.ts @@ -0,0 +1,70 @@ +import * as cheerio from 'cheerio'; +import {headers} from '../headers'; +import {Post} from '../types'; +import {getBaseUrl} from '../getBaseUrl'; + +export const clGetPosts = async function ( + filter: string, + page: number, + providerValue: string, + signal: AbortSignal, +): Promise { + const baseUrl = await getBaseUrl('cinemaLuxe'); + // console.log(baseUrl); + const url = `${baseUrl + filter}page/${page}/`; + console.log('multiUrl', url); + + return posts(url, signal); +}; + +export const clGetPostsSearch = async function ( + searchQuery: string, + page: number, + providerValue: string, + signal: AbortSignal, +): Promise { + const baseUrl = await getBaseUrl('cinemaLuxe'); + // console.log(baseUrl); + const url = `${baseUrl}/page/${page}/?s=${searchQuery}`; + console.log('multiUrl', url); + + return posts(url, signal); +}; + +async function posts(url: string, signal: AbortSignal): Promise { + try { + const res = await fetch(url, {headers, signal}); + const data = await res.text(); + const $ = cheerio.load(data); + const catalog: Post[] = []; + $('.item.tvshows,.item.movies').map((i, element) => { + const title = $(element).find('.poster').find('img').attr('alt'); + const link = $(element).find('.poster').find('a').attr('href'); + const image = $(element).find('.poster').find('img').attr('data-src'); + if (title && link && image) { + catalog.push({ + title: title, + link: link, + image: image, + }); + } + }); + $('.result-item').map((i, element) => { + const title = $(element).find('.thumbnail').find('img').attr('alt'); + const link = $(element).find('.thumbnail').find('a').attr('href'); + const image = $(element).find('.thumbnail').find('img').attr('data-src'); + if (title && link && image) { + catalog.push({ + title: title, + link: link, + image: image, + }); + } + }); + // console.log(catalog); + return catalog; + } catch (err) { + console.error('cinemaluxe error ', err); + return []; + } +} diff --git a/src/lib/providers/cinemaLuxe/clGetSteam.ts b/src/lib/providers/cinemaLuxe/clGetSteam.ts new file mode 100644 index 0000000..f4e0420 --- /dev/null +++ b/src/lib/providers/cinemaLuxe/clGetSteam.ts @@ -0,0 +1,34 @@ +import axios from 'axios'; +import {Stream} from '../types'; +import {hubcloudExtracter} from '../hubcloudExtractor'; +import {gdFlixExtracter} from '../gdflixExtractor'; + +export const clGetStream = async ( + link: string, + type: string, + signal: AbortSignal, +): Promise => { + try { + let newLink = link; + if (!link.includes('hubcloud') && !link.includes('gdflix')) { + console.log('link', link); + const res = await axios.get(link); + const data = res.data; + const encodedLink = data.match(/"link":"([^"]+)"/)[1]; + newLink = encodedLink ? atob(encodedLink) : link; + } + console.log('newLink', newLink); + if (newLink.includes('gdflix')) { + const sreams = await gdFlixExtracter(newLink, signal); + return sreams; + } + const res2 = await axios.get(newLink, {signal}); + const data2 = res2.data; + newLink = data2.match(/location\.replace\('([^']+)'/)?.[1] || newLink; + const hubCloudLinks = await hubcloudExtracter(newLink, signal); + return hubCloudLinks; + } catch (err) { + console.error(err); + return []; + } +}; diff --git a/src/lib/providers/cinemaLuxe/index.ts b/src/lib/providers/cinemaLuxe/index.ts new file mode 100644 index 0000000..3a9d90a --- /dev/null +++ b/src/lib/providers/cinemaLuxe/index.ts @@ -0,0 +1,16 @@ +import {clGenresList, clCatalog} from './clCatalog'; +import {clGetInfo} from './clGetMeta'; +import {clsEpisodeLinks} from './clGetEpisodes'; +import {clGetPostsSearch, clGetPosts} from './clGetPosts'; +import {ProviderType} from '../../Manifest'; +import {clGetStream} from './clGetSteam'; + +export const cinemaLuxe: ProviderType = { + catalog: clCatalog, + genres: clGenresList, + GetHomePosts: clGetPosts, + GetMetaData: clGetInfo, + GetSearchPosts: clGetPostsSearch, + GetEpisodeLinks: clsEpisodeLinks, + GetStream: clGetStream, +}; diff --git a/src/lib/providers/gdflixExtractor.ts b/src/lib/providers/gdflixExtractor.ts new file mode 100644 index 0000000..245fbbb --- /dev/null +++ b/src/lib/providers/gdflixExtractor.ts @@ -0,0 +1,158 @@ +import axios from 'axios'; +import * as cheerio from 'cheerio'; +import {Stream} from './types'; +import {headers} from './headers'; + +export async function gdFlixExtracter(link: string, signal: AbortSignal) { + try { + const streamLinks: Stream[] = []; + const res = await axios(`${link}`, {headers, signal}); + console.log('gdFlixExtracter', link); + const data = res.data; + const $drive = cheerio.load(data); + // try { + // const resumeBot = $drive('.fab.fa-artstation').prev().attr('href') || ''; + // console.log('resumeBot', resumeBot); + // const resumeBotRes = await axios.get(resumeBot, {headers}); + // const resumeBotToken = resumeBotRes.data.match( + // /formData\.append\('token', '([a-f0-9]+)'\)/, + // )[1]; + // const resumeBotBody = new FormData(); + // resumeBotBody.append('token', resumeBotToken); + // const resumeBotPath = resumeBotRes.data.match( + // /fetch\('\/download\?id=([a-zA-Z0-9\/+]+)'/, + // )[1]; + // const resumeBotBaseUrl = resumeBot.split('/download')[0]; + // // console.log( + // // 'resumeBotPath', + // // resumeBotBaseUrl + '/download?id=' + resumeBotPath, + // // ); + // // console.log('resumeBotBody', resumeBotToken); + + // const resumeBotDownload = await fetch( + // resumeBotBaseUrl + '/download?id=' + resumeBotPath, + // { + // method: 'POST', + // body: resumeBotBody, + // headers: { + // Referer: resumeBot, + // Cookie: 'PHPSESSID=7e9658ce7c805dab5bbcea9046f7f308', + // }, + // }, + // ); + // const resumeBotDownloadData = await resumeBotDownload.json(); + // console.log('resumeBotDownloadData', resumeBotDownloadData.url); + // streamLinks.push({ + // server: 'ResumeBot', + // link: resumeBotDownloadData.url, + // type: 'mkv', + // }); + // } catch (err) { + // console.log('ResumeBot link not found', err); + // } + + /// resume cloud + try { + const baseUrl = link.split('/').slice(0, 3).join('/'); + const resumeDrive = $drive('.btn-secondary').attr('href') || ''; + console.log('resumeDrive', resumeDrive); + if (resumeDrive.includes('indexbot')) { + const resumeBotRes = await axios.get(resumeDrive, {headers}); + const resumeBotToken = resumeBotRes.data.match( + /formData\.append\('token', '([a-f0-9]+)'\)/, + )[1]; + const resumeBotBody = new FormData(); + resumeBotBody.append('token', resumeBotToken); + const resumeBotPath = resumeBotRes.data.match( + /fetch\('\/download\?id=([a-zA-Z0-9\/+]+)'/, + )[1]; + const resumeBotBaseUrl = resumeDrive.split('/download')[0]; + // console.log( + // 'resumeBotPath', + // resumeBotBaseUrl + '/download?id=' + resumeBotPath, + // ); + // console.log('resumeBotBody', resumeBotToken); + + const resumeBotDownload = await fetch( + resumeBotBaseUrl + '/download?id=' + resumeBotPath, + { + method: 'POST', + body: resumeBotBody, + headers: { + Referer: resumeDrive, + Cookie: 'PHPSESSID=7e9658ce7c805dab5bbcea9046f7f308', + }, + }, + ); + const resumeBotDownloadData = await resumeBotDownload.json(); + console.log('resumeBotDownloadData', resumeBotDownloadData.url); + streamLinks.push({ + server: 'ResumeBot', + link: resumeBotDownloadData.url, + type: 'mkv', + }); + } else { + const url = baseUrl + resumeDrive; + const resumeDriveRes = await axios.get(url, {headers}); + const resumeDriveHtml = resumeDriveRes.data; + const $resumeDrive = cheerio.load(resumeDriveHtml); + const resumeLink = $resumeDrive('.btn-success').attr('href'); + // console.log('resumeLink', resumeLink); + if (resumeLink) { + streamLinks.push({ + server: 'ResumeCloud', + link: resumeLink, + type: 'mkv', + }); + } + } + } catch (err) { + console.log('Resume link not found'); + } + + //instant link + try { + const seed = $drive('.btn-danger').attr('href') || ''; + console.log('seed', seed); + if (!seed.includes('?url=')) { + const newLinkRes = await axios.head(seed, {headers, signal}); + console.log('newLinkRes', newLinkRes.request?.responseURL); + const newLink = + newLinkRes.request?.responseURL?.split('?url=')?.[1] || seed; + streamLinks.push({server: 'G-Drive', link: newLink, type: 'mkv'}); + } else { + const instantToken = seed.split('=')[1]; + // console.log('InstantToken', instantToken); + const InstantFromData = new FormData(); + InstantFromData.append('keys', instantToken); + const videoSeedUrl = seed.split('/').slice(0, 3).join('/') + '/api'; + // console.log('videoSeedUrl', videoSeedUrl); + const instantLinkRes = await fetch(videoSeedUrl, { + method: 'POST', + body: InstantFromData, + headers: { + 'x-token': videoSeedUrl, + }, + }); + const instantLinkData = await instantLinkRes.json(); + // console.log('instantLinkData', instantLinkData); + if (instantLinkData.error === false) { + const instantLink = instantLinkData.url; + streamLinks.push({ + server: 'Gdrive-Instant', + link: instantLink, + type: 'mkv', + }); + } else { + console.log('Instant link not found', instantLinkData); + } + } + } catch (err) { + console.log('Instant link not found', err); + } + return streamLinks; + } catch (error) { + console.log('hubcloudExtracter error: ', error); + return []; + } +} diff --git a/src/lib/providers/getBaseUrl.ts b/src/lib/providers/getBaseUrl.ts index 89a005e..35947ae 100644 --- a/src/lib/providers/getBaseUrl.ts +++ b/src/lib/providers/getBaseUrl.ts @@ -1,7 +1,7 @@ import {MmmkvCache} from '../Mmkv'; -// 12 hours -const expireTime = 43200000; +// 1 hour +const expireTime = 60 * 60 * 1000; export const getBaseUrl = async (providerValue: string) => { try { diff --git a/src/lib/providers/hubcloudExtractor.ts b/src/lib/providers/hubcloudExtractor.ts index ed75d2c..fa3b8bf 100644 --- a/src/lib/providers/hubcloudExtractor.ts +++ b/src/lib/providers/hubcloudExtractor.ts @@ -16,9 +16,13 @@ export async function hubcloudExtracter(link: string, signal: AbortSignal) { const streamLinks: Stream[] = []; const vLinkRes = await axios(`${link}`, {headers, signal}); const vLinkText = vLinkRes.data; + const $vLink = cheerio.load(vLinkText); const vLinkRedirect = vLinkText.match(/var\s+url\s*=\s*'([^']+)';/) || []; const vcloudLink = - decode(vLinkRedirect[1]?.split('r=')?.[1]) || vLinkRedirect[1] || link; + decode(vLinkRedirect[1]?.split('r=')?.[1]) || + vLinkRedirect[1] || + $vLink('.fa-file-download.fa-lg').parent().attr('href') || + link; console.log('vcloudLink', vcloudLink); const vcloudRes = await fetch(vcloudLink, { @@ -27,6 +31,7 @@ export async function hubcloudExtracter(link: string, signal: AbortSignal) { redirect: 'follow', }); const $ = cheerio.load(await vcloudRes.text()); + console.log('vcloudRes', vcloudRes.url); const linkClass = $('.btn-success.btn-lg.h6,.btn-danger,.btn-secondary'); for (const element of linkClass) { diff --git a/src/lib/providers/netflixMirror/nfGetInfo.ts b/src/lib/providers/netflixMirror/nfGetInfo.ts index a7c97ad..63bcda0 100644 --- a/src/lib/providers/netflixMirror/nfGetInfo.ts +++ b/src/lib/providers/netflixMirror/nfGetInfo.ts @@ -6,10 +6,11 @@ export const nfGetInfo = async function (link: string): Promise { try { const url = link; console.log('nfifo', url); - const res = await axios.get(url, { - headers: headers, + const res = await fetch(url, { + headers, + credentials: 'omit', }); - const data = res.data; + const data = await res.json(); const id = link.split('id=')[1]?.split('&')[0]; const meta = { title: data.title, @@ -33,7 +34,7 @@ export const nfGetInfo = async function (link: string): Promise { } else { linkList.push({ title: meta.title, - directLinks: [{link: link, title: 'Movie', type: 'movie'}], + directLinks: [{link: id, title: 'Movie', type: 'movie'}], }); } diff --git a/src/lib/providers/netflixMirror/nfGetPost.ts b/src/lib/providers/netflixMirror/nfGetPost.ts index 9f31d0c..b318df3 100644 --- a/src/lib/providers/netflixMirror/nfGetPost.ts +++ b/src/lib/providers/netflixMirror/nfGetPost.ts @@ -20,8 +20,8 @@ export const nfGetPost = async function ( const url = `${baseUrl + filter}`; // console.log(url); - const res = await axios.get(url, {headers, signal}); - const data = res.data; + const res = await fetch(url, {headers, signal, credentials: 'omit'}); + const data = await res.text(); const $ = cheerio.load(data); $('a.post-data').map((i, element) => { const title = ''; diff --git a/src/lib/providers/netflixMirror/nfGetSteam.ts b/src/lib/providers/netflixMirror/nfGetSteam.ts index 12d136c..4b89eba 100644 --- a/src/lib/providers/netflixMirror/nfGetSteam.ts +++ b/src/lib/providers/netflixMirror/nfGetSteam.ts @@ -9,10 +9,12 @@ export const nfGetStream = async (id: string): Promise => { const url = `${baseUrl}/playlist.php?id=${id}&t=${Math.round( new Date().getTime() / 1000, )}`; - const res = await axios.get(url, { + const res = await fetch(url, { headers: headers, + credentials: 'omit', }); - const data = res.data?.[0]; + const resJson = await res.json(); + const data = resJson?.[0]; const streamLinks: Stream[] = []; data?.sources.forEach((source: any) => { streamLinks.push({ @@ -21,6 +23,7 @@ export const nfGetStream = async (id: string): Promise => { type: 'm3u8', headers: { Referer: baseUrl, + origin: baseUrl, }, }); }); diff --git a/src/lib/providers/netflixMirror/nfHeaders.ts b/src/lib/providers/netflixMirror/nfHeaders.ts index 7460330..fbb18d9 100644 --- a/src/lib/providers/netflixMirror/nfHeaders.ts +++ b/src/lib/providers/netflixMirror/nfHeaders.ts @@ -1,18 +1,6 @@ export const headers = { - Accept: - 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7', - 'Accept-Encoding': 'gzip, deflate', - 'Accept-Language': 'en-US,en;q=0.9', - Connection: 'keep-alive', Cookie: - 'HstCfa1188575=1722858787120; HstCmu1188575=1722858787120; _dtspv={"ss":"6tcf6y824c","st":1722858790.15,"sl":1722858790.15,"u1":1722858790.15,"u3":1722858790.15,"pv":1,"c":{"cc":"in","pl":"m","b":"chrome@113"}}; __dtsu=6D0017228587928C04F132747F446C6C; HstCnv1188575=2; HstCns1188575=2; HstCla1188575=1723028120961; HstPn1188575=2; HstPt1188575=4', - Host: 'iosmirror.cc', - 'Sec-Fetch-Dest': 'document', - 'Sec-Fetch-Mode': 'navigate', - 'Sec-Fetch-Site': 'none', - 'Sec-Fetch-User': '?1', - 'Upgrade-Insecure-Requests': '1', + 'hd=on; lang=hin; SE81149450=81220014; t_hash_t=0ef922dd880144760184234a679f6a5d%3A%3A271c7b007bfd59a495f9dada46e01dcd%3A%3A1725781321%3A%3Ani; SE81707950=81726576; t_hash=969e1e9bd2212c1e411b13f29cf86b58%3A%3A1725966315%3A%3Ani; SE81285617=81285624; recentplay=SE81285617-81282732-SE81707950-70213514-235527-SE81149450', 'User-Agent': - 'Mozilla/5.0 (Linux; Android 14; sdk_gphone64_x86_64 Build/UE1A.230829.036.A2; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/113.0.5672.136 Mobile Safari/537.36 /OS.Gatu v1.0', - 'X-Requested-With': 'com.example.netflixmirror', + 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36 Edg/128.0.0.0', }; diff --git a/src/screens/home/Home.tsx b/src/screens/home/Home.tsx index cbe1dce..6e30109 100644 --- a/src/screens/home/Home.tsx +++ b/src/screens/home/Home.tsx @@ -38,6 +38,7 @@ const Home = ({}: Props) => { const recentlyWatched = useWatchHistoryStore(state => state).history; const ShowRecentlyWatched = MMKV.getBool('showRecentlyWatched'); const drawer = useRef(null); + const [isDrawerOpen, setIsDrawerOpen] = useState(false); const disableDrawer = MMKV.getBool('disableDrawer') || false; const {provider} = useContentStore(state => state); @@ -141,6 +142,15 @@ const Home = ({}: Props) => { drawerType="slide" edgeWidth={70} useNativeAnimations={false} + // onDrawerOpen={() => setIsDrawerOpen(true)} + // onDrawerClose={() => setIsDrawerOpen(false)} + // onDrawerStateChanged={(newState, drawerWillShow) => { + // if (drawerWillShow) { + // setIsDrawerOpen(true); + // } else { + // setIsDrawerOpen(false); + // } + // }} ref={drawer} drawerBackgroundColor={'black'} renderNavigationView={() => @@ -168,7 +178,7 @@ const Home = ({}: Props) => { }} /> }> - + {!loading && recentlyWatched?.length > 0 && diff --git a/src/screens/settings/Preference.tsx b/src/screens/settings/Preference.tsx index fee2373..51e405a 100644 --- a/src/screens/settings/Preference.tsx +++ b/src/screens/settings/Preference.tsx @@ -40,6 +40,10 @@ const Preferences = () => { MMKV.getBool('showMediaControls') || true, ); + const [showHamburgerMenu, setShowHamburgerMenu] = useState( + MMKV.getBool('showHamburgerMenu') || false, + ); + return ( @@ -151,6 +155,28 @@ const Preferences = () => { /> + {/* show hamburger menu */} + {!disableDrawer && ( + + + Show Hamburger Menu + + + { + MMKV.setBool('showHamburgerMenu', !showHamburgerMenu); + setShowHamburgerMenu(!showHamburgerMenu); + ToastAndroid.show( + 'Restart App to Apply Changes', + ToastAndroid.SHORT, + ); + }} + /> + + )} + {/* show media controls */} @@ -179,6 +205,10 @@ const Preferences = () => { onValueChange={() => { MMKV.setBool('showRecentlyWatched', !showRecentlyWatched); setShowRecentlyWatched(!showRecentlyWatched); + ToastAndroid.show( + 'Restart App to Apply Changes', + ToastAndroid.SHORT, + ); }} />