adrianhajdin / aora

Build your first mobile application
https://jsmastery.pro
1.41k stars 259 forks source link

Video not playing on device (IOS) #33

Open mbacarro opened 1 month ago

mbacarro commented 1 month ago

Got to the video portion at around the 3 hour mark and fonud that the videos weren't loading. I added the onError property to the

The server is not correctly configured. - The AVPlayerItem instance has failed with the error code -11850 and domain "AVFoundationErrorDomain"

Here's the code I have related to this error

import { ResizeMode, Video } from "expo-av";
.
.
.
                <Video
                    source={{ uri: item.video}}
                    className="w-52 h-72 rounded-[33px] mt-3 bg-white/10"
                    resizeMode={ResizeMode.CONTAIN}
                    useNativeControls
                    shouldPlay
                    onPlaybackStatusUpdate={(status) => {
                    if (status.didJustFinish) {
                        setPlay(false);
                    }
                    }}
                    onError={(error) => {
                        console.error("Video error: ", error); // Log the error
                    }}
                />

I think it's my device but not sure how to fix it

RazvanBalota commented 1 month ago

Hi there,

I have the same problem. I don't have a solution for you but it seems like the url videos are broken? I mean i can play them in my browser but for some reasons they are not playing on my device (iPhone 13 Pro Max running ios 18 beta 3), but if I use another url for the videos they work.

mbacarro commented 1 month ago

Weird, for me its any URL, it only works if I download a video and put the file path name as the source.

Mik3ll commented 1 month ago

https://docs.expo.dev/versions/latest/sdk/video-av/

The format of the url should contain the .mp4. Something like this https://yourserver.com/path/to/video.mp4 Vimeo or Youtube doesn't support it, if you want to use it from Vimeo, you need to use their API

Jeremydfrancis commented 1 week ago

You can also use react-native-webview if you prefer to use something other than the API route for embedded videos. This allows you to easily use embed videos from platforms like YouTube and Vimeo directly within your React Native application. I implemented logic to detect whether the video URL is a direct or embedded link. Depending on the result, the component renders the Video component (for direct links) or a WebView (for embedded videos).

Additionally, you'll need to apply similar changes to your app's VideoCard component to handle embedded videos correctly.


import { ResizeMode, Video } from "expo-av";
import * as Animatable from "react-native-animatable";
import {
  FlatList,
  Image,
  ImageBackground,
  TouchableOpacity,
  View,
  Dimensions,
} from "react-native";
import { WebView } from "react-native-webview";

import { icons } from "../constants";

const zoomIn = {
  0: {
    scale: 0.9,
  },
  1: {
    scale: 1,
  },
};

const zoomOut = {
  0: {
    scale: 1,
  },
  1: {
    scale: 0.9,
  },
};

const isEmbeddedVideo = (url) => {
  return url.includes("youtube.com") || url.includes("vimeo.com");
};

const TrendingItem = ({ activeItem, item }) => {
  const [play, setPlay] = useState(false);
  const isEmbedded = isEmbeddedVideo(item.video);

  const itemStyle = {
    width: Dimensions.get("window").width * 0.55,
    height: Dimensions.get("window").height * 0.45,
    borderRadius: 33,
    overflow: "hidden",
    marginTop: 15,
    backgroundColor: "rgba(255, 255, 255, 0.1)",
  };

  return (
    <Animatable.View
      style={{ marginRight: 20 }}
      animation={activeItem === item.$id ? zoomIn : zoomOut}
      duration={500}
    >
      {play ? (
        isEmbedded ? (
          <View style={itemStyle}>
            <WebView
              source={{ uri: item.video }}
              style={{ flex: 1 }}
              allowsInlineMediaPlayback={true}
              javaScriptEnabled={true}
              allowsFullscreenVideo={true}
              scalesPageToFit={true}
              startInLoadingState={true}
            />
          </View>
        ) : (
          <View style={itemStyle}>
            <Video
              source={{ uri: item.video }}
              style={{ flex: 1 }}
              useNativeControls
              resizeMode={ResizeMode.COVER}
              shouldPlay
              onPlaybackStatusUpdate={(status) => {
                if (status.didJustFinish) {
                  setPlay(false);
                }
              }}
              onError={(error) => {
                console.error("Video error:", error);
                setPlay(false);
              }}
            />
          </View>
        )
      ) : (
        <TouchableOpacity
          style={itemStyle}
          activeOpacity={0.7}
          onPress={() => setPlay(true)}
        >
          <ImageBackground
            source={{ uri: item.thumbnail }}
            style={{ width: "100%", height: "100%" }}
            resizeMode="cover"
          >
            <View
              style={{
                justifyContent: "center",
                alignItems: "center",
                flex: 1,
              }}
            >
              <Image
                source={icons.play}
                style={{ width: 48, height: 48 }}
                resizeMode="contain"
              />
            </View>
          </ImageBackground>
        </TouchableOpacity>
      )}
    </Animatable.View>
  );
};

const Trending = ({ posts }) => {
  const [activeItem, setActiveItem] = useState(posts[0]);

  const viewableItemsChanged = ({ viewableItems }) => {
    if (viewableItems.length > 0) {
      setActiveItem(viewableItems[0].key);
    }
  };

  return (
    <FlatList
      data={posts}
      horizontal
      keyExtractor={(item) => item.$id}
      renderItem={({ item }) => (
        <TrendingItem activeItem={activeItem} item={item} />
      )}
      onViewableItemsChanged={viewableItemsChanged}
      viewabilityConfig={{
        itemVisiblePercentThreshold: 70,
      }}
      contentOffset={{ x: 170 }}
    />
  );
};

export default Trending;