c#操作cctalk视频下载(代码片段)

哲虎 哲虎     2023-04-01     134

关键词:

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

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

流程

  1. 获取播放列表
  2. 通过播放列表获取视频地址并生成Aria2c批量下载URL(指定文件名)
  3. 使用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; 

            [

c#中利用npoi包操作excel文件(代码片段)

...供ISheet、IRow、ICell等接口usingNPOI.XSSF.UserModel;//提供相关类操作扩展名为xlsx的2007之后版本E 查看详情

你不一定知晓的c#取消异步操作(代码片段)

原文:【你不一定知晓的】C#取消异步操作在.Net和C#中运行异步代码相当简单,因为我们有时候需要取消正在进行的异步操作,通过本文,可以掌握通过CancellationToken取消任务(包括non-cancellable任务)。 早期早期.Net使用Backgroun... 查看详情

c#操作svg矢量图-nuget库svg(代码片段)

文章目录NuGet测试文档NuGet新建C#应用配置包源工具->NuGet包管理器->程序包管理器设置新建包源https://www.nuget.org/api/v2/安装svg测试测试数据博客不支持SVG格式,只能放入网盘,下载后放在D盘目录下。(使用其他svg图... 查看详情

c#中简单操作mysql数据库(代码片段)

以C#访问MySQL数据库,执行简单的CRUD。MySql.Data.dll是C#操作MySQL的驱动文件,是C#连接MySQL必要插件,使C#语言更简洁的操作MySQL数据库。可以用NuGet命令安装 PM>Install-PackageMySql.Data-Version8.0.16项目中添加该组件的引用,在代码页... 查看详情

c#中的原子操作(代码片段)

某天,我同学发给我这样一道题。看着还是挺简单的,我当时就想到了线程等待。使用AutoResetEvent类来两个线程互相等待,互相通知1classProgram23staticAutoResetEventautoResetEvent1=newAutoResetEvent(false);4staticAutoResetEventautoResetEvent2=newAutoResetEv... 查看详情

c#操作excel总结(代码片段)

 1、导入命名空间: usingMicrosoft.Office.Interop.Excel; 2、如何打开已有excel文档,或者创建一个新的excel文档 Applicationapp=newApplication();Workbookswbks=app.Workbooks;_Workbook_wbk=wbks.Add(excelTempPath+"qu 查看详情

c#操作高低位(代码片段)

1.int32占4个字节intdata=2147483647;byte[]byte4=newbyte[4];byte4=BitConverter.GetBytes(data);//结果逆序2.int16占2个字节:intdata=32767;bytehigh=Convert.ToByte((data>>8)&0x00ff);//位运算:右移8位bytelow=Convert.T 查看详情

关于c#中async/await的用法(代码片段)

...,async/await成对出现才有意义。其意义在于可以等待异步操作完成后继续顺序执行,而不是异步操作还没处理完成主线程就进行了下一步。  假设,我们现在要模拟简单的下载场景,首先用户点击下载,那么就调用DownloadHa... 查看详情

c#操作mongodb(代码片段)

1安装MongoDB.Driver2建立数据库连接#mongodb://127.0.0.1:27017MongoClientclient=newMongoClient(“连接字符串”);3获取数据库vardatabase=client.GetDatabase("数据库");4获取数据集Collection#如果数据是预先定义好的可以在<输入数据的类型>,如果是没有... 查看详情

c#字符串的操作(代码片段)

vartStr="0|1:开门|2:关门|3:门检失败|4:开门|5:开门|6:关门";varresult=string.Format("[0]",string.Join(",",tStr.Substring(2).Split(‘|‘).Select(s=>string.Format("doorid:0,status:1",s.Split(‘:‘)[0],s.Split( 查看详情

c#学习笔记(19)操作sqlserver下(代码片段)

C#学习笔记(19)操作SQLServer下ADO.net操作数据库这应该是比较老的技术了,以后有空的话学学Linq///<summary>///数据库使用类///</summary>publicstaticclassMySqlHelper///<summary>///1.数据库连接字符串///</summary 查看详情

c#学习笔记(18)操作sqlserver中(代码片段)

C#学习笔记(18)操作SQLServer中数据库基础操作SQL语法可以参考菜鸟教程或者微软官方的SQL示例注意SQL不区分大小写查1.基础查询--最基础的查询语句,select*fromtable_nameselect*fromstudentTable2.条件查询--条件查询select*fromtable... 查看详情

c#一个简单办法判断操作系统版本(代码片段)

做个记录,最近写个小软件,涉及到判断操作系统版本的,查看了微软的相关资料,感觉以及网上的一些Demo,感觉不全,而且有些系统也不好区分。因为之前写过批处理版本的操作系统判断使用了WMIC的命令,所以一想放到C#试... 查看详情

c#中利用npoi包操作excel文件(代码片段)

...供ISheet、IRow、ICell等接口usingNPOI.XSSF.UserModel;//提供相关类操作扩展名为xlsx的2007之后版本Excel文件usingNPOI.HSSF.UserModel;//提供相关类操作扩展名为xls的2007之前版本Excel文件完整代码如下usingSystem;usingSystem.IO;//提供文件流文件和文件流... 查看详情

c#中利用npoi包操作excel文件(代码片段)

...供ISheet、IRow、ICell等接口usingNPOI.XSSF.UserModel;//提供相关类操作扩展名为xlsx的2007之后版本Excel文件usingNPOI.HSSF.UserModel;//提供相关类操作扩展名为xls的2007之前版本Excel文件完整代码如下usingSystem;usingSystem.IO;//提供文件流文件和文件流... 查看详情

c#下载文件(代码片段)

usingSystem;usingSystem.Collections.Generic;usingSystem.Linq;usingSystem.Text;usingSystem.Threading.Tasks;usingSystem.Net;WebClientwebClient=newWebClient();stringurl="http://192.168.1.171: 查看详情

c#基础之ado.net(代码片段)

...DO.NET事务   定义:所谓事务,可以看做是一个操作单元,是最小的操作单位,在这个事务中的操作,要么全部执行成功,要么全部失败。  在一个事务性操作的环境下,操作有着以下的4种特性,被称为ACID特性... 查看详情

c#学习笔记(17)操作sqlserver上(代码片段)

C#学习笔记(17)操作SQLServer上安装SQLServer微软官网https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads如果不使用局域网访问数据库,安装默认功能即可安装完毕后需要重启电脑启动SQLServer如果该服务没有启动,将其... 查看详情