郑重声明: 本人已购买该付费课程, 必须提前购买课程才可以下载。不是广告!
写这篇文章的目的是为了方便在本地播放和保存视频.
流程
- 获取播放列表
- 通过播放列表获取视频地址并生成Aria2c批量下载URL(指定文件名)
- 使用Aria2c进行下载视频
开始分析
打开DevTools,进入已购买的课程页面,点击开始学习
按钮,在DevTools筛选器上搜索all_lesson_list
此时获取到了一个URL,这个连接是所有课程数据列表,https://www.cctalk.com/webapi/content/v1.2/series/all_lesson_list?seriesId=1648563754438470&limit=&showStudyTime=false&_timestamp=1663807475982
seriesId=1648563754438470是课程ID在下面URL中使用。
继续通过分析从该链接https://www.cctalk.com/webapi/content/v1.1/series/1648563754438470/get_content_unit_struts
获取json数据,该数据中contentIdList
就是所有课程视频ID => videoId
{
"data": {
"seriesId": 1648563754438470,
"showType": 0,
"totalCount": 83,
"unitList": [{
"contentIdList": [
16486908151117,
......
],
"unitId": 0
}]
},
"message": "success",
"status": 0,
"time": "2022-09-22T09:24:25+0800"
}
通过上面的数据获取到了必要参数后,现在需要获取单个视频的json数据,经过分析发现通过该URLhttps://www.cctalk.com/webapi/content/v1.1/video/detail?videoId=16486908151117&seriesId=1648563754438470
可以获取到视频信息。
- videoId=16486908151117 视频ID
- seriesId=1648563754438470 课程ID
这2个参数是从上面步骤获取到的.
返回数据如下,在这里核心数据为videoUrl
这个是视频URL,通过访问该URL可以在线播放,也可以下载视频.同时也需要videoName
它是视频标题,使用它在下面下载视频保存文件时指定文件名.
{
"data": {
"adEnable": true,
"collectInfo": {
"collectCount": 2,
"collectStatus": 0,
"collectionContentId": 5096,
"contentId": 16486908151117,
"contentType": 1
},
"companyId": 0,
"coursewareInfo": {
"coursewareId": "1509184337896175193",
"ocsStatus": 0,
"tenantId": 10002,
"userSign": "K0JPWgQeSLvrlK551YiXHo3Xuq/TnKdqQ3sTnwo4LVUXcIN4HGEBPvvXtvGKsjPN1LVV+290fyfn2MGBdIu3jrlJxZ9f5JZeTmFbAPRSQ62rIgTK0hqizoUr+jyx+ne77tLjdTNQQd4ISF7XpJ+lsspshn6gu9dIB0T634KPiBEPMheGNHXq6xkEv3dE3aqtXTbPvzWGk27ezVG5qHpAlu8eTdIsAhepVtc5uF4fsPYopKlbXujRYRlg1NVUmdPXHOX3/gg8yFzpxDEb2u/pC5XFkYYJ5ztdBGtxA7r1OoSmMg/b2JaOenmkrd/Cze2PxBEWKt7PM2AUphUMwm0re6EeAf2aw5TlFksl6+WkCcxkSoUtVtw6ValjGo5AxWieNc5itJpA8OQ8TenBiBhikvrQiToJBh5Aw1QvfhgAVht7LcOUDOhFd2wAEJRoZMuPkGOAbixXVhV/5i9+80lg/3WXrRuCi8lDkn1W+NPsCVvDh0P8WKX3teCgfBXYR9Gl"
},
"coverUrl": "https://cc.hjfile.cn/cc/img/20220330/2022033011024002972564.jpg",
"createUserId": xxxxxx,
"enableCache": 1,
"feedbackInfo": {
"haveFeedback": 0
},
"groupId": 90268531,
"groupIsActive": 1,
"groupName": "vol框架开发实战讲解.NetCore vue uni-app",
"hideRating": false,
"hideReserveButton": false,
"intro": {
"section": [{
"contentStruct": {},
"contents": []
}]
},
"isCharge": 1,
"isGroupMember": true,
"isOpenProtection": false,
"isReserve": true,
"isTrial": false,
"knowledgeList": [],
"likeCount": 2,
"likeStatus": 0,
"liveNum": 0,
"liveStartDate": "2022-03-31T09:40:15+0800",
"liveStatus": 11,
"logo": "vol",
"logoShowStatus": 0,
"mediaTotalTime": 411000,
"openType": 1,
"pagePermission": 1,
"playCount": 1881,
"playPermission": 1,
"ratingCount": 6,
"reserveCount": 0,
"reviewStatus": 21,
"seriesInfo": {
"coverUrl": "https://cc.hjfile.cn/cc/img/20220329/2022032910204179033032.jpg",
"hasSubscribe": true,
"seriesId": 1648563754438470,
"seriesName": "vol框架视频",
"subscribeCount": 336,
"videoCount": 83
},
"showRecommend": false,
"starAvg": 5.0,
"studyPosition": 0,
"taskInfo": {},
"totalSize": 40894464,
"trialDuration": -1,
"userCard": {
"avatar": "https://i2n.hjfile.cn/u/default/ext/200/5.jpg",
"followedMeCount": 366,
"nickName": "vol",
"relationStatus": 1,
"summary": "多年.net、vue前后端分离开发经验.",
"userId": xxxxxx,
"userName": "QQ用户xxxx"
},
"videoCut": 0,
"videoEndDate": "2022-03-31T09:47:06+0800",
"videoId": 16486908151117,
"videoName": "框架介绍",
"videoStartDate": "2022-03-31T09:40:15+0800",
"videoType": 0,
"videoUrl": "https://record-manual.cctalk.com/5285d79daf63dd321eb89d912a9236d5.mp4?auth_key=1663823958-58b24996728341e69d9ec573d356f669-0-0606fbe337ddd193046cff6ffc121ee9"
},
"message": "success",
"status": 0
}
到目前为止已经完成了基本的分析,下面开始写代码
c#代码
在下面代码中需要填写2个参数,第一个是填写自己的COOKIE,使用自己的账号登录后,从浏览器中复制cookie,第二个是课程ID,await Getcourse("1648563754438470");
这里传递的参数是课程ID
使用nuget
添加以下2个扩展,同时本地需要安装redis数据库,如果没有可以改代码,使用SortedList
代替redis
- StackExchange.Redis
- Newtonsoft.Json
Program.cs
// See https://aka.ms/new-console-template for more information
using StackExchange.Redis;
using System.Net.Http.Headers;
using System.Net;
using Newtonsoft.Json;
using System;
using Newtonsoft.Json.Converters;
using System.Globalization;
using System;
using System.Collections.Generic;
using static CCtalk.Program;
namespace CCtalk
{
class Program
{
public static string global_cookies = "填写自己的COOKIE";//使用自己的账号登录后,从浏览器中复制cookie
//连接redis服务器
public static ConnectionMultiplexer redis = ConnectionMultiplexer.Connect("localhost");
//获取redis数据库
public static IDatabase db = redis.GetDatabase();
static async Task Main(string[] args)
{
//获取课程所有视频ID
await Getcourse("1648563754438470");
//获取最终视频播放地址并把地址写入txt文件,最后使用aria2c工具进行批量下载
await Getcontent();
}
/// <summary>
/// 获取最终视频播放地址并把地址写入txt文件,最后使用aria2c工具进行批量下载
/// </summary>
/// <returns></returns>
public static async Task Getcontent()
{
//获取桌面路径
string desktopPath = Environment.GetFolderPath(Environment.SpecialFolder.DesktopDirectory);
//在桌面生成cctalk.txt文件
using (FileStream fs = new FileStream(desktopPath + @"\cctalk.txt", FileMode.OpenOrCreate, FileAccess.ReadWrite))
{
using (StreamWriter sw = new StreamWriter(fs))
{
//获取redis数据
var full_redis_json_data = await db.HashGetAllAsync("cctalk_contentIdLists");
//遍历数据
foreach (var item in full_redis_json_data)
{
//获取单个视频JSON数据,提取VideoName和videoUrl
var result = await Browser(item.Value.ToString());
//解析json数据
var contents = Contents.FromJson(result);
//把数据保存到redis数据库,进行备份操作,方便后续使用,也可以使用自己编写代码进行下载视频.
// key为1. 框架介绍.mp4,value为最终视频URL地址
await db.HashSetAsync("cctalk_VideoLists", item.Name.ToString() + "." + contents.Data.VideoName.ToString() + ".mp4", contents.Data.VideoUrl.ToString());
//把数据写入txt文件,输入格式为Aria2c下载格式并指定文件名
Task task = sw.WriteLineAsync(contents.Data.VideoUrl.ToString() + "\r\n" + " out=" + item.Name.ToString() + "." + contents.Data.VideoName.ToString() + ".mp4");
}
}
}
}
/// <summary>
/// 获取课程所有视频ID
/// </summary>
/// <param name="seriesId">课程ID</param>
/// <returns></returns>
public static async Task Getcourse(string seriesId)
{
var kechengURL = "https://www.cctalk.com/webapi/content/v1.1/series/" + seriesId.ToString() + "/get_content_unit_struts";
string url_begin = "https://www.cctalk.com/webapi/content/v1.1/video/detail?videoId=";
string url_end = "&seriesId="+ seriesId.ToString()+ "&_timestamp=1663738877186";
//获取JSON数据
var result = await Browser(kechengURL);
//解析JSON数据
var course = Course.FromJson(result);
var i = 1;
//遍历course,获取所有视频ID
foreach (var item in course.Data.UnitList[0].ContentIdList)
{
//拼接完整单个视频访问URL地址
var final_url = url_begin + item.ToString() + url_end;
//将视频ID和完整URL存入redis数据库, key为i,value为完整URL地址
var redis_hastset = await db.HashSetAsync("cctalk_contentIdLists", i.ToString(), final_url.ToString());
i += 1;
}
}
public partial class Course
{
[JsonProperty("data")]
public Data Data { get; set; }
[JsonProperty("message")]
public string Message { get; set; }
[JsonProperty("status")]
public long Status { get; set; }
[JsonProperty("time")]
public string Time { get; set; }
}
public partial class Data
{
[JsonProperty("seriesId")]
public long SeriesId { get; set; }
[JsonProperty("showType")]
public long ShowType { get; set; }
[JsonProperty("totalCount")]
public long TotalCount { get; set; }
[JsonProperty("unitList")]
public UnitList[] UnitList { get; set; }
}
public partial class UnitList
{
[JsonProperty("contentIdList")]
public long[] ContentIdList { get; set; }
[JsonProperty("unitId")]
public long UnitId { get; set; }
}
public partial class Course
{
public static Course FromJson(string json) => JsonConvert.DeserializeObject<Course>(json, Converter.Settings);
}
public partial class Contents
{
[JsonProperty("data")]
public Data Data { get; set; }
[JsonProperty("message")]
public string Message { get; set; }
[JsonProperty("status")]
public long Status { get; set; }
}
public partial class Data
{
[JsonProperty("adEnable")]
public bool AdEnable { get; set; }
[JsonProperty("collectInfo")]
public CollectInfo CollectInfo { get; set; }
[JsonProperty("companyId")]
public long CompanyId { get; set; }
[JsonProperty("coursewareInfo")]
public CoursewareInfo CoursewareInfo { get; set; }
[JsonProperty("coverUrl")]
public Uri CoverUrl { get; set; }
[JsonProperty("createUserId")]
public long CreateUserId { get; set; }
[JsonProperty("enableCache")]
public long EnableCache { get; set; }
[JsonProperty("feedbackInfo")]
public FeedbackInfo FeedbackInfo { get; set; }
[JsonProperty("groupId")]
public long GroupId { get; set; }
[JsonProperty("groupIsActive")]
public long GroupIsActive { get; set; }
[JsonProperty("groupName")]
public string GroupName { get; set; }
[JsonProperty("hideRating")]
public bool HideRating { get; set; }
[JsonProperty("hideReserveButton")]
public bool HideReserveButton { get; set; }
[JsonProperty("intro")]
public Intro Intro { get; set; }
[JsonProperty("isCharge")]
public long IsCharge { get; set; }
[JsonProperty("isGroupMember")]
public bool IsGroupMember { get; set; }
[JsonProperty("isOpenProtection")]
public bool IsOpenProtection { get; set; }
[JsonProperty("isReserve")]
public bool IsReserve { get; set; }
[JsonProperty("isTrial")]
public bool IsTrial { get; set; }
[JsonProperty("knowledgeList")]
public object[] KnowledgeList { get; set; }
[JsonProperty("likeCount")]
public long LikeCount { get; set; }
[JsonProperty("likeStatus")]
public long LikeStatus { get; set; }
[JsonProperty("liveNum")]
public long LiveNum { get; set; }
[JsonProperty("liveStartDate")]
public string LiveStartDate { get; set; }
[JsonProperty("liveStatus")]
public long LiveStatus { get; set; }
[JsonProperty("logo")]
public string Logo { get; set; }
[JsonProperty("logoShowStatus")]
public long LogoShowStatus { get; set; }
[JsonProperty("mediaTotalTime")]
public long MediaTotalTime { get; set; }
[JsonProperty("openType")]
public long OpenType { get; set; }
[JsonProperty("pagePermission")]
public long PagePermission { get; set; }
[JsonProperty("playCount")]
public long PlayCount { get; set; }
[JsonProperty("playPermission")]
public long PlayPermission { get; set; }
[JsonProperty("ratingCount")]
public long RatingCount { get; set; }
[JsonProperty("reserveCount")]
public long ReserveCount { get; set; }
[JsonProperty("reviewStatus")]
public long ReviewStatus { get; set; }
[JsonProperty("seriesInfo")]
public SeriesInfo SeriesInfo { get; set; }
[JsonProperty("showRecommend")]
public bool ShowRecommend { get; set; }
[JsonProperty("starAvg")]
public long StarAvg { get; set; }
[JsonProperty("studyPosition")]
public long StudyPosition { get; set; }
[JsonProperty("taskInfo")]
public TaskInfo TaskInfo { get; set; }
[JsonProperty("totalSize")]
public long TotalSize { get; set; }
[JsonProperty("trialDuration")]
public long TrialDuration { get; set; }
[JsonProperty("userCard")]
public UserCard UserCard { get; set; }
[JsonProperty("videoCut")]
public long VideoCut { get; set; }
[JsonProperty("videoEndDate")]
public string VideoEndDate { get; set; }
[JsonProperty("videoId")]
public long VideoId { get; set; }
[JsonProperty("videoName")]
public string VideoName { get; set; }
[JsonProperty("videoStartDate")]
public string VideoStartDate { get; set; }
[JsonProperty("videoType")]
public long VideoType { get; set; }
[JsonProperty("videoUrl")]
public Uri VideoUrl { get; set; }
}
public partial class CollectInfo
{
[JsonProperty("collectCount")]
public long CollectCount { get; set; }
[JsonProperty("collectStatus")]
public long CollectStatus { get; set; }
[JsonProperty("contentId")]
public long ContentId { get; set; }
[JsonProperty("contentType")]
public long ContentType { get; set; }
}
public partial class CoursewareInfo
{
[JsonProperty("coursewareId")]
public string CoursewareId { get; set; }
[JsonProperty("ocsStatus")]
public long OcsStatus { get; set; }
[JsonProperty("tenantId")]
public long TenantId { get; set; }
[JsonProperty("userSign")]
public string UserSign { get; set; }
}
public partial class FeedbackInfo
{
[JsonProperty("haveFeedback")]
public long HaveFeedback { get; set; }
}
public partial class Intro
{
[JsonProperty("section")]
public Section[] Section { get; set; }
}
public partial class Section
{
[JsonProperty("contentStruct")]
public TaskInfo ContentStruct { get; set; }
[JsonProperty("contents")]
public object[] Contents { get; set; }
}
public partial class TaskInfo
{
}
public partial class SeriesInfo
{
[JsonProperty("coverUrl")]
public Uri CoverUrl { get; set; }
[JsonProperty("hasSubscribe")]
public bool HasSubscribe { get; set; }
[JsonProperty("seriesId")]
public long SeriesId { get; set; }
[JsonProperty("seriesName")]
public string SeriesName { get; set; }
[JsonProperty("subscribeCount")]
public long SubscribeCount { get; set; }
[JsonProperty("videoCount")]
public long VideoCount { get; set; }
}
public partial class UserCard
{
[JsonProperty("avatar")]
public Uri Avatar { get; set; }
[JsonProperty("followedMeCount")]
public long FollowedMeCount { get; set; }
[JsonProperty("nickName")]
public string NickName { get; set; }
[JsonProperty("relationStatus")]
public long RelationStatus { get; set; }
[JsonProperty("summary")]
public string Summary { get; set; }
[JsonProperty("userId")]
public long UserId { get; set; }
[JsonProperty("userName")]
public string UserName { get; set; }
}
public partial class Contents
{
public static Contents FromJson(string json) => JsonConvert.DeserializeObject<Contents>(json, Converter.Settings);
}
internal static class Converter
{
public static readonly JsonSerializerSettings Settings = new JsonSerializerSettings
{
MetadataPropertyHandling = MetadataPropertyHandling.Ignore,
DateParseHandling = DateParseHandling.None,
Converters =
{
new IsoDateTimeConverter { DateTimeStyles = DateTimeStyles.AssumeUniversal }
},
};
}
/// <summary>
/// 获取HTML数据的通用方法
/// </summary>
/// <param name="target_url">URL</param>
/// <returns>返回HTML body</returns>
public static async Task<string> Browser(string target_url)
{
var handler = new HttpClientHandler();
//handler.UseCookies = false;
handler.AutomaticDecompression = ~DecompressionMethods.None;
handler.AllowAutoRedirect = true;
handler.UseProxy = false;
using (var httpClient = new HttpClient(handler))
{
using (var request = new HttpRequestMessage(new HttpMethod("GET"), target_url))
{
request.Headers.TryAddWithoutValidation("authority", "www.cctalk.com");
request.Headers.TryAddWithoutValidation("accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9");
request.Headers.TryAddWithoutValidation("accept-language", "ko,en;q=0.9,en-US;q=0.8");
request.Headers.TryAddWithoutValidation("cache-control", "max-age=0");
request.Headers.TryAddWithoutValidation("sec-ch-ua", "\"Microsoft Edge\";v=\"105\", \" Not;A Brand\";v=\"99\", \"Chromium\";v=\"105\"");
request.Headers.TryAddWithoutValidation("sec-ch-ua-mobile", "?0");
request.Headers.TryAddWithoutValidation("sec-ch-ua-platform", "\"Windows\"");
request.Headers.TryAddWithoutValidation("sec-fetch-dest", "document");
request.Headers.TryAddWithoutValidation("sec-fetch-mode", "navigate");
request.Headers.TryAddWithoutValidation("sec-fetch-site", "none");
request.Headers.TryAddWithoutValidation("sec-fetch-user", "?1");
request.Headers.TryAddWithoutValidation("upgrade-insecure-requests", "1");
request.Headers.TryAddWithoutValidation("user-agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/105.0.0.0 Safari/537.36 Edg/105.0.1343.42");
request.Headers.TryAddWithoutValidation("cookie", global_cookies);
var response = await httpClient.SendAsync(request);
if ((int)response.StatusCode == 200)
{
//获取响应内容
var responseString = await response.Content.ReadAsStringAsync();
//打印相应代码和状态
return responseString;
}
else
{
Console.WriteLine("Requests blocked!");
return "None";
}
}
}
}
}
}
SerializeHelpers.cs
using Newtonsoft.Json;
using static CCtalk.Program;
// See https://aka.ms/new-console-template for more information
namespace CCtalk
{
internal static class SerializeHelpers
{
public static string ToJson(this Course self) => JsonConvert.SerializeObject(self, Converter.Settings);
}
}
通过运行上面代码,在桌面生成cctalk.txt
文件,格式如下 注意此时获取到视频URL地址有效期是暂时的需要尽快下载
https://record-manual.cctalk.com/5285d79daf63dd321eb89d912a9236d5.mp4?auth_key=1663762237-9d1a425a08454c78aa1a9cf661672790-0-eff1d4dc9c30856e583d5230ae0221f6
out=1.框架介绍.mp4
现在使用Aria2c进行视频下载,打开CMD切换到cctalk.txt
文件所在目录,然后执行以下命令行进行下载,COOKIE为使用自己的账号登录CCtalk后,从浏览器中复制cookie
aria2c --header="Cookie: 填写自己的COOKIE" -i cctalk.txt
使用Aria2c工具进行下载视频的原因是它是专业下载工具。专业的事情交给专业的人去做,这才是科学的。
Aria2c下载结果
Download Results:
gid |stat|avg speed |path/URI
======+====+===========+=======================================================
780456|OK | 10MiB/s|C:/Users/user/Downloads/cct/38.树形table-tree配置-2.mp4
462b9c|OK | 10MiB/s|C:/Users/user/Downloads/cct/66.移动端-弹出框扫描二维码与自定义组件.mp4
0febfd|OK | 6.9MiB/s|C:/Users/user/Downloads/cct/3.项目启动异常排查.mp4
9593a5|OK | 5.0MiB/s|C:/Users/user/Downloads/cct/15.框架文档入门-前端.mp4
c5efc5|OK | 5.3MiB/s|C:/Users/user/Downloads/cct/41.框架全文档1-表格格式化、点击事件、自定义按钮.mp4
3e52cc|OK | 8.8MiB/s|C:/Users/user/Downloads/cct/71.centos+nginx后台部署.mp4
255c68|OK | 7.4MiB/s|C:/Users/user/Downloads/cct/24.后台代码源码位置.mp4
12a72c|OK | 7.4MiB/s|C:/Users/user/Downloads/cct/75.(补录)通用导出excel文件.mp4
0ea407|OK | 7.1MiB/s|C:/Users/user/Downloads/cct/43.框架全文档3-多弹出框与组件扩展.mp4
3582d1|OK | 7.8MiB/s|C:/Users/user/Downloads/cct/17.前后端代码调试.mp4
e5f8e2|OK | 10MiB/s|C:/Users/user/Downloads/cct/22.后台业务代码扩展-1.mp4
b1a7c2|OK | 8.2MiB/s|C:/Users/user/Downloads/cct/16.框架文档入门-后台.mp4
e4fd28|OK | 9.4MiB/s|C:/Users/user/Downloads/cct/21.vue基本操作创建页面与调用接口.mp4
9d5c59|OK | 9.8MiB/s|C:/Users/user/Downloads/cct/31.自定义组件扩展4-权限相关.mp4
7fddd2|OK | 10MiB/s|C:/Users/user/Downloads/cct/13.多表关联生成代码.mp4
c78d25|OK | 10MiB/s|C:/Users/user/Downloads/cct/20.后台配置appsettings.json说明.mp4
6cfd1b|OK | 11MiB/s|C:/Users/user/Downloads/cct/62.移动端-自定义底部tabBar修改.mp4
ddadb2|OK | 10MiB/s|C:/Users/user/Downloads/cct/48.框架全文档6-1-打印与自定义权限按钮.mp4
804249|OK | 10MiB/s|C:/Users/user/Downloads/cct/73.centos+nginx绑定域名.mp4
1868d4|OK | 11MiB/s|C:/Users/user/Downloads/cct/42.框架全文档2-表格显示合计汇总.mp4
0a22be|OK | 11MiB/s|C:/Users/user/Downloads/cct/30.自定义组件扩展3-选择数据.mp4
f2c11a|OK | 7.1MiB/s|C:/Users/user/Downloads/cct/29.自定义组件扩展2-弹出框.mp4
397597|OK | 10MiB/s|C:/Users/user/Downloads/cct/19.后台swagger接口调试.mp4
376587|OK | 10MiB/s|C:/Users/user/Downloads/cct/9.代码生成器详解3.mp4
73009b|OK | 10MiB/s|C:/Users/user/Downloads/cct/54.前端通用方法封装.mp4
cb5aa3|OK | 6.1MiB/s|C:/Users/user/Downloads/cct/72.centos+nginx前端部署.mp4
775dc4|OK | 9.6MiB/s|C:/Users/user/Downloads/cct/79.审批流程介绍与更新.mp4
0101cc|OK | 2.8MiB/s|C:/Users/user/Downloads/cct/39.树形table-递归设置默认值-3.mp4
49fc2a|OK | 8.0MiB/s|C:/Users/user/Downloads/cct/80.审批流程配置与审核.mp4
41b0ae|OK | 9.0MiB/s|C:/Users/user/Downloads/cct/53.框架全文档10-生成页面方法实现.mp4
88e7c5|OK | 9.0MiB/s|C:/Users/user/Downloads/cct/60.移动端-项目启动.mp4
2fcce7|OK | 9.6MiB/s|C:/Users/user/Downloads/cct/28.自定义组件扩展1-增加选择器.mp4
487c86|OK | 8.6MiB/s|C:/Users/user/Downloads/cct/23.后台业务代码扩展-2.mp4
a6b614|OK | 7.7MiB/s|C:/Users/user/Downloads/cct/46.框架全文档5-1-在线编辑与多表显示.mp4
f8869c|OK | 8.7MiB/s|C:/Users/user/Downloads/cct/37.树形table配置-1.mp4
b9c59c|OK | 11MiB/s|C:/Users/user/Downloads/cct/44.框架全文档4-1-select联动(省市县).mp4
d674b6|OK | 11MiB/s|C:/Users/user/Downloads/cct/7.代码生成器详解1.mp4
b5e460|OK | 5.3MiB/s|C:/Users/user/Downloads/cct/47.框架全文档5-2-多表显示加载table数据.mp4
808ef7|OK | 3.7MiB/s|C:/Users/user/Downloads/cct/2.境配置与项目启动与.mp4
073274|OK | 11MiB/s|C:/Users/user/Downloads/cct/5.代码生成入门.mp4
01bd8a|OK | 4.5MiB/s|C:/Users/user/Downloads/cct/4.项目结构目录介绍.mp4
c6b065|OK | 4.5MiB/s|C:/Users/user/Downloads/cct/26.vue基础语法说明.mp4
229ef3|OK | 10MiB/s|C:/Users/user/Downloads/cct/76.(补录)一对多-1.mp4
28d7e3|OK | 5.9MiB/s|C:/Users/user/Downloads/cct/45.框架全文档4-2-select联动(省市县).mp4
322e3a|OK | 7.3MiB/s|C:/Users/user/Downloads/cct/81.审批条件、节点控制与发送邮件.mp4
5ea81d|OK | 7.9MiB/s|C:/Users/user/Downloads/cct/55.数据库访问EF.mp4
e06075|OK | 11MiB/s|C:/Users/user/Downloads/cct/74.(补录)echarts图表使用.mp4
e1cb6a|OK | 10MiB/s|C:/Users/user/Downloads/cct/10.代码生成器级联.mp4
1d593e|OK | 8.2MiB/s|C:/Users/user/Downloads/cct/32.自定义组件扩展5-根据条件隐藏按钮.mp4
d1c0e6|OK | 11MiB/s|C:/Users/user/Downloads/cct/25.后台代码IOC注入.mp4
7cd390|OK | 6.1MiB/s|C:/Users/user/Downloads/cct/40.生成自增流水单号.mp4
2c18c4|OK | 9.0MiB/s|C:/Users/user/Downloads/cct/69.移动端-list自定义多个按钮.mp4
8e0ee1|OK | 6.4MiB/s|C:/Users/user/Downloads/cct/68.移动端-table调用自定义弹出框.mp4
6ba6b0|OK | 12MiB/s|C:/Users/user/Downloads/cct/49.框架全文档6-2-打印与自定义权限按钮.mp4
1f0686|OK | 11MiB/s|C:/Users/user/Downloads/cct/51.框架全文档8-设置默认值.mp4
b9eba7|OK | 6.3MiB/s|C:/Users/user/Downloads/cct/50.框架全文档7-表单日期范围限制与只读.mp4
30c17f|OK | 8.2MiB/s|C:/Users/user/Downloads/cct/6.代码生成文件介绍.mp4
ff0d7e|OK | 6.0MiB/s|C:/Users/user/Downloads/cct/36.明细表扩展-4-搜索功能.mp4
ee2977|OK | 11MiB/s|C:/Users/user/Downloads/cct/70.项目发布windows+iis.mp4
35b8a9|OK | 12MiB/s|C:/Users/user/Downloads/cct/18.前端谷歌调试插件.mp4
502138|OK | 6.1MiB/s|C:/Users/user/Downloads/cct/14.框架文档介绍.mp4
1b7417|OK | 10MiB/s|C:/Users/user/Downloads/cct/27.表高度设置与固定查询显示.mp4
d11580|OK | 6.8MiB/s|C:/Users/user/Downloads/cct/34.明细表扩展-2-table配置.mp4
0803b9|OK | 5.4MiB/s|C:/Users/user/Downloads/cct/8.代码生成器详解2.mp4
6bbf90|OK | 11MiB/s|C:/Users/user/Downloads/cct/83.定时任务(Quartz)配置.mp4
65b88c|OK | 6.7MiB/s|C:/Users/user/Downloads/cct/64.移动端-table显示、格式化、宽度设置、换行显示.mp4
976aeb|OK | 9.9MiB/s|C:/Users/user/Downloads/cct/63.移动端-代码生成页面.mp4
ee8a67|OK | 7.1MiB/s|C:/Users/user/Downloads/cct/1.框架介绍.mp4
26bb1a|OK | 7.3MiB/s|C:/Users/user/Downloads/cct/57.租户管理(数据隔离).mp4
84fb7e|OK | 10MiB/s|C:/Users/user/Downloads/cct/35.明细表扩展-3-回写数据.mp4
ab5e07|OK | 7.4MiB/s|C:/Users/user/Downloads/cct/59.uniapp与微信小程序环境配置.mp4
f71551|OK | 10MiB/s|C:/Users/user/Downloads/cct/82.定时任务(Quartz)更新说明.mp4
1258a1|OK | 7.7MiB/s|C:/Users/user/Downloads/cct/56.数据库访问Dapper.mp4
70d94f|OK | 10MiB/s|C:/Users/user/Downloads/cct/67.移动端-table添加按钮与单元格点击事件.mp4
c4aad1|OK | 7.1MiB/s|C:/Users/user/Downloads/cct/65.移动端-扫描二维码与自定义组件.mp4
52bc15|OK | 9.3MiB/s|C:/Users/user/Downloads/cct/33.明细表扩展-1-弹出框.mp4
fffa43|OK | 9.8MiB/s|C:/Users/user/Downloads/cct/78.框架更新与文件差异比较.mp4
a9bd1e|OK | 10MiB/s|C:/Users/user/Downloads/cct/12.主从表数据源绑定.mp4
0a2297|OK | 6.8MiB/s|C:/Users/user/Downloads/cct/52.框架全文档9-生成页面属性配置.mp4
73004e|OK | 10MiB/s|C:/Users/user/Downloads/cct/61.移动端-目录结构介绍.mp4
88c057|OK | 6.6MiB/s|C:/Users/user/Downloads/cct/11.主从表生成代码.mp4
fe1073|OK | 9.8MiB/s|C:/Users/user/Downloads/cct/77.(补录)一对多-2.mp4
0fa3ce|OK | 476KiB/s|C:/Users/user/Downloads/cct/58.页面复用(生成页面配置为多个菜单).mp4
Status Legend:
(OK):download completed.