feat: 给受版权保护(DRM)的视频添加提示,并跳过视频处理

This commit is contained in:
lanyeeee
2026-02-04 20:44:28 +08:00
parent ff573f1de9
commit b7b99a8e43
6 changed files with 60 additions and 12 deletions
+1
View File
@@ -447,6 +447,7 @@ impl BiliClient {
"ep_id": ep_id,
"qn": 127,
"fnval": 4048,
"drm_tech_type": 2,
});
// 发送获取课程url的请求
let request = self
+22 -1
View File
@@ -66,6 +66,7 @@ pub struct DownloadProgress {
pub json_task: JsonTask,
pub create_ts: u64,
pub completed_ts: Option<u64>,
pub is_drm: bool,
}
impl DownloadProgress {
@@ -138,6 +139,7 @@ impl DownloadProgress {
json_task: tasks.json,
create_ts,
completed_ts: None,
is_drm: false,
};
Ok(progress)
@@ -185,6 +187,7 @@ impl DownloadProgress {
json_task: tasks.json,
create_ts,
completed_ts: None,
is_drm: false,
};
Ok(progress)
@@ -240,7 +243,16 @@ impl DownloadProgress {
tracing::debug!("{ids_string} `{filename}`音频下载任务完成");
}
if !video_process_task.is_completed() {
let video_process_task_is_completed = video_process_task.is_completed();
if self.is_drm && !video_process_task_is_completed {
download_task.update_progress(|p| {
p.video_process_task.skipped = true;
p.video_process_task.completed = true;
});
tracing::debug!(
"{ids_string} `{filename}`受版权保护(DRM),无法处理,已跳过视频处理任务"
);
} else if !video_process_task_is_completed {
video_process_task
.process(download_task, self, &mut player_info)
.await
@@ -359,6 +371,8 @@ impl DownloadProgress {
.await
.context("获取课程视频链接失败")?;
self.is_drm = media_url.is_drm;
if video_selected && !video_completed {
// 如果视频被选中且未完成,则准备视频任务
self.video_task.prepare_cheese(app, &media_url).await?;
@@ -507,6 +521,7 @@ fn create_normal_progresses_for_single(
json_task: tasks.json,
create_ts,
completed_ts: None,
is_drm: false,
};
return Ok(vec![progress]);
@@ -543,6 +558,7 @@ fn create_normal_progresses_for_single(
json_task: tasks.json,
create_ts,
completed_ts: None,
is_drm: false,
};
return Ok(vec![progress]);
@@ -579,6 +595,7 @@ fn create_normal_progresses_for_single(
json_task: tasks.json.clone(),
create_ts,
completed_ts: None,
is_drm: false,
};
progresses.push(progress);
@@ -647,6 +664,7 @@ fn create_normal_progresses_for_season(
json_task: tasks.json,
create_ts,
completed_ts: None,
is_drm: false,
};
return Ok(vec![progress]);
@@ -683,6 +701,7 @@ fn create_normal_progresses_for_season(
json_task: tasks.json,
create_ts,
completed_ts: None,
is_drm: false,
};
return Ok(vec![progress]);
@@ -720,6 +739,7 @@ fn create_normal_progresses_for_season(
json_task: tasks.json.clone(),
create_ts,
completed_ts: None,
is_drm: false,
};
progresses.push(progress);
@@ -766,6 +786,7 @@ impl Tasks {
embed_chapter_selected: config.embed_chapter,
embed_skip_selected: config.embed_skip,
completed: false,
skipped: false,
};
let danmaku = DanmakuTask {
@@ -24,11 +24,13 @@ pub struct VideoProcessTask {
pub embed_chapter_selected: bool,
pub embed_skip_selected: bool,
pub completed: bool,
pub skipped: bool,
}
impl VideoProcessTask {
pub fn mark_uncompleted(&mut self) {
self.completed = false;
self.skipped = false;
}
pub fn is_completed(&self) -> bool {
+1
View File
@@ -23,6 +23,7 @@ pub struct CheeseMediaUrl {
pub seek_type: String,
pub from: String,
pub video_codecid: i64,
pub is_drm: bool,
pub no_rexcode: i64,
pub format: String,
pub support_formats: Vec<SupportFormatInCheese>,
+2 -2
View File
@@ -284,7 +284,7 @@ export type Dimension = { width: number; height: number; rotate: number }
export type DimensionInBangumi = { height: number; rotate: number; width: number }
export type DimensionInWatchLater = { width: number; height: number; rotate: number }
export type DownloadEvent = { event: "Speed"; data: { speed: string } } | { event: "TaskCreate"; data: { state: DownloadTaskState; progress: DownloadProgress } } | { event: "TaskStateUpdate"; data: { task_id: string; state: DownloadTaskState } } | { event: "TaskSleeping"; data: { task_id: string; remaining_sec: number } } | { event: "TaskDelete"; data: { task_id: string } } | { event: "ProgressPreparing"; data: { task_id: string } } | { event: "ProgressUpdate"; data: { progress: DownloadProgress } }
export type DownloadProgress = { task_id: string; episode_type: EpisodeType; aid: number; bvid: string | null; cid: number; ep_id: number | null; duration: number; pub_ts: number; collection_title: string; part_title: string | null; part_order: number | null; episode_title: string; episode_order: number; up_name: string | null; up_uid: number | null; up_avatar: string | null; episode_dir: string; filename: string; video_task: VideoTask; audio_task: AudioTask; video_process_task: VideoProcessTask; subtitle_task: SubtitleTask; danmaku_task: DanmakuTask; cover_task: CoverTask; nfo_task: NfoTask; json_task: JsonTask; create_ts: number; completed_ts: number | null }
export type DownloadProgress = { task_id: string; episode_type: EpisodeType; aid: number; bvid: string | null; cid: number; ep_id: number | null; duration: number; pub_ts: number; collection_title: string; part_title: string | null; part_order: number | null; episode_title: string; episode_order: number; up_name: string | null; up_uid: number | null; up_avatar: string | null; episode_dir: string; filename: string; video_task: VideoTask; audio_task: AudioTask; video_process_task: VideoProcessTask; subtitle_task: SubtitleTask; danmaku_task: DanmakuTask; cover_task: CoverTask; nfo_task: NfoTask; json_task: JsonTask; create_ts: number; completed_ts: number | null; is_drm: boolean }
export type DownloadTaskState = "Pending" | "Downloading" | "Paused" | "Completed" | "Failed"
export type Ed = { end: number; start: number }
export type EpInBangumi = { aid: number; badge: string; badge_info: BadgeInfoInBangumi; badge_type: number | null; bvid: string | null; cid: number; cover: string; dimension: DimensionInBangumi | null; duration: number | null; enable_vt: boolean; ep_id: number; from: string | null; id: number; is_view_hide: boolean; link: string; link_type: string | null; long_title: string | null; pub_time: number; pv: number; release_date: string | null; rights: RightsInBangumiEp | null; section_type: number; share_copy: string | null; share_url: string | null; short_link: string | null; showDrmLoginDialog: boolean; show_title: string | null; skip: Skip | null; status: number; subtitle: string | null; title: string; vid: string | null; icon_font: IconFont | null }
@@ -420,7 +420,7 @@ export type UserStatusInCheese = { bp: number; expire_at: number; favored: numbe
export type UserVideoInfo = { list: UserVideoList; page: PageInUserVideo }
export type UserVideoList = { vlist: EpInUserVideo[] }
export type UserVideoSearchResult = UserVideoInfo
export type VideoProcessTask = { merge_selected: boolean; embed_chapter_selected: boolean; embed_skip_selected: boolean; completed: boolean }
export type VideoProcessTask = { merge_selected: boolean; embed_chapter_selected: boolean; embed_skip_selected: boolean; completed: boolean; skipped: boolean }
export type VideoQuality = "Unknown" | "240P" | "360P" | "480P" | "720P" | "720P60" | "1080P" | "AiRepair" | "1080P+" | "1080P60" | "4K" | "HDR" | "Dolby" | "8K"
export type VideoQualityAndCodecType = { video_quality: VideoQuality; codec_type: CodecType }
export type VideoTask = { selected: boolean; url: string; video_quality: VideoQuality; codec_type: CodecType; content_length: number; chunks: MediaChunk[]; completed: boolean; skipped: boolean }
@@ -149,12 +149,20 @@ function handleModifyClick() {
@contextmenu="handleProgressContextMenu"
@dblclick="handleProgressDoubleClick">
<div class="flex">
<img
class="w-224px h-140px rounded-lg object-cover lazyload"
:data-src="`${ensureHttps(p.cover_task.url)}@672w_378h_1c.webp`"
:key="p.cover_task.url"
alt=""
draggable="false" />
<div class="relative">
<img
class="w-224px h-140px rounded-lg object-cover lazyload"
:data-src="`${ensureHttps(p.cover_task.url)}@672w_378h_1c.webp`"
:key="p.cover_task.url"
alt=""
draggable="false" />
<div
v-if="p.is_drm"
class="absolute top-3 left-3 z-1 bg-red-5 text-white px-1 rounded"
title="该资源受版权保护(DRM)">
🔒DRM
</div>
</div>
<div class="ml-2 flex flex-col w-full overflow-hidden">
<div class="text-lg font-bold line-clamp-2" :title="p.episode_title">{{ p.episode_title }}</div>
@@ -187,9 +195,24 @@ function handleModifyClick() {
</span>
</ColorfulTag>
<ColorfulTag v-if="p.video_process_task.merge_selected" color="purple">自动合并</ColorfulTag>
<ColorfulTag v-if="p.video_process_task.embed_chapter_selected" color="purple">标记章节</ColorfulTag>
<ColorfulTag v-if="p.video_process_task.embed_skip_selected" color="purple">标记广告</ColorfulTag>
<ColorfulTag v-if="p.video_process_task.merge_selected" color="purple">
<span :class="{ 'text-gray': p.video_process_task.skipped }">
<span>自动合并</span>
<span v-if="p.video_process_task.skipped">(跳过)</span>
</span>
</ColorfulTag>
<ColorfulTag v-if="p.video_process_task.embed_chapter_selected" color="purple">
<span :class="{ 'text-gray': p.video_process_task.skipped }">
<span>标记章节</span>
<span v-if="p.video_process_task.skipped">(跳过)</span>
</span>
</ColorfulTag>
<ColorfulTag v-if="p.video_process_task.embed_skip_selected" color="purple">
<span :class="{ 'text-gray': p.video_process_task.skipped }">
<span>标记广告</span>
<span v-if="p.video_process_task.skipped">(跳过)</span>
</span>
</ColorfulTag>
<ColorfulTag v-if="p.danmaku_task.xml_selected" color="green">
<span :class="{ 'text-gray': p.danmaku_task.skipped }">