在B站看课的进度助手

效果

在这里插入图片描述

代码

BilibiliVideoDurationCrawler

import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import java.io.IOException;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;public class BilibiliVideoDurationCrawler {private static final Pattern VIDEO_PART_PATTERN = Pattern.compile("\"part\":\"(.*?)\",\"duration\":(\\d+),");/*** 主函数:根据视频链接获取视频分P信息并打印每一集的观看进度* 参数:args - 传入的命令行参数数组*/public static void main(String[] args) {// 根据视频链接获取视频分P信息的步骤String url = "https://www.bilibili.com/video/BV1834y1676P/";List<VideoPart> videoParts = new ArrayList<>();try {videoParts = getVideoPartsFromUrl(url); // 1. 获取网页源代码并爬取视频信息,转换为视频对象列表} catch (IOException | ParseException e) {System.err.println("获取视频信息失败:" + e.getMessage());return;}// 打印每一集所在进度的步骤if (!videoParts.isEmpty()) {for (int i = 0; i < videoParts.size(); i++) {String progress = getProgressStr(videoParts, i); // 获取指定集数的观看进度的字符串表示System.out.println("p" + (i + 1) + " " + videoParts.get(i).getPart() + " " + progress); // 打印集数、标题和进度}}}/*** 从给定的URL获取视频分段信息的列表。* @param url 需要解析的网页URL,预期包含视频分段的相关信息。* @return 返回一个包含视频分段及其持续时间的VideoPart对象列表。* @throws IOException 如果在连接或获取网页内容时发生IO异常。*/public static List<VideoPart> getVideoPartsFromUrl(String url) throws IOException, ParseException {// 使用Jsoup连接指定URL并获取网页内容,模拟浏览器行为Document doc = Jsoup.connect(url).userAgent("Mozilla/5.0").get();// 选择网页中所有的<script>元素Elements elements = doc.select("script");// 用于临时存储匹配到的视频分段信息List<String> result = new ArrayList<>();// 遍历所有<script>元素,尝试匹配视频分段信息for (Element element : elements) {Matcher matcher = VIDEO_PART_PATTERN.matcher(element.html());while (matcher.find()) {// 将匹配到的分段信息以字符串形式添加到result列表中result.add("Part: " + matcher.group(1) + ", Duration: " + matcher.group(2));}}// 从result列表中解析出VideoPart对象并添加到videoParts列表中List<VideoPart> videoParts = new ArrayList<>();// 优化 totalDuration 的计算, 避免重复计算long totalDuration = 0;for (String str : result) {// 分割字符串以获取分段名称和持续时间String[] parts = str.split(", ");String part = parts[0].split(": ")[1];long duration = Long.parseLong(parts[1].split(": ")[1]);totalDuration += duration;// 创建VideoPart对象并添加到列表VideoPart videoPart = new VideoPart(part, duration);videoParts.add(videoPart);}VideoPart.setTotalDuration(totalDuration);return videoParts;}/*** 计算给定视频片段列表中前p个片段的进度百分比,并返回格式化后的字符串。** @param videoParts 视频片段列表,每个片段包含持续时间。* @param p 计算进度时考虑的视频片段数量(从0开始)。* @return 返回计算出的进度百分比的字符串表示,保留两位小数。*/public static String getProgressStr(List<VideoPart> videoParts, int p) {// 验证参数合法性if (videoParts == null || p < 0 || p >= videoParts.size()) {throw new IllegalArgumentException("Invalid video parts or index p");}// 计算所有视频片段的总长度long totalLength = VideoPart.getTotalDuration();// 计算前p个视频片段的长度总和long lengthBeforeP = 0;for (int i = 0; i <= p; i++) {lengthBeforeP += videoParts.get(i).getDuration();}// 根据前面计算的长度,计算并返回进度百分比,结果保留两位小数double progress = (double) lengthBeforeP / (totalLength == 0 ? 1 : totalLength) * 100;return String.format("%.2f%%", progress);}
}

VideoPart

import lombok.AllArgsConstructor;
import lombok.Data;import java.util.Date;@Data
@AllArgsConstructor
/*** 视频部分信息类,用于描述视频的一个片段。*/
public class VideoPart {/*** 构造方法,初始化视频片段的信息。* @param part 视频片段的标识。* @param duration 视频片段的持续时间,单位为秒。*/public VideoPart(String part,long duration){this.part = part;this.duration = duration;}public static void setTotalDuration(long totalDuration) {VideoPart.totalDuration = totalDuration;}public static long getTotalDuration() {return totalDuration;}/*** 将持续时间转换为需要的时间对象。* 该方法将持续时间(秒)转换为Date对象,假设每秒为1000毫秒。*/public void Duration2NeedTime(){this.needTime = new Date(duration*1000);}private String part; // 视频片段标识private long duration; // 视频片段持续时间,单位为秒private Date needTime; // 视频片段需要的时间,Date对象表示private double progress; // 视频片段的进度private static long totalDuration =-1; // 所有视频片段的总持续时间,初始值为-1表示未计算
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/303455.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Git分布式版本控制系统——Git常用命令(一)

一、获取Git仓库--在本地初始化仓库 执行步骤如下&#xff1a; 1.在任意目录下创建一个空目录&#xff08;例如GitRepos&#xff09;作为我们的本地仓库 2.进入这个目录中&#xff0c;点击右键打开Git bash窗口 3.执行命令git init 如果在当前目录中看到.git文件夹&#x…

Redis 常用的基本命令

&#x1f525;博客主页&#xff1a;fly in the sky - CSDN博客 &#x1f680;欢迎各位&#xff1a;点赞&#x1f44d;收藏⭐️留言✍️&#x1f680; &#x1f386;慢品人间烟火色,闲观万事岁月长&#x1f386; &#x1f4d6;希望我写的博客对你有所帮助,如有不足,请指正&#…

【Linux】进程的状态(运行、阻塞、挂起)详解,揭开孤儿进程和僵尸进程的面纱,一篇文章万字讲透!!!!进程的学习②

目录 1.进程排队 时间片 时间片的分配 结构体内存对齐 偏移量补充 对齐规则 为什么会有对齐 2.操作系统学科层面对进程状态的理解 2.1进程的状态理解 ①我们说所谓的状态就是一个整型变量&#xff0c;是task_struct中的一个整型变量 ②.状态决定了接下来的动作 2.2运行状态 2.…

【JavaWeb】Day34.MySQL概述——数据库设计-DDL(一)

项目开发流程 需求文档&#xff1a; 在我们开发一个项目或者项目当中的某个模块之前&#xff0c;会先会拿到产品经理给我们提供的页面原型及需求文档。 设计&#xff1a; 拿到产品原型和需求文档之后&#xff0c;我们首先要做的不是编码&#xff0c;而是要先进行项目的设计&am…

荣湃半导体隔离芯片系列产品介绍和选型

一、公司简介 荣湃半导体&#xff08;上海&#xff09;有限公司成立于2017年&#xff0c;专注于高性能、高品质模拟芯片的设计与研发&#xff0c;凭借独创的电容智能分压技术&#xff08;iDivider技术&#xff09;&#xff0c;致力于成为全球技术领先的高性能模拟集成电路产品…

JVM基础篇

初识JVM Java虚拟机的组成 字节码文件 i与1 javap ideajclasslib arthas(线上运行的)

【小程序】常用方法、知识点汇总1

欢迎来到《小5讲堂》 这是《小程序》系列文章&#xff0c;每篇文章将以博主理解的角度展开讲解&#xff0c; 温馨提示&#xff1a;博主能力有限&#xff0c;理解水平有限&#xff0c;若有不对之处望指正&#xff01; 目录 前言请求超时Markdown解析逐行显示效果文本变动事件转发…

T527 Qt 触摸 ----- TSLIB

一、调试 1、驱动路径 bsp/drivers/input/ctp/gt9xx/gt9xx_ts.c 2、硬件接口 挂载在TWI0下 3、中断复位脚 4、设备树 &twi0 {clock-frequency <400000>;pinctrl-0 <&twi0_pins_default>;pinctrl-1 <&twi0_pins_sleep>;pinctrl-names &quo…

面试算法-172-对称二叉树

题目 给你一个二叉树的根节点 root &#xff0c; 检查它是否轴对称。 示例 1&#xff1a; 输入&#xff1a;root [1,2,2,3,4,4,3] 输出&#xff1a;true 解 class Solution {public boolean isSymmetric(TreeNode root) {return isSymm(root.left,root.right);}public b…

赛氪网|2024中国翻译协会年会“AI科技时代竞赛与就业”分论坛

在2024年中国翻译协会年会期间&#xff0c;赛氪网与中西部翻译协会共同体多边合作平台共同承办&#xff0c;于3月30日下午在长沙成功举办了“AI科技时代竞赛与就业分论坛”。该论坛汇聚了众多翻译界、科技界和教育界的专家学者&#xff0c;共同探讨科技、实践、就业与竞赛人才培…

【javaScript面试题】2023前端最新版javaScript模块,高频24问

&#x1f973;博 主&#xff1a;初映CY的前说(前端领域) &#x1f31e;个人信条&#xff1a;想要变成得到&#xff0c;中间还有做到&#xff01; &#x1f918;本文核心&#xff1a;博主收集的关于javaScript的面试题 目录 一、2023javaScript面试题精选 1.js的数据类型…

如何用Python编写简单的网络爬虫(页面代码简单分析过程)

一、什么是网络爬虫 在当今信息爆炸的时代&#xff0c;网络上蕴藏着大量宝贵的信息&#xff0c;如何高效地从中获取所需信息成为了一个重要课题。网络爬虫&#xff08;Web crawler&#xff09;作为一种自动化工具&#xff0c;可以帮助我们实现这一目标&#xff0c;用于数据分析…

注解式 WebSocket - 构建 群聊、单聊 系统

目录 前言 注解式 WebSocket 构建聊天系统 群聊系统&#xff08;基本框架&#xff09; 群聊系统&#xff08;添加昵称&#xff09; 单聊系统 WebSocket 作用域下无法注入 Spring Bean 对象&#xff1f; 考虑离线消息 前言 很久之前&#xff0c;咱们聊过 WebSocket 编程式…

Android 属性动画及自定义3D旋转动画

Android 动画框架 其中包括&#xff0c;帧动画、视图动画&#xff08;补间动画&#xff09;、属性动画。 在Android3.0之前&#xff0c;视图动画一家独大&#xff0c;之后属性动画框架被推出。属性动画框架&#xff0c;基本可以实现所有的视图动画效果。 视图动画的效率较高…

新品攻略—小功率、小体积、高效率!LED驱动模块RSC6218A

瑞森半导体&#xff08;REASUNOS&#xff09;推出应用在5W-18W LED电源上的LED驱动模块RSC6218A。 LED驱动模块RSC6218A是一款LLC 谐振拓扑功率模块&#xff0c;带有半桥驱动的控制电路和功率转化器件&#xff0c;适用于 LED 恒流控制线路&#xff0c;电路工作频率可达200KHz。…

MicroPython with LVGL

官方博客:Micropython LittlevGL | LVGL’s Blog github:GitHub - lvgl/lv_micropython: Micropython bindings to LVGL for Embedded devices, Unix and JavaScript 官方在线模拟器:https://sim.lvgl.io/(需要电脑能访问外网才能使用) 电脑不能访问外网会出现以下错误&…

GlusterFS分布式存储

目录 前言 一、GlusterFS分布式存储概述 1、GFS概念 2、GFS特点 3、GFS术语 4、GFS构成 5、GFS工作流程 6、后端存储如何定位文件 7、GlusterFs的卷类型 7.1 Distributed Volume&#xff08;分布式卷&#xff09; 7.2 Striped Volume&#xff08;条带卷&#xff09…

vue通过echarts实现数据可视化

1、安装echarts cnpm install echarts -Sechart官方图表示例大全&#xff1a;https://echarts.apache.org/examples/zh/index.html#chart-type-line 2、代码实现 <template><div><div class"box" ref"zhu"></div><div class&…

无线游戏手柄的测试(Windows11系统手柄调试方法)

实物 1、把游戏手柄的无线接收器插入到电脑usb接口中 2、【控制面板】----【查看设备和打印机】 3、【蓝牙和其它设备】--【更多设备和打印机设置】 4、鼠标右键【游戏控制器设置】 5、【属性】 6、【测试】&#xff08;每个按键是否正常&#xff09; 7、【校准】&#xff08;…

NLP在搜索召回领域中的应用场景

自然语言处理&#xff08;NLP&#xff09;在搜索召回领域中的应用场景非常广泛&#xff0c;它通过理解和分析人类语言&#xff0c;提高了信息检索的准确性和效率。以下是一些具体的应用场景&#xff1a; 1. 搜索引擎优化 NLP技术可以用于优化搜索引擎的查询处理&#xff0c;通…