前言

继上一篇使用Flutter开发的抖音国际版 后再次撸一个国内版抖音,大部分功能已完成,主要是Flutter开发APP速度很爽,  先看下图

项目主要结构介绍

这次主要的改动在api.dart 及douyin.dart里,国内抖音的api是不同的,另外地址以及实体类也不一样。详细下面介绍.

抖音的实体类

主要是讲json转化为实体模型,然后绑定到view 层面,写这个实体类还是很耗费时间的,毕竟得先用爬网知识讲抖音的json拿到,并且根据json反向写实体类.

这个地址获取到抖音的推荐列表json: https://creator.douyin.com/aweme/v1/creator/data/billboard/?billboard_type=4,绑定第一个Douyin实体,拿到所有抖音的url地址
 
通过第二个api地址 https://www.iesdouyin.com/web/api/v2/aweme/iteminfo/?item_ids= 拿到抖音视频所有的json信息并且绑定VideoData实体类
class Douyin {
int statusCode;
String statusMsg;
List<BillboardData> billboardData;
Extra extra; Douyin({this.statusCode, this.statusMsg, this.billboardData, this.extra}); Douyin.fromJson(Map<String, dynamic> json) {
statusCode = json["status_code"];
statusMsg = json["status_msg"];
if (json['billboard_data'] != null) {
billboardData = new List<BillboardData>();
json["billboard_data"].forEach((v) {
billboardData.add(BillboardData.fromJson(v));
});
}
extra = json['extra'] != null ? new Extra.fromJson(json['extra']) : null;
} Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data["status_code"] = this.statusCode;
data["status_msg"] = this.statusMsg;
if (this.billboardData != null) {
data["billboard_data"] =
this.billboardData.map((v) => v.toJson()).toList();
}
data["extra"] = this.extra;
return data;
}
} class BillboardData {
String author;
String imgUrl;
String link;
int rank;
String title;
String value; BillboardData(
{this.author, this.imgUrl, this.link, this.rank, this.title, this.value}); BillboardData.fromJson(Map<String, dynamic> json) {
this.author = json["author"];
this.imgUrl = json["img_url"];
this.link = json["link"];
this.rank = json["rank"];
this.title = json["title"];
this.value = json["value"];
} Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data["author"] = this.author;
data["img_url"] = this.imgUrl;
data["link"] = this.link;
data["rank"] = this.rank;
data["title"] = this.title;
data["value"] = this.value;
return data;
}
} class Extra {
int now;
Extra({this.now}); Extra.fromJson(Map<String, dynamic> json) {
now = json["now"];
} Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data["now"] = this.now;
return data;
}
} class VideoData {
int statusCode;
List<Itemlist> itemList;
ExtraData extra; VideoData.fromJson(Map<String, dynamic> json) {
this.statusCode = json["status_code"];
if (json['item_list'] != null) {
itemList = new List<Itemlist>();
json['item_list'].forEach((v) {
itemList.add(new Itemlist.fromJson(v));
});
}
this.extra =
json["extra"] != null ? new ExtraData.fromJson(json["extra"]) : null;
} Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data["status_code"] = this.statusCode;
if (this.itemList != null) {
data['item_list'] = this.itemList.map((v) => v.toJson()).toList();
}
if (this.extra != null) {
data["extra"] = this.extra.toJson();
}
return data;
}
} class Itemlist {
String awemeid;
String videolabels;
String labeltoptext;
int category;
Author author;
int duration;
String promotions;
int ispreview;
int createtime;
List<ChaList> chalist;
String commentlist;
int authoruserid;
String videotext;
int groupid;
bool islivereplay;
ShareInfo shareinfo;
String position;
String imageinfos;
RiskInfos riskinfos;
String uniqidposition;
String geofencing;
Statistics statistics;
int awemetype;
Music music;
List<TextExtra> textExtras;
Video video;
String shareurl;
String desc;
String longvideo; Itemlist(
{this.awemeid,
this.videolabels,
this.labeltoptext,
this.category,
this.author,
this.duration,
this.promotions,
this.ispreview,
this.createtime,
this.chalist,
this.commentlist,
this.authoruserid,
this.videotext,
this.groupid,
this.islivereplay,
this.shareinfo,
this.position,
this.imageinfos,
this.riskinfos,
this.uniqidposition,
this.geofencing,
this.statistics,
this.awemetype,
this.music,
this.textExtras,
this.video,
this.shareurl,
this.desc,
this.longvideo}); Itemlist.fromJson(Map<String, dynamic> json) {
this.awemeid = json["aweme_id"];
this.videolabels = json["video_labels"];
this.labeltoptext = json["label_top_text"];
this.category = json["category"];
this.author =
json["author"] != null ? new Author.fromJson(json["author"]) : null;
this.duration = json["duration"];
this.promotions = json["promotions"];
this.ispreview = json["is_preview"];
this.createtime = json["create_time"];
if (json["cha_list"] != null) {
this.chalist = new List<ChaList>();
json["cha_list"].forEach((v) {
this.chalist.add(new ChaList.fromJson(v));
});
}
this.commentlist = json["comment_list"];
this.authoruserid = json["author_user_id"];
this.videotext = json["video_text"];
this.groupid = json["group_id"];
this.islivereplay = json["is_live_replay"];
this.shareinfo = json["share_info"] != null
? new ShareInfo.fromJson(json["share_info"])
: null;
this.position = json["position"];
this.imageinfos = json["image_infos"];
this.riskinfos = json["risk_infos"] != null
? new RiskInfos.fromJson(json["risk_infos"])
: null;
this.uniqidposition = json["uniqid_position"];
this.geofencing = json["geofencing"];
this.statistics = json["statistics"] != null
? new Statistics.fromJson(json["statistics"])
: null;
this.awemetype = json["aweme_type"];
this.music =
json["music"] != null ? new Music.fromJson(json["music"]) : null;
if (json["text_extra"] != null) {
this.textExtras = new List<TextExtra>();
json['text_extra'].forEach((v) {
textExtras.add(new TextExtra.formJson(v));
});
}
this.video =
json["video"] != null ? new Video.fromJson(json["video"]) : null;
this.shareurl = json["share_url"];
this.desc = json["desc"];
this.longvideo = json["long_video"];
} Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data["aweme_id"] = this.awemeid;
data["video_labels"] = this.videolabels;
data["label_top_text"] = this.labeltoptext;
data["category"] = this.category;
if (this.author != null) {
data["author"] = this.author.toJson();
}
data["duration"] = this.duration;
data["promotions"] = this.promotions;
data["is_preview"] = this.ispreview;
data["create_time"] = this.createtime;
if (this.chalist != null) {
data["cha_list"] = this.chalist.map((e) => e.toJson()).toList();
}
data["comment_list"] = this.commentlist;
data["author_user_id"] = this.authoruserid;
data["video_text"] = this.videotext;
data["group_id"] = this.groupid;
data["is_live_replay"] = this.islivereplay;
if (this.shareinfo != null) {
data["share_info"] = this.shareinfo.toJson();
}
data["position"] = this.position;
data["image_infos"] = this.imageinfos;
if (this.riskinfos != null) {
data["risk_infos"] = this.riskinfos.toJson();
}
data["uniqid_position"] = this.uniqidposition;
data["geofencing"] = this.geofencing;
if (this.statistics != null) {
data["statistics"] = this.statistics.toJson();
}
data["aweme_type"] = this.awemetype;
if (this.music != null) {
data["music"] = this.music.toJson();
}
if (this.textExtras != null) {
data["text_extra"] = this.textExtras.map((e) => e.toJson()).toList();
}
if (this.video != null) {
data["video"] = this.video.toJson();
}
data["share_url"] = this.shareurl;
data["desc"] = this.desc;
data["long_video"] = this.longvideo;
return data;
}
} class TextExtra {
String hashtagName;
int hashtagId;
int start;
int end;
int type; TextExtra(
{this.hashtagName, this.hashtagId, this.start, this.end, this.type}); TextExtra.formJson(Map<String, dynamic> json) {
this.hashtagName = json["hashtag_name"];
this.hashtagId = json["hashtag_id"];
this.start = json["start"];
this.end = json["end"];
this.type = json["type"];
} Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data["hashtag_name"] = this.hashtagName;
data["hashtag_id"] = this.hashtagId;
data["start"] = this.start;
data["end"] = this.end;
data["type"] = this.type;
return data;
}
} // Author
class Author {
String geofencing;
String uid;
String shortID;
String signature;
AvatarMedium avatarMedium;
String uniqueId;
String followersDetail;
String platformSyncInfo;
String policyVersion;
String nickname;
AvatarLarger avatarlarger;
AvatarThumb avatarthumb; Author(
{this.geofencing,
this.uid,
this.shortID,
this.signature,
this.avatarMedium,
this.uniqueId,
this.followersDetail,
this.platformSyncInfo,
this.policyVersion,
this.nickname,
this.avatarlarger,
this.avatarthumb}); Author.fromJson(Map<String, dynamic> json) {
this.geofencing = json["geofencing"];
this.uid = json["uid"];
this.shortID = json["short_id"];
this.signature = json["signature"];
this.avatarMedium = json["avatar_medium"] != null
? new AvatarMedium.fromJson(json["avatar_medium"])
: null;
this.uniqueId = json["unique_id"];
this.followersDetail = json["followers_detail"];
this.platformSyncInfo = json["platform_sync_info"];
this.policyVersion = json["policy_version"];
this.nickname = json["nickname"];
this.avatarlarger = json["avatar_larger"] != null
? new AvatarLarger.formJson(json["avatar_larger"])
: null;
this.avatarthumb = json["avatar_thumb"] != null
? new AvatarThumb.formJson(json["avatar_thumb"])
: null;
} Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data["geofencing"] = this.geofencing;
data["uid"] = this.uid;
data["short_id"] = this.shortID;
data["signature"] = this.signature;
if (this.avatarMedium != null) {
data["avatar_medium"] = this.avatarMedium.toJson();
}
data["unique_id"] = this.uniqueId;
data["followers_detail"] = this.followersDetail;
data["platform_sync_info"] = this.platformSyncInfo;
data["policy_version"] = this.policyVersion;
data["nickname"] = this.nickname;
if (this.avatarlarger != null) {
data["avatar_larger"] = this.avatarlarger.toJson();
}
if (this.avatarthumb != null) {
data["avatar_thumb"] = this.avatarthumb.toJson();
}
return data;
}
} class AvatarMedium {
List<String> urlList;
String uri;
AvatarMedium({this.urlList, this.uri}); AvatarMedium.fromJson(Map<String, dynamic> json) {
if (json["url_list"] != null) {
this.urlList = json["url_list"].cast<String>();
}
this.uri = json["uri"];
} Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data["url_list"] = this.urlList;
return data;
}
} class AvatarLarger {
String uri;
List<String> urlList;
AvatarLarger({this.uri, this.urlList}); AvatarLarger.formJson(Map<String, dynamic> json) {
this.uri = json["uri"] as String;
this.urlList = json["url_list"].cast<String>();
} Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data["url_list"] = this.urlList;
data["uri"] = this.uri;
return data;
}
} class AvatarThumb {
String uri;
List<String> urlList;
AvatarThumb({this.uri, this.urlList}); AvatarThumb.formJson(Map<String, dynamic> json) {
this.uri = json["uri"] as String;
this.urlList = json["url_list"].cast<String>();
} Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data["url_list"] = this.urlList;
data["uri"] = this.uri;
return data;
}
} class ExtraData {
int now;
String logid;
ExtraData({this.now, this.logid}); ExtraData.fromJson(Map<String, dynamic> json) {
this.now = json["now"];
this.logid = json["logid"];
} Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data["now"] = this.now;
data["logid"] = this.logid;
return data;
}
}
//End author //ChaList
class ChaList {
String chaName;
int viewCount;
String hashTagProfile;
bool isCommerce;
String cid;
String desc;
int userCount;
String connectMusic;
int type;
CoverItem coverItem;
ChaList(
{this.chaName,
this.viewCount,
this.hashTagProfile,
this.isCommerce,
this.cid,
this.desc,
this.userCount,
this.connectMusic,
this.type,
this.coverItem}); ChaList.fromJson(Map<String, dynamic> json) {
this.chaName = json["cha_name"];
this.viewCount = json["view_count"];
this.hashTagProfile = json["hash_tag_profile"];
this.isCommerce = json["is_commerce"];
this.cid = json["cid"];
this.desc = json["desc"];
this.userCount = json["user_count"];
this.connectMusic = json["connect_music"];
this.type = json["type"];
this.coverItem = json["cover_item"] != null
? new CoverItem.formJson(json["cover_item"])
: null;
} Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data["cha_name"] = this.chaName;
data["view_count"] = this.viewCount;
data["hash_tag_profile"] = this.hashTagProfile;
data["is_commerce"] = this.isCommerce;
data["cid"] = this.cid;
data["desc"] = this.desc;
data["user_count"] = this.userCount;
data["connect_music"] = this.connectMusic;
data["type"] = this.type;
if (this.coverItem != null) {
data["cover_item"] = this.coverItem.toJson();
}
return data;
}
} class CoverItem {
String uri;
List<String> urlList;
CoverItem({this.uri, this.urlList});
CoverItem.formJson(Map<String, dynamic> json) {
this.uri = json["uri"] as String;
this.urlList = json["url_list"].cast<String>();
} Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data["url_list"] = this.urlList;
data["uri"] = this.uri;
return data;
}
}
//End ChaList //ShareInfo
class ShareInfo {
String shareweibodesc;
String sharedesc;
String sharetitle;
ShareInfo({this.shareweibodesc, this.sharedesc, this.sharetitle});
ShareInfo.fromJson(Map<String, dynamic> json) {
this.shareweibodesc = json["share_weibo_desc"];
this.sharedesc = json["share_desc"];
this.sharetitle = json["share_title"];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data["share_weibo_desc"] = this.shareweibodesc;
data["share_desc"] = this.sharedesc;
data["share_title"] = this.sharetitle;
return data;
}
}
//End ShareInfo //RiskInfos
class RiskInfos {
bool warn;
int type;
String content;
RiskInfos({this.warn, this.type, this.content});
RiskInfos.fromJson(Map<String, dynamic> json) {
this.warn = json["warn"] as bool;
this.type = json["type"];
this.content = json["content"];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data["warn"] = this.warn;
data["type"] = this.type;
data["content"] = this.content;
return data;
}
}
//End RiskInfos //Statistics
class Statistics {
String awemeId;
int commentCount;
int diggCount;
Statistics.fromJson(Map<String, dynamic> json) {
this.awemeId = json["aweme_id"];
this.commentCount = json["comment_count"];
this.diggCount = json["digg_count"];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data["aweme_id"] = this.awemeId;
data["comment_count"] = this.commentCount;
data["digg_count"] = this.diggCount;
return data;
}
}
//End Statistics //Music
class Music {
CoverLarge coverlarge;
CoverMedium covermedium;
int duration;
int status;
String mid;
String title;
String author;
PlayUrl playurl;
String position;
int id;
CoverHd coverhd;
CoverThumb coverthumb; Music.fromJson(Map<String, dynamic> json) {
this.coverlarge = json["cover_large"] != null
? new CoverLarge.formJson(json["cover_large"])
: null;
this.covermedium = json["cover_medium"] != null
? new CoverMedium.formJson(json["cover_medium"])
: null;
this.duration = json["duration"];
this.status = json["status"];
this.mid = json["mid"];
this.title = json["title"];
this.author = json["author"];
this.playurl = json["play_url"] != null
? new PlayUrl.formJson(json["play_url"])
: null;
this.position = json["position"];
this.id = json["id"];
this.coverhd = json["cover_hd"] != null
? new CoverHd.formJson(json["cover_hd"])
: null;
this.coverthumb = json["cover_thumb"] != null
? new CoverThumb.formJson(json["cover_thumb"])
: null;
} Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
if (this.coverlarge != null) {
data["cover_large"] = this.coverlarge.toJson();
}
if (this.covermedium != null) {
data["cover_medium"] = this.covermedium.toJson();
}
data["duration"] = this.duration;
data["status"] = this.status;
data["mid"] = this.mid;
data["title"] = this.title;
data["author"] = this.author;
if (this.playurl != null) {
data["play_url"] = this.playurl.toJson();
}
data["position"] = this.position;
data["id"] = this.id;
if (this.coverhd != null) {
data["cover_hd"] = this.coverhd.toJson();
}
if (this.coverthumb != null) {
data["cover_thumb"] = this.coverthumb.toJson();
}
return data;
}
} class CoverLarge {
String uri;
List<String> urlList;
CoverLarge({this.uri, this.urlList});
CoverLarge.formJson(Map<String, dynamic> json) {
this.uri = json["uri"] as String;
this.urlList = json["url_list"].cast<String>();
} Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data["url_list"] = this.urlList;
data["uri"] = this.uri;
return data;
}
} class CoverMedium {
String uri;
List<String> urlList;
CoverMedium({this.uri, this.urlList});
CoverMedium.formJson(Map<String, dynamic> json) {
this.uri = json["uri"] as String;
this.urlList = json["url_list"].cast<String>();
} Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data["url_list"] = this.urlList;
data["uri"] = this.uri;
return data;
}
} class PlayUrl {
String uri;
List<String> urlList;
PlayUrl({this.uri, this.urlList});
PlayUrl.formJson(Map<String, dynamic> json) {
this.uri = json["uri"] as String;
this.urlList = json["url_list"].cast<String>();
} Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data["url_list"] = this.urlList;
data["uri"] = this.uri;
return data;
}
} class CoverHd {
String uri;
List<String> urlList;
CoverHd({this.uri, this.urlList});
CoverHd.formJson(Map<String, dynamic> json) {
this.uri = json["uri"] as String;
this.urlList = json["url_list"].cast<String>();
} Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data["url_list"] = this.urlList;
data["uri"] = this.uri;
return data;
}
} class CoverThumb {
String uri;
List<String> urlList;
CoverThumb({this.uri, this.urlList});
CoverThumb.formJson(Map<String, dynamic> json) {
this.uri = json["uri"] as String;
this.urlList = json["url_list"].cast<String>();
} Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data["url_list"] = this.urlList;
data["uri"] = this.uri;
return data;
}
}
//End Music //Video
class Video {
int width;
OriginCover origincover;
String ratio;
bool haswatermark;
String bitrate;
PlayAddr playaddr;
Cover cover;
int duration;
String vid;
int islongvideo;
int height;
DynamicCover dynamiccover;
Video(
{this.width,
this.origincover,
this.ratio,
this.haswatermark,
this.bitrate,
this.playaddr,
this.cover,
this.duration,
this.vid,
this.islongvideo,
this.height,
this.dynamiccover});
Video.fromJson(Map<String, dynamic> json) {
this.width = json["width"];
this.origincover = json["origin_cover"] != null
? new OriginCover.formJson(json["origin_cover"])
: null;
this.ratio = json["ratio"];
this.haswatermark = json["has_watermark"];
this.bitrate = json["bit_rate"];
this.playaddr = json["play_addr"] != null
? new PlayAddr.formJson(json["play_addr"])
: null;
this.cover =
json["cover"] != null ? new Cover.formJson(json["cover"]) : null;
this.duration = json["duration"];
this.vid = json["vid"];
this.islongvideo = json["is_long_video"];
this.height = json["height"];
this.dynamiccover = json["dynamic_cover"] != null
? new DynamicCover.formJson(json["dynamic_cover"])
: null;
} Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data["width"] = this.width;
if (this.origincover != null) {
data["origin_cover"] = this.origincover.toJson();
}
data["ratio"] = this.ratio;
data["has_watermark"] = this.haswatermark;
data["bit_rate"] = this.bitrate;
if (this.playaddr != null) {
data["play_addr"] = this.playaddr.toJson();
}
if (this.cover != null) {
data["cover"] = this.cover.toJson();
}
data["duration"] = this.duration;
data["vid"] = this.vid;
data["is_long_video"] = this.islongvideo;
data["height"] = this.height;
if (this.dynamiccover != null) {
data["dynamic_cover"] = this.dynamiccover.toJson();
}
return data;
}
} class OriginCover {
String uri;
List<String> urlList;
OriginCover({this.uri, this.urlList});
OriginCover.formJson(Map<String, dynamic> json) {
this.uri = json["uri"] as String;
this.urlList = json["url_list"].cast<String>();
} Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data["url_list"] = this.urlList;
data["uri"] = this.uri;
return data;
}
} class PlayAddr {
String uri;
List<String> urlList;
PlayAddr({this.uri, this.urlList});
PlayAddr.formJson(Map<String, dynamic> json) {
this.uri = json["uri"] as String;
this.urlList = json["url_list"].cast<String>();
} Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data["url_list"] = this.urlList;
data["uri"] = this.uri;
return data;
}
} class Cover {
String uri;
List<String> urlList;
Cover({this.uri, this.urlList});
Cover.formJson(Map<String, dynamic> json) {
this.uri = json["uri"] as String;
this.urlList = json["url_list"].cast<String>();
} Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data["url_list"] = this.urlList;
data["uri"] = this.uri;
return data;
}
} class DynamicCover {
String uri;
List<String> urlList;
DynamicCover({this.uri, this.urlList});
DynamicCover.formJson(Map<String, dynamic> json) {
this.uri = json["uri"] as String;
this.urlList = json["url_list"].cast<String>();
} Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data["url_list"] = this.urlList;
data["uri"] = this.uri;
return data;
}
} //End Video

  

取抖音无水印视频,这里才是关键

通过这个api地址 https://aweme.snssdk.com/aweme/v1/play/?video_id={}&ratio=720p&line=0&media_type=4&vr_type=0&improve_bitrate=0&is_play_url=1&h265=1&adapt720=1 可以成功的拿到无水印视频,

此方法仅用于学习研究目的,不得从事违法活动哈,  否则与本作者无关.

具体实现代码如下

import 'dart:io';

import 'package:flutter/cupertino.dart';
import 'package:http/http.dart' as http;
import 'package:dio/dio.dart'; class RequestController {
//static String host = "https://www.tiktok.com/";
static String host = "https://creator.douyin.com";
String url = host + "/aweme/v1/creator/data/billboard/?billboard_type=4"; String video =
"https://www.iesdouyin.com/web/api/v2/aweme/iteminfo/?item_ids="; String player = "https://aweme.snssdk.com/aweme/v1/play/?video_id="; Future<String> getVideos() async {
try {
var response = await http.get(url);
return response.body;
} catch (e) {
return e.toString();
}
} //获取无水印的视频
Future<String> getRedirects(String videoid) async {
try {
var response = await new Dio().get(
player +
videoid +
"&ratio=720p&line=0&media_type=4&vr_type=0&improve_bitrate=0&is_play_url=1&h265=1&adapt720=1",
options: Options(
headers: headers,
contentType: "text/html; charset=utf-8",
followRedirects: false,
validateStatus: (status) {
return status < 500;
}),
);
if (response.statusCode == 302) {
return response.data.toString().split('"')[1];
}
return '';
} catch (ex) {
return '';
}
} Future<String> getCookie() async {
try {
var response = await http.get(host + "/share/item/");
return response.headers["set-cookie"];
} catch (e) {
return "error";
}
} var headers = {
"user-agent":
"Mozilla/5.0 (iPhone; CPU iPhone OS 11_0 like Mac OS X) AppleWebKit/604.1.38 (KHTML, like Gecko) Version/11.0 Mobile/15A372 Safari/604.1"
};
}

 

剩下就是改造TrendingScreen里获取视频的方法

  getTrending() async {
//var cookies = await api.getCookie();
//api.setCookie(cookies);
try {
var response = await http.get(
api.url,
headers: api.headers,
);
Douyin tiktok = Douyin.fromJson(jsonDecode(response.body));
tiktok.billboardData.forEach(
(item) {
setState(() {
getVideos(item);
});
},
);
} catch (ex) {
SimpleDialog(
title: Text('Hot videos list is empty'),
);
print(ex);
}
}

  

把获取到的无水印视频加载到view层

getVideos(BillboardData v) async {
try {
var url = v.link.split("/")[5];
var response = await http.get(
api.video + url + "&dytk",
headers: api.headers,
);
VideoData videoData = VideoData.fromJson(jsonDecode(response.body));
//获取无水印的视频地址
api.getRedirects(videoData.itemList[0].video.playaddr.uri).then((url) => {
print( Uri.decodeFull(url)),
if (url != '')
{
videos.add(VideoItem(
data: videoData,
videourl: url,
))
}
});
} catch (ex) {
print(ex);
}
}

 

最后,就是绑定视频数据啦,大功告成!

  Widget build(BuildContext context) {
return Scaffold(
body: Stack(
children: <Widget>[
DouyinVideoPlayer(
url: videourl,
),
title(),
VideoDescription(
description: data.itemList[0].textExtras[0].hashtagName,
musicName: data.itemList[0].music.title,
authorName: data.itemList[0].music.author,
userName: data.itemList[0].author.nickname,
),
ActionsToolbar(
comments: data.itemList[0].statistics.commentCount.toString(),
userImg: data.itemList[0].author.avatarMedium.urlList[0],
favorite: data.itemList[0].statistics.diggCount,
coverImg: data.itemList[0].music.covermedium.urlList[0],
),
],
),
);
}

 

结语

写到这里,手撸一个抖音app完成了基本功能,一些数据转化比喻点赞数还是原始int数据,需要转化成K M 等,后续待完善,毕竟花了一天时间来写这个app纯粹为了兴趣. 本人也极喜欢玩抖音.

另外因为写得匆忙,只测试了少量数据,json返回的数据有些为null ,也不知道具体是啥类型,这个待完善。 各位博友们觉得感兴趣的点个赞哈.  支持支持!

顺便说一下,各位支持的话点赞关注我继续完善剩余的部分,有需要学习了解的可以联系我,代码上传到github ,地址:https://github.com/WangCharlie/douyin,到这里就点个star, 谢谢.

第二篇-用Flutter手撸一个抖音国内版,看看有多炫的更多相关文章

  1. 第四篇-用Flutter手撸一个抖音国内版,看看有多炫

    前言 这次对布局进行优化,主要包含了首页tabview pageview 以及添加几个按钮的操作过程.主要使用到stack层叠布局,tabpview和pageview,tabview两个页面,一个关注 ...

  2. 第三篇-用Flutter手撸一个抖音国内版,看看有多炫

    前言 前一篇已经开发了大部分框架,包含视频上下滑动播放,这次将上次未完成的数据显示友好显示,以及底部音乐走马灯特效,另外优化了加载数据的bug,在dart语言里 & 会自动变成&  另 ...

  3. 第五篇- 抖音的强大对手来了,用Flutter手撸一个抖音国际版,看看有多炫

    前言 由于中间几个月项目天天加班,导致没没时间更新,最近一段时间对前端进行了重构,加了很多页面,如登录.注册.关注.个人中心等,目前写这个纯属业余个人爱好,所以断断续续的继续在做...... 前端地址 ...

  4. Golang:手撸一个支持六种级别的日志库

    Golang标准日志库提供的日志输出方法有Print.Fatal.Panic等,没有常见的Debug.Info.Error等日志级别,用起来不太顺手.这篇文章就来手撸一个自己的日志库,可以记录不同级别 ...

  5. 使用Flutter开发的抖音国际版

    简介 最近花了两天时间研究使用Flutter开发一个抖音国际版. 先上图,个人感觉使用Flutter开发app快得不要不要的额.  两天就基本可以开发个大概出来.   最主要是热更新,太方便实时调整U ...

  6. 使用Java Socket手撸一个http服务器

    原文连接:使用Java Socket手撸一个http服务器 作为一个java后端,提供http服务可以说是基本技能之一了,但是你真的了解http协议么?你知道知道如何手撸一个http服务器么?tomc ...

  7. 五分钟,手撸一个Spring容器!

    大家好,我是老三,Spring是我们最常用的开源框架,经过多年发展,Spring已经发展成枝繁叶茂的大树,让我们难以窥其全貌. 这节,我们回归Spring的本质,五分钟手撸一个Spring容器,揭开S ...

  8. 【手撸一个ORM】MyOrm的使用说明

    [手撸一个ORM]第一步.约定和实体描述 [手撸一个ORM]第二步.封装实体描述和实体属性描述 [手撸一个ORM]第三步.SQL语句构造器和SqlParameter封装 [手撸一个ORM]第四步.Ex ...

  9. 通过 Netty、ZooKeeper 手撸一个 RPC 服务

    说明 项目链接 微服务框架都包括什么? 如何实现 RPC 远程调用? 开源 RPC 框架 限定语言 跨语言 RPC 框架 本地 Docker 搭建 ZooKeeper 下载镜像 启动容器 查看容器日志 ...

随机推荐

  1. 自动驾驶汽车数据不再封闭,Uber 开源新的数据可视化系统

    日前,Uber 开源了基于 web 的自动驾驶可视化系统(AVS),称该系统为自动驾驶行业带来理解和共享数据的新方式.AVS 由Uber旗下负责自动驾驶汽车研发的技术事业群(ATG)开发,目前该系统已 ...

  2. matlab画图(一)

    例1.画出函数图像 >> x=-pi/2:0.01:pi/2; >> y=x+sin(x)+exp(x); >> plot(x,y,'r','Linewidth', ...

  3. 13、canvas操纵像素数据ImageData

    2019独角兽企业重金招聘Python工程师标准>>> 一.ImageData 对象 含义: 存储canvas对象真实的像素数据(每个像素块的RGBA色值) 属性: 1.width: ...

  4. Eclipse Collections:让Java Streams更上一层楼

    \ 关键要点 \\ Eclipse Collections是一个高性能的Java集合框架,为原生JDK集合增加了丰富的功能.\\t Streams是JDK的一个非常受欢迎的功能,但它缺少了一些特性,严 ...

  5. LeetCode 56,区间合并问题

    本文始发于个人公众号:TechFlow,原创不易,求个关注 今天是LeetCode专题的第33篇文章,我们一起来看LeetCode的第56题,它的难度是Medium. 题意 这道题的题意也很简单,只有 ...

  6. Python3中正则的贪婪匹配模式

    什么是贪婪模式 正则在进行匹配时,从开始位置查找最远的结束位置,这种模式称之为贪婪模式. 在进行HTML标签类似内容获取时,贪婪模式会导致整个内容的返回,需要使用非贪婪模式. 固定的书写规则 : .* ...

  7. JS实现显示来访者的停留时间

    显示来访者的停留时间 <script language="javascript"> var ap_name = navigator.appName; var ap_vi ...

  8. MinorGC前检查

  9. NLTK数据包下载频繁报错——解决方法

    问题描述:Nltk下载数据包,安装频繁报错. import nltk nltk.download() 运行上面的代码,下载nltk的数据包.但是在下载过程中因为各种问题导致网络传输失败,下载不成功. ...

  10. 微信小程序使用GoEasy实现websocket实时通讯

    不需要下载安装,便可以在微信好友.微信群之间快速的转发,用户只需要扫码或者在微信里点击,就可以立即运行,有着近似APP的用户体验,使得微信小程序成为全民热爱的好东西~ 同时因为微信小程序使用的是Jav ...