diff --git a/android/app/build.gradle b/android/app/build.gradle
index 76a6412..1fca73a 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 45
- versionName "2.2.2"
+ versionCode 46
+ versionName "2.2.3"
}
signingConfigs {
release {
diff --git a/package.json b/package.json
index d5d8cea..f9c4bd6 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "vega",
- "version": "2.2.2",
+ "version": "2.2.3",
"private": true,
"scripts": {
"android": "react-native run-android",
diff --git a/src/App.tsx b/src/App.tsx
index 32f1e9c..ebda54e 100644
--- a/src/App.tsx
+++ b/src/App.tsx
@@ -21,6 +21,7 @@ import About, {checkForUpdate} from './screens/settings/About';
import {MMKV} from './lib/Mmkv';
import BootSplash from 'react-native-bootsplash';
import {enableFreeze, enableScreens} from 'react-native-screens';
+import Preferences from './screens/settings/Preference';
enableScreens(true);
enableFreeze(true);
@@ -60,6 +61,7 @@ export type SettingsStackParamList = {
Settings: undefined;
DisableProviders: undefined;
About: undefined;
+ Preferences: undefined;
};
const Tab = createBottomTabNavigator();
const App = () => {
@@ -135,6 +137,7 @@ const App = () => {
component={DisableProviders}
/>
+
);
}
@@ -208,7 +211,7 @@ const App = () => {
useEffect(() => {
if (MMKV.getBool('autoCheckUpdate') !== false) {
- checkForUpdate(() => {}, MMKV.getBool('autoDownload') || false);
+ checkForUpdate(() => {}, MMKV.getBool('autoDownload') || false, false);
}
}, []);
diff --git a/src/components/Hero.tsx b/src/components/Hero.tsx
index c5393a3..c673ff8 100644
--- a/src/components/Hero.tsx
+++ b/src/components/Hero.tsx
@@ -76,17 +76,24 @@ function Hero() {
setSearchActive(false)}
autoFocus={true}
onSubmitEditing={e => {
- searchNavigation.navigate('ScrollList', {
- providerValue: provider.value,
- filter: 'query' + e.nativeEvent.text,
- title: `${provider.name}`,
- });
+ if (e.nativeEvent.text.includes('https://')) {
+ navigation.navigate('Info', {
+ link: e.nativeEvent.text,
+ });
+ } else {
+ searchNavigation.navigate('ScrollList', {
+ providerValue: provider.value,
+ filter: 'query' + e.nativeEvent.text,
+ title: `${provider.name}`,
+ });
+ }
}}
placeholder={`Search in ${provider.name}`}
className="w-[95%] px-4 h-10 rounded-full border-white border"
diff --git a/src/components/SeasonList.tsx b/src/components/SeasonList.tsx
index 23881a1..181ec33 100644
--- a/src/components/SeasonList.tsx
+++ b/src/components/SeasonList.tsx
@@ -25,6 +25,7 @@ import {manifest} from '../lib/Manifest';
import SharedGroupPreferences from 'react-native-shared-group-preferences';
import RNReactNativeHapticFeedback from 'react-native-haptic-feedback';
import Feather from '@expo/vector-icons/Feather';
+import useWatchHistoryStore from '../lib/zustand/watchHistrory';
const SeasonList = ({
LinkList,
@@ -32,12 +33,18 @@ const SeasonList = ({
metaTitle,
providerValue,
refreshing,
+ routeParams,
}: {
LinkList: Link[];
poster: string;
metaTitle: string;
providerValue: string;
refreshing?: boolean;
+ routeParams: Readonly<{
+ link: string;
+ provider?: string;
+ poster?: string;
+ }>;
}) => {
const navigation =
useNavigation>();
@@ -57,6 +64,8 @@ const SeasonList = ({
LinkList[0],
);
+ const {addItem} = useWatchHistoryStore(state => state);
+
useEffect(() => {
const fetchList = async () => {
if (!ActiveSeason?.episodesLink) {
@@ -158,7 +167,14 @@ const SeasonList = ({
return;
}
};
+
const playHandler = async ({link, type, title, file}: playHandlerProps) => {
+ addItem({
+ link: routeParams.link,
+ title: metaTitle,
+ image: routeParams.poster!,
+ provider: providerValue,
+ });
const externalPlayer = MMKV.getString('externalPlayer');
const downloaded = await ifExists(file);
if (externalPlayer && !downloaded) {
diff --git a/src/components/Slider.tsx b/src/components/Slider.tsx
index e3497b8..c122ed1 100644
--- a/src/components/Slider.tsx
+++ b/src/components/Slider.tsx
@@ -1,13 +1,15 @@
-import {Image, Text, TouchableOpacity, View} from 'react-native';
+import {Image, Pressable, Text, TouchableOpacity, View} from 'react-native';
import React from 'react';
import type {Post} from '../lib/providers/types';
import {NativeStackNavigationProp} from '@react-navigation/native-stack';
import {useNavigation} from '@react-navigation/native';
import {HomeStackParamList} from '../App';
-import {Skeleton} from 'moti/skeleton';
import useContentStore from '../lib/zustand/contentStore';
import {FlashList} from '@shopify/flash-list';
import SkeletonLoader from './Skeleton';
+import ReactNativeHapticFeedback from 'react-native-haptic-feedback';
+import AntDesign from '@expo/vector-icons/AntDesign';
+import useWatchHistoryStore from '../lib/zustand/watchHistrory';
export default function Slider({
isLoading,
@@ -25,21 +27,25 @@ export default function Slider({
const {provider} = useContentStore(state => state);
const navigation =
useNavigation>();
+ const [isSelected, setSelected] = React.useState('');
+ const {removeItem} = useWatchHistoryStore(state => state);
return (
-
+ setSelected('')} className="gap-3 mt-7">
{title}
-
- navigation.navigate('ScrollList', {
- title: title,
- filter: filter,
- providerValue: providerValue,
- })
- }>
- more
-
+ {filter && (
+
+ navigation.navigate('ScrollList', {
+ title: title,
+ filter: filter,
+ providerValue: providerValue,
+ })
+ }>
+ more
+
+ )}
{isLoading ? (
@@ -57,18 +63,29 @@ export default function Slider({
estimatedItemSize={30}
showsHorizontalScrollIndicator={false}
data={posts}
+ extraData={isSelected}
horizontal
contentContainerStyle={{paddingHorizontal: 3, paddingTop: 7}}
renderItem={({item}) => (
+ onLongPress={e => {
+ e.stopPropagation();
+ ReactNativeHapticFeedback.trigger('effectClick', {
+ enableVibrateFallback: true,
+ ignoreAndroidSystemSettings: false,
+ });
+ setSelected(item.link);
+ }}
+ onPress={e => {
+ e.stopPropagation();
+ setSelected('');
navigation.navigate('Info', {
link: item.link,
- provider: providerValue || provider?.value,
+ provider: item.provider || providerValue || provider?.value,
poster: item?.image,
- })
- }>
+ });
+ }}>
+ {isSelected === item.link && (
+
+ {
+ console.log('remove', item);
+ setSelected('');
+ removeItem(item);
+ }}
+ />
+
+ )}
{item.title.length > 24
@@ -98,6 +129,6 @@ export default function Slider({
keyExtractor={item => item.link}
/>
)}
-
+
);
}
diff --git a/src/lib/Manifest.ts b/src/lib/Manifest.ts
index 7e078de..7fb2b5d 100644
--- a/src/lib/Manifest.ts
+++ b/src/lib/Manifest.ts
@@ -16,7 +16,7 @@ import {modGetEpisodeLinks} from './providers/mod/modGetEpisodesList';
import {modGetStream} from './providers/mod/modGetStream';
/// uhd
-import {uhdCatalogList} from './providers/uhd/uhCtatalog';
+import {uhdCatalogList, uhdGenresList} from './providers/uhd/uhCtatalog';
import {uhdGetPosts} from './providers/uhd/uhdGetPosts';
import getUhdInfo from './providers/uhd/getUhdInfo';
import {uhdGetStream} from './providers/uhd/uhdGetStream';
@@ -150,7 +150,7 @@ export const manifest: Manifest = {
},
uhd: {
catalog: uhdCatalogList,
- genres: [],
+ genres: uhdGenresList,
blurImage: true,
nonStreamableServer: ['Gdrive-Instant'],
getStream: uhdGetStream,
diff --git a/src/lib/getHomepagedata.ts b/src/lib/getHomepagedata.ts
index eb6b5f4..d9c9b56 100644
--- a/src/lib/getHomepagedata.ts
+++ b/src/lib/getHomepagedata.ts
@@ -1,11 +1,6 @@
import {Content} from './zustand/contentStore';
import {manifest} from './Manifest';
-
-export interface Post {
- title: string;
- link: string;
- image: string;
-}
+import {Post} from './providers/types';
export interface HomePageData {
title: string;
diff --git a/src/lib/providers/dramacool/dcGetPosts.ts b/src/lib/providers/dramacool/dcGetPosts.ts
index 0fea4db..696fdf5 100644
--- a/src/lib/providers/dramacool/dcGetPosts.ts
+++ b/src/lib/providers/dramacool/dcGetPosts.ts
@@ -12,10 +12,11 @@ export const dcGetPosts = async function (
): Promise {
try {
const urlRes = await axios.get(
- 'https://consumet8.vercel.app/movies/dramacool/info?id=drama-detail/shogun',
+ 'https://himanshu8443.github.io/providers/modflix.json',
);
- const resData = urlRes.data.episodes[0].url;
- const baseUrl = resData.split('/').slice(0, 3).join('/');
+ const dataRes = urlRes.data;
+ // console.log(dataRes.hdhub.url);
+ const baseUrl = dataRes?.dc?.url;
console.log('dcBaseUrl', baseUrl);
const url = filter.includes('query')
? `${baseUrl}/search?type=movies&keyword=${filter.replace(
diff --git a/src/lib/providers/mod/catalog.ts b/src/lib/providers/mod/catalog.ts
index 53a07bd..ba79f18 100644
--- a/src/lib/providers/mod/catalog.ts
+++ b/src/lib/providers/mod/catalog.ts
@@ -18,6 +18,22 @@ export const catalogList = [
];
export const modGenresList = [
+ {
+ title: 'Apple TV+',
+ filter: '/ott/apple-tv',
+ },
+ {
+ title: 'Disney+',
+ filter: '/ott/disney-plus',
+ },
+ {
+ title: 'Hulu',
+ filter: '/ott/hulu',
+ },
+ {
+ title: 'Crunchyroll',
+ filter: '/ott/crunchyroll',
+ },
{
title: 'Action',
filter: '/movies-by-genre/action/',
diff --git a/src/lib/providers/mod/header.ts b/src/lib/providers/mod/header.ts
index fe0c37d..f6a6dcf 100644
--- a/src/lib/providers/mod/header.ts
+++ b/src/lib/providers/mod/header.ts
@@ -10,7 +10,8 @@ export const headers = {
'sec-ch-ua-platform': '"Windows"',
'Sec-Fetch-Dest': 'document',
'Sec-Fetch-Mode': 'navigate',
- Referer: 'https://moviesmod.live/',
+ Referer: 'https://moviesmod.band/',
+ Cookie: 'popads_user_id=6ba8fe60a481387a3249f05aa058822d',
'Sec-Fetch-Site': 'none',
'Sec-Fetch-User': '?1',
'Upgrade-Insecure-Requests': '1',
diff --git a/src/lib/providers/mod/modGetStream.ts b/src/lib/providers/mod/modGetStream.ts
index bb68161..d925faf 100644
--- a/src/lib/providers/mod/modGetStream.ts
+++ b/src/lib/providers/mod/modGetStream.ts
@@ -74,42 +74,46 @@ export const modGetStream = async (
const driveRes = await axios.get(driveLink, {headers});
const driveHtml = driveRes.data;
const $drive = cheerio.load(driveHtml);
- const resumeBot = $drive('.btn.btn-light').attr('href') || '';
- 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);
- servers.push({
- server: 'ResumeBot',
- link: resumeBotDownloadData.url,
- type: 'mkv',
- });
+ try {
+ const resumeBot = $drive('.btn.btn-light').attr('href') || '';
+ 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);
+ servers.push({
+ server: 'ResumeBot',
+ link: resumeBotDownloadData.url,
+ type: 'mkv',
+ });
+ } catch (err) {
+ console.log('ResumeBot link not found', err);
+ }
// CF workers type 1
try {
const cfWorkersLink = driveLink.replace('/file', '/wfile') + '?type=1';
@@ -199,7 +203,7 @@ const isDriveLink = async (ddl: string) => {
/window\.location\.replace\("([^"]+)"\)/,
)[1];
const mainUrl = ddl.split('/')[2];
- console.log(`https://${mainUrl}${path}`);
+ console.log(`driveUrl = https://${mainUrl}${path}`);
return `https://${mainUrl}${path}`;
} else {
return ddl;
diff --git a/src/lib/providers/multi/multiGetStream.ts b/src/lib/providers/multi/multiGetStream.ts
index ed33c1e..4eb3a69 100644
--- a/src/lib/providers/multi/multiGetStream.ts
+++ b/src/lib/providers/multi/multiGetStream.ts
@@ -34,30 +34,69 @@ export const multiGetStream = async (
});
const playerData = await playerRes.json();
console.log('playerData', playerData);
- const ifameUrl =
+ let ifameUrl =
playerData?.embed_url?.match(/
-
+
{meta?.description
? meta?.description.length > 180
? meta?.description.slice(0, 180) + '...'
@@ -365,6 +365,7 @@ export default function Info({route, navigation}: Props): React.JSX.Element {
}
poster={meta?.logo || ''}
metaTitle={meta?.name || info?.title}
+ routeParams={route.params}
/>
)}
diff --git a/src/screens/settings/About.tsx b/src/screens/settings/About.tsx
index ff932af..01318ee 100644
--- a/src/screens/settings/About.tsx
+++ b/src/screens/settings/About.tsx
@@ -92,6 +92,7 @@ const downloadUpdate = async (url: string, name: string) => {
export const checkForUpdate = async (
setUpdateLoading: React.Dispatch>,
autoDownload: boolean,
+ showToast: boolean = true,
) => {
setUpdateLoading(true);
try {
@@ -116,7 +117,7 @@ export const checkForUpdate = async (
]);
console.log('version', data.tag_name.replace('v', ''), pkg.version);
} else {
- ToastAndroid.show('App is up to date', ToastAndroid.SHORT);
+ showToast && ToastAndroid.show('App is up to date', ToastAndroid.SHORT);
console.log('version', data.tag_name.replace('v', ''), pkg.version);
}
} catch (error) {
diff --git a/src/screens/settings/Preference.tsx b/src/screens/settings/Preference.tsx
new file mode 100644
index 0000000..cbcc780
--- /dev/null
+++ b/src/screens/settings/Preference.tsx
@@ -0,0 +1,104 @@
+import {View, Text, Switch, ScrollView, TouchableOpacity} from 'react-native';
+import React, {useState} from 'react';
+import {MMKV} from '../../lib/Mmkv';
+import MaterialCommunityIcons from '@expo/vector-icons/MaterialCommunityIcons';
+import RNReactNativeHapticFeedback from 'react-native-haptic-feedback';
+import useWatchHistoryStore from '../../lib/zustand/watchHistrory';
+
+const Preferences = () => {
+ const [showRecentlyWatched, setShowRecentlyWatched] = useState(
+ MMKV.getBool('showRecentlyWatched') || false,
+ );
+ const {clearHistory} = useWatchHistoryStore(state => state);
+
+ const [ExcludedQualities, setExcludedQualities] = useState(
+ MMKV.getArray('ExcludedQualities') || [],
+ );
+ return (
+
+
+ Preference
+
+
+
+ {/* show recentlyWatched */}
+
+
+ Show Recently Watched
+
+
+ {
+ MMKV.setBool('showRecentlyWatched', !showRecentlyWatched);
+ setShowRecentlyWatched(!showRecentlyWatched);
+ }}
+ />
+
+
+ {/* clear watch history */}
+
+ Clear Watch History
+ {
+ RNReactNativeHapticFeedback.trigger('virtualKey', {
+ enableVibrateFallback: true,
+ ignoreAndroidSystemSettings: false,
+ });
+ clearHistory();
+ }}>
+
+
+
+
+ {/* Excluded qualities */}
+
+ Excluded qualities
+
+ {['480p', '720p', '1080p'].map((quality, index) => (
+ {
+ RNReactNativeHapticFeedback.trigger('effectTick', {
+ enableVibrateFallback: true,
+ ignoreAndroidSystemSettings: false,
+ });
+ if (ExcludedQualities.includes(quality)) {
+ setExcludedQualities(prev =>
+ prev.filter(q => q !== quality),
+ );
+ MMKV.setArray(
+ 'ExcludedQualities',
+ ExcludedQualities.filter(q => q !== quality),
+ );
+ } else {
+ setExcludedQualities(prev => [...prev, quality]);
+ MMKV.setArray('ExcludedQualities', [
+ ...ExcludedQualities,
+ quality,
+ ]);
+ }
+ console.log(ExcludedQualities);
+ }}>
+
+ {quality}
+
+
+ ))}
+
+
+
+
+ );
+};
+
+export default Preferences;
diff --git a/src/screens/settings/Settings.tsx b/src/screens/settings/Settings.tsx
index a9b07de..6c14818 100644
--- a/src/screens/settings/Settings.tsx
+++ b/src/screens/settings/Settings.tsx
@@ -17,7 +17,12 @@ import {providersList} from '../../lib/constants';
import {startActivityAsync, ActivityAction} from 'expo-intent-launcher';
import {NativeStackScreenProps} from '@react-navigation/native-stack';
import {SettingsStackParamList} from '../../App';
-import {MaterialCommunityIcons, AntDesign, Feather} from '@expo/vector-icons';
+import {
+ MaterialCommunityIcons,
+ AntDesign,
+ Feather,
+ MaterialIcons,
+} from '@expo/vector-icons';
const players = [
{
@@ -42,10 +47,6 @@ const Settings = ({navigation}: Props) => {
players[0],
);
- const [ExcludedQualities, setExcludedQualities] = useState(
- MMKV.getArray('ExcludedQualities') || [],
- );
-
const {provider, setProvider} = useContentStore(state => state);
return (
@@ -256,43 +257,20 @@ const Settings = ({navigation}: Props) => {
- {/* Excluded qualities */}
-
- Excluded qualities
-
- {['480p', '720p', '1080p'].map((quality, index) => (
- {
- ReactNativeHapticFeedback.trigger('effectTick', {
- enableVibrateFallback: true,
- ignoreAndroidSystemSettings: false,
- });
- if (ExcludedQualities.includes(quality)) {
- setExcludedQualities(prev => prev.filter(q => q !== quality));
- MMKV.setArray(
- 'ExcludedQualities',
- ExcludedQualities.filter(q => q !== quality),
- );
- } else {
- setExcludedQualities(prev => [...prev, quality]);
- MMKV.setArray('ExcludedQualities', [
- ...ExcludedQualities,
- quality,
- ]);
- }
- console.log(ExcludedQualities);
- }}>
-
- {quality}
-
-
- ))}
+ {/* Preferences */}
+ {
+ navigation.navigate('Preferences');
+ }}
+ background={TouchableNativeFeedback.Ripple('gray', false)}>
+
+
+
+ Preference
+
+
-
+
{/* clear cache */}