2

I want to create a flutter website where there is a collection of twitch and youtube videos. I tried to use the video_player plugin but for that I can either use the youtube_player plugin or I have to use an API to convert all links to their source files. But I am having trouble making something to embed twitch videos. Anything. Same page with youtube would be perfect but, a seperate twitch player would be good too. Maybe the Twitch API could help but I have no idea how to use it and am unable to understantd it. Here are the plugins I found that may be used\

1>Video_Player
2>Youtube_Player_plugin
Please Help

EDIT
This is the code I am using to make youtube videos with ext_video_player cause it works on web.

class videoBox extends StatefulWidget {
  String Video;
  videoBox(this.Video);
  @override
  _videoBoxState createState() => _videoBoxState(Video);
}

class _videoBoxState extends State<videoBox> {
  String Video;
  bool error = false;
  _videoBoxState(this.Video);
  VideoPlayerController _controller;
  @override
  void dispose(){
    super.dispose();
    _controller.dispose();
  }
  @override
  void initState(){
    super.initState();
      _controller = VideoPlayerController.network(
        Video,
      );

      _controller.initialize().then((value) {
        setState(() {
          print("Initialized");
        });
      });
      _controller.addListener(() {
        if (_controller.value.hasError) {
          print(_controller.value.errorDescription);
          setState(() {
            error = true;
            print(Video);
          });
        }
    });
        }
  @override
  Widget build(BuildContext context) {
    return error?Container(
      decoration: BoxDecoration(
          color: Colors.white,
          borderRadius: BorderRadius.all(Radius.circular(15))
      ),
      child: Image(fit:BoxFit.cover,image:NetworkImage("https://hiapseng-thailand.com/wp-content/themes/skywalker/facilities/video-placeholder.jpg"))
    ):GestureDetector(
      onTap:(){
        _controller.value.isPlaying?
        _controller.pause()
            :_controller.play();
      },
      child: Container(
        decoration: BoxDecoration(
            color: Colors.white,
            borderRadius: BorderRadius.all(Radius.circular(15))
        ),
        child:  VideoPlayer(_controller,),
    )
    );
  }
}

EDIT
I figured out a new way to make a video using iFrames. Using this I can add twitch streams but I just want the video, not the whole thing with chat and stuff. How to do that? Here is the coe I am using now

class videoBox extends StatefulWidget {
  String Video;
  videoBox(this.Video);
  @override
  _videoBoxState createState() => _videoBoxState(Video);
}

class _videoBoxState extends State<videoBox> {
  String Video;
  IFrameElement iFrame = IFrameElement();
  _videoBoxState(this.Video);

  @override
  Widget build(BuildContext context) {
    iFrame.width = (MediaQuery.of(context).size.width*0.32).toString();
    iFrame.height = (MediaQuery.of(context).size.width*0.27).toString();
    iFrame.src = "https://www.youtube.com/embed/"+Video;
    iFrame.allowFullscreen =true;
    // ignore: undefined_prefixed_name
    ui.platformViewRegistry.registerViewFactory(
      'i'+Video,
          (int viewId) =>iFrame,
    );
    return Container(
        height:MediaQuery.of(context).size.height *0.27,
        width:MediaQuery.of(context).size.width *0.32,
        decoration: BoxDecoration(
            color: Colors.white,
            borderRadius: BorderRadius.all(Radius.circular(15))
        ),
        child: HtmlElementView(
            key:UniqueKey(),
            viewType:'i'+Video
        ),
    ) ;
  }
}
Siddharth Agrawal
  • 2,960
  • 3
  • 16
  • 37

2 Answers2

0

Update

Making HTTP requests to the Twitch API is fairly easy. You have to register your application on the Twitch dev console. This will grant you access to both a client id and a client secret. Refer to the documentation for a detailed guide.

With those two, you can make a request which generates an app access token. Getting a video id is simply hitting a different endpoint. It requires a game id and/or user id as per the documentation

URL

GET https://api.twitch.tv/helix/videos

Required Query Parameters

Each request must specify one or more video ids, one user_id, or one game_id.

In the example below I generated an app access token, using my own client id and secret. Got a game id from another endpoint and finally retrieved a video id from the game id.

class TwitchAPIService {
  // Making a singleton pattern ensures only one instance of a class is ever created

  TwitchAPIService._internal();

  static final TwitchAPIService _twitchAPIService = TwitchAPIService._internal();

  static TwitchAPIService get twitchAPIService => _twitchAPIService;

  String twitchClientID, twitchClientSecret; // This are to be gotten from the Twitch developer console

  Future<String> fetchAppAccessToken() async {
    final baseUrl = 'id.twitch.tv';
    Map<String, String> parameters = {
      'client_id': twitchClientID,
      'client_secret': twitchClientSecret,
      'grant_type': 'client_credentials',
    };

    Map<String, String> headers = {
      'Accept': 'application/json',
    };

    Uri uri = Uri.https(baseUrl, '/oauth2/token', parameters);

    var token;
    try {
      token = await http.post(uri, headers: headers);
      if (token.statusCode == 200) {
        // Make secure requests with the token.
        return token.body;
      }
      return json.decode(token.body)['message'];
    } catch (e) {
      return json.decode(token.body)['message'];
    }
  }

  // This gets the game Id of any given game under Twitch's game library
  Future<String> fetchGameId(String token) async {
    final baseUrl = 'api.twitch.tv';
    Map<String, String> parameters = {
      'name': 'fortnite',
    };
    Map<String, String> headers = {
      'Accept': 'application/json',
      'Authorization': 'Bearer $token',
      'Client-id': twitchClientID,
    };

    Uri uri = Uri.https(baseUrl, '/helix/games', parameters);

    try {
      var gameId = await http.get(uri, headers: headers);
      return gameId.body;
    } catch (e) {
      return e.toString();
    }
  }
  // This retrieves videoId(s) under a particular gameId
  Future<dynamic> fetchVideoId(String gameId) async {
    final baseUrl = 'api.twitch.tv';
    Map<String, String> parameters = {
      'game_id': gameId,
    };
    Map<String, String> headers = {
      'Accept': 'application/json',
      'Authorization': 'Bearer 4aq6y8pqjyw7cc9x4o8el7zha1ua8u',
      'Client-id': twitchClientID,
    };
    Uri uri = Uri.https(baseUrl, '/helix/videos', parameters);
    try {
      var videoId = await http.get(uri, headers: headers);
      return videoId.body;
    } catch (e) {
      return e.toString();
    }
  }
}

A Hacked Solution

The Twitch API offers various services, such as getting streams, channel details and so much more. I'll cut right to the chase and assume you have already set up your Twitch developer account here.

Note: In regards to your question, you don't have to have an active developer account. Although if you want to use other services like the ones mentioned above, you would need a form of Authentication hence a Twitch developer account.


Prerequisite

  1. A WebView package preferably Flutter Inappwebview.
  2. A Twitch channel name or video ID. This can be hardcoded or gotten dynamically using the Twitch API. The idle way to getting it should be the latter. For the sake of this answer, I have a random video ID below.
  3. A deployed website bundled with a ssl certificate ( Optional ).

Please point 3 is strongly required. Usually, most developers would just directly save the html content locally in a html file or even directly write it out in dart files.

According to this thread, this will not work. The embedded Twitch player will only work over a localhost and/or a website coupled with a ssl certificate. Some hosting services automatically bundle any deployed website with a ssl certificate. I am very sure Firebase Hosting does this. You can skip this part since, testing locally is supported.

Other things to keep in mind

Local development

Use “localhost” or any IP address in the “127.0.0.1/8” range as the parent value to use either HTTP or HTTPS in local development. Any port can be used, though this does not need to be specified anywhere (80, 3000, 8100, etc) Local development over other IP ranges (e.g. 192.1.1.1) must adhere to the HTTPS requirement, though a valid certificate is not required


Now unto the codebase.

  • Create an index.html file which would contain the Official Iframe Player.

     <!DOCTYPE html>
     <html>
    
     <head>
         <style>
             html,
             body {
                 margin: 0;
                 padding: 0;
                 background-color: #000000;
                 overflow: hidden;
                 position: fixed;
                 height: 100%;
                 width: 100%;
             }
         </style>
         <meta name='viewport' content='width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no'>
     </head>
    
     <body>
         <div id="player"></div>
         <script src="https://player.twitch.tv/js/embed/v1.js"></script>
         <div id="<player div ID>"></div>
         <script type="text/javascript">
             var options = {
                 width: window.innerWidth,
                 height: window.innerHeight,
                 video: "335180634",
                 // This should be used locally.
                 // If deployed, i.e not local then the parent should be the url of your website.
                 // For example if the full url of our deployed website is https://www.flutterproject.com then the parent would be
                 // parent: ["flutterproject.com"]
                 parent: ["localhost"]
             };
             var player = new Twitch.Player("<player div ID>", options);
             player.setVolume(0.5);
         </script>
     </body>
    
     </html>
    

The main thing to focus on is the script block. It contains the Interactive iframe player. It also accepts an options object which can be customised. Much more parameters can be found here. You can simply move that code snippet into an editor an open it on a live server, to make sure it works.

  • The Dart Side.

Basically, we use some sort of WebView to open up our deployed website that contains the html content mention in point 1. We also have to give constraints to the WebView in order to place it along other widgets. A simple aspect Ratio of 16:9 should be sufficient.

Enabling allowsInlineMediaPlayback: true would make sure that the video players in the correct aspect ratio. Setting it to false, will have an effect of causing the video to dive into fullscreen on IOS.

main(List<String> args) {
  runApp(
    MaterialApp(
      home: Scaffold(
        backgroundColor: Colors.black,
        appBar: AppBar(
          title: Text('Twtich Embed'),
        ),
        body: AspectRatio(
          aspectRatio: 16 / 9,
          child: InAppWebView(
            key: UniqueKey(),
            initialUrl: 'flutterproject.com',
            initialOptions: InAppWebViewGroupOptions(
              ios: IOSInAppWebViewOptions(allowsInlineMediaPlayback: true),
              crossPlatform: InAppWebViewOptions(
                mediaPlaybackRequiresUserGesture: false,
                transparentBackground: true,
              ),
            ),
          ),
        ),
      ),
    ),
  );
}

Notes

Downsides

  • This solution will push traffic to your own managed website.
  • It might be relatively slow depending on how you optimise your deployed website.

Upside(s)

  • It is the only way Twitch supports mobile embeds, as they do not have a native sdk.
Adeolaex
  • 179
  • 10
  • I am looping through the videos so the only way this will help me is having the iframe show only the video and not the full screen. Is there any way to use HTTP requests in flutter to get the video url – Siddharth Agrawal Dec 17 '20 at 04:50
  • Twitch does not provide video urls, rather video ids with the api. I updated my answer to reflect this step. Since you are looping, you can accept a url parameter in your website's url called newVideoId. From the flutter side of things, every time a new video is being looped over, you add the video id to the IntialUrl of InAppWebView like this 'flutterproject.co/123456' . Your website will capture the url parameter to newVideoId and display the new video on every loop. – Adeolaex Dec 17 '20 at 15:31
  • @Adeolaex are you able to change buttons size ? My implementation is similar to yours but buttons are really small on the player when the screen is in portrait. – thegrxp Jan 21 '21 at 11:54
  • @thegrxp Yes I agree with you on the size of the buttons, but no it's bot possible. Only the size of the video player can be changed. – Adeolaex Jan 22 '21 at 12:44
0

We try to play videos on flutter web platform, but only this thing works for me. To use embedded script and HTML from docs:

so add this library or any other which may work's with html : webviewx: ^0.1.0

and then paste HTML sritp:

WebViewX(
        initialContent:
            """<script src= "https://player.twitch.tv/js/embed/v1.js"></script>
                  <div id="${345}"></div>
                  <script type="text/javascript">
                  var options = {
                      width: "${300}",
                      height: "${300}",
                      channel: "icebergdoto",
                      parent: ["your.app","your.ext"]
                    };
                    var player = new Twitch.Player("345", options);
                    player.setVolume(0.5);
                  </script>""",
        initialSourceType: SourceType.HTML,
        onWebViewCreated: (controller) {});

in this case you still be able use some variables such as height and width