前言

继上一篇使用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. SQL语句学习(一)

    这篇文章用来记录再学习SQL语句的过程. 首先,我们从简单的创建表开始.创建表的语法是CREATE TABLE 表名(列1的名字  列1的属性,列2的名字  列2的属性...); 如果希望将某一列作为 ...

  2. 内蒙古特检院利用物联网/RFID技术提高电梯检测水平

    随着电梯检验工作信息化进程的进一步深入,内蒙古特检院从检验工作中寻找新方法.新手段,为检验员新引入电梯检验手持终端设备,力求提高电梯检验水平,将"电梯安全惠民工程"落到实处. 电梯 ...

  3. 外媒解读Web安全核心PKI的四大致命问题

    Web安全的立足根基在于复杂的PKI部署体系,但实际生活中得到正确部署的比例却非常有限,而且这一切都将随着摩尔定律的滚滚洪流灰飞烟灭. 我个人算是PKI(即公共密钥基础设施)的忠实拥护者.我热爱数学与 ...

  4. Intellij IDEA 使用Spring-boot-devTools

    转载地址:https://blog.csdn.net/u013938484/article/details/77541050 转载于:https://blog.51cto.com/881206524/ ...

  5. 51NOD 2072 装箱问题 背包问题 01 背包 DP 动态规划

    有一个箱子容量为 V(正整数,0<=V<=20000),同时有 n 个物品(0<n<=30),每个物品有一个体积(正整数). 现在在 n 个物品中,任取若干个装入箱内,使得箱子 ...

  6. Pthon学习相关

    1. Cython入门教程:https://www.jianshu.com/p/cfcc2c04a6f5

  7. IP 基础知识全家桶,45 张图一套带走

    前言 前段时间,有读者希望我写一篇关于 IP 分类地址.子网划分等的文章,他反馈常常混淆,摸不着头脑. 那么,说来就来!而且要盘就盘全一点,顺便挑战下小林的图解功力,所以就来个 IP 基础知识全家桶. ...

  8. 似乎是最实用的hashtable知识总结

    哈希表:将对象转换为索引,然后存储在数组中. 定义注意点: 对象:就是面向对象中的对象,可以为任何东西.整数.浮点数.日期.字符串.类. 转换:通过hash函数来完成,hash函数是hash表的核心与 ...

  9. 数据库——数据库SQL语句大全,最常用的SQL语句

    检索数据 检索单个列: SELECT pname FROM product 检索多个列: SELECT pname,market_price,is_hot FROM product 检索所有列: SE ...

  10. x86软路由虚拟化openwrt-koolshare-mod-v2.33联通双拨IPV6教程(第二篇)

    续第一篇:https://www.cnblogs.com/zlAurora/p/12433296.html   4 设置多拨 (1)连入OpenWrt Web界面,默认为192.168.1.1,在“网 ...