c#操作CCtalk视频下载

郑重声明: 本人已购买该付费课程, 必须提前购买课程才可以下载。不是广告!

购买截图

写这篇文章的目的是为了方便在本地播放和保存视频.

流程

  1. 获取播放列表
  2. 通过播放列表获取视频地址并生成Aria2c批量下载URL(指定文件名)
  3. 使用Aria2c进行下载视频

开始分析

打开DevTools,进入已购买的课程页面,点击开始学习按钮,在DevTools筛选器上搜索all_lesson_list

在这里插入图片描述

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.
  • 21
    点赞
  • 40
    收藏
    觉得还不错? 一键收藏
  • 28
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 28
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值