Merge branch 'master' of https://github.com/Tzahi12345/YoutubeDL-Material into download-manager
commit
ff403d18d1
@ -0,0 +1 @@
|
|||||||
|
<button *ngIf="show_skip_ad_button" (click)="skipAdButtonClicked()" mat-flat-button><ng-container i18n="Skip ad button">Skip ad</ng-container></button>
|
@ -0,0 +1,25 @@
|
|||||||
|
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
|
import { SkipAdButtonComponent } from './skip-ad-button.component';
|
||||||
|
|
||||||
|
describe('SkipAdButtonComponent', () => {
|
||||||
|
let component: SkipAdButtonComponent;
|
||||||
|
let fixture: ComponentFixture<SkipAdButtonComponent>;
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
await TestBed.configureTestingModule({
|
||||||
|
declarations: [ SkipAdButtonComponent ]
|
||||||
|
})
|
||||||
|
.compileComponents();
|
||||||
|
});
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
fixture = TestBed.createComponent(SkipAdButtonComponent);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create', () => {
|
||||||
|
expect(component).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
@ -0,0 +1,107 @@
|
|||||||
|
import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core';
|
||||||
|
import { PostsService } from 'app/posts.services';
|
||||||
|
import CryptoJS from 'crypto-js';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-skip-ad-button',
|
||||||
|
templateUrl: './skip-ad-button.component.html',
|
||||||
|
styleUrls: ['./skip-ad-button.component.scss']
|
||||||
|
})
|
||||||
|
export class SkipAdButtonComponent implements OnInit {
|
||||||
|
|
||||||
|
@Input() current_video = null;
|
||||||
|
@Input() playback_timestamp = null;
|
||||||
|
|
||||||
|
@Output() setPlaybackTimestamp = new EventEmitter<any>();
|
||||||
|
|
||||||
|
sponsor_block_cache = {};
|
||||||
|
show_skip_ad_button = false;
|
||||||
|
|
||||||
|
constructor(private postsService: PostsService) { }
|
||||||
|
|
||||||
|
ngOnInit(): void {
|
||||||
|
setInterval(() => this.skipAdButtonCheck(), 500);
|
||||||
|
}
|
||||||
|
|
||||||
|
checkSponsorBlock(video_to_check) {
|
||||||
|
if (!video_to_check) return;
|
||||||
|
|
||||||
|
// check cache, null means it has been checked and confirmed not to exist (limits API calls)
|
||||||
|
if (this.sponsor_block_cache[video_to_check.url] || this.sponsor_block_cache[video_to_check.url] === null) return;
|
||||||
|
|
||||||
|
// sponsor block needs first 4 chars from video ID hash
|
||||||
|
const video_id = this.getVideoIDFromURL(video_to_check.url);
|
||||||
|
const id_hash = this.getVideoIDHashFromURL(video_id);
|
||||||
|
if (!id_hash || id_hash.length < 4) return;
|
||||||
|
const truncated_id_hash = id_hash.substring(0, 4);
|
||||||
|
|
||||||
|
// we couldn't get the data from the cache, let's get it from sponsor block directly
|
||||||
|
|
||||||
|
this.postsService.getSponsorBlockDataForVideo(truncated_id_hash).subscribe(res => {
|
||||||
|
if (res && res['length'] && res['length'] === 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const found_data = res['find'](data => data['videoID'] === video_id);
|
||||||
|
if (found_data) {
|
||||||
|
this.sponsor_block_cache[video_to_check.url] = found_data;
|
||||||
|
}
|
||||||
|
}, err => {
|
||||||
|
// likely doesn't exist
|
||||||
|
this.sponsor_block_cache[video_to_check.url] = null;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
getVideoIDHashFromURL(video_id) {
|
||||||
|
if (!video_id) return null;
|
||||||
|
return CryptoJS.SHA256(video_id).toString(CryptoJS.enc.Hex);;
|
||||||
|
}
|
||||||
|
|
||||||
|
getVideoIDFromURL(url) {
|
||||||
|
const regex_exp = /^.*((youtu.be\/)|(v\/)|(\/u\/\w\/)|(embed\/)|(watch\?))\??v?=?([^#&?]*).*/;
|
||||||
|
const match = url.match(regex_exp);
|
||||||
|
return (match && match[7].length==11) ? match[7] : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
skipAdButtonCheck() {
|
||||||
|
const sponsor_block_data = this.sponsor_block_cache[this.current_video.url];
|
||||||
|
if (!sponsor_block_data && sponsor_block_data !== null) {
|
||||||
|
// we haven't yet tried to get the sponsor block data for the video
|
||||||
|
this.checkSponsorBlock(this.current_video);
|
||||||
|
} else if (!sponsor_block_data) {
|
||||||
|
this.show_skip_ad_button = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.getTimeToSkipTo()) {
|
||||||
|
this.show_skip_ad_button = true;
|
||||||
|
} else {
|
||||||
|
this.show_skip_ad_button = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
getTimeToSkipTo() {
|
||||||
|
const sponsor_block_data = this.sponsor_block_cache[this.current_video.url];
|
||||||
|
|
||||||
|
if (!sponsor_block_data) return;
|
||||||
|
|
||||||
|
// check if we're in between an ad segment
|
||||||
|
const found_segment = sponsor_block_data['segments'].find(segment_data => this.playback_timestamp > segment_data.segment[0] && this.playback_timestamp < segment_data.segment[1] - 0.5);
|
||||||
|
|
||||||
|
if (found_segment) {
|
||||||
|
return found_segment['segment'][1];
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
skipAdButtonClicked() {
|
||||||
|
const time_to_skip_to = this.getTimeToSkipTo();
|
||||||
|
if (!time_to_skip_to) return;
|
||||||
|
|
||||||
|
this.setPlaybackTimestamp.emit(time_to_skip_to);
|
||||||
|
|
||||||
|
this.show_skip_ad_button = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in New Issue