I downloaded a Youtube downloader from Github it was a WPF and it works however I want to reproduce this C# for Windows App. The original code from WPF is:
public async Task BeginDownload()
{
if (!CheckInputs())
return;
ChangeButtonStates(false);
string link = videoLink.Text;
string? downloadFormat = null;
string savedDirectory = Properties.Settings.Default.savedDirectory;
if (saveMP3.IsChecked == true)
downloadFormat = "mp3";
else
downloadFormat = "mp4";
try
{
cancellationToken = cancellationTokenSource.Token;
// If the given URL contains "&list" it means it is playlist
if (!link.Contains("&list"))
await DownloadSingle(link, savedDirectory, downloadFormat);
else
await DownloadPlaylist(link, savedDirectory, downloadFormat);
}
catch (Exception ex)
{
new Thread(() =>
{
MessageBox.Show($"An error occurred: \"{ex.Message}\".", "Downloader", MessageBoxButton.OK, MessageBoxImage.Error);
}).Start();
}
ChangeButtonStates(true);
}
My code converted for use with windows form
public async Task BeginDownload()
{
if (!CheckInputs())
return;
ChangeButtonStates(false);
string link = videoLink.Text;
string downloadFormat = null;
string savedDirectory = Properties.Settings.Default.savedDirectory;
if (cmbDownloadType.SelectedIndex == 1)
downloadFormat = "mp3";
else
downloadFormat = "mp4";
try
{
cancellationToken = cancellationTokenSource.Token;
//// If the given URL contains "&list" it means it is playlist
//if (!link.Contains("&list"))
await DownloadSingle(link, savedDirectory, downloadFormat);
//else
//await DownloadPlaylist(link, savedDirectory, downloadFormat);
}
catch (Exception ex)
{
new Thread(() =>
{
MessageBox.Show($"An error occurred: \"{ex.Message}\".", "Downloader", MessageBoxButtons.OK, MessageBoxIcon.Error);
}).Start();
}
ChangeButtonStates(true);
}
for simplicity I commented out playlist I can add it later I only want to start with a single download. When I run my code it get a html error not sure how to troubleshoot the error.
WPF code to download single
public async Task DownloadSingle(string link, string path, string format)
{
// Needed for security
var handler = new HttpClientHandler();
var httpClient = new HttpClient(handler, true);
handler.UseCookies = false;
// Get video data
var youtube = new YoutubeClient(httpClient);
var streamData = await youtube.Videos.GetAsync(link);
var title = ReplaceInvalidCharacters(streamData.Title);
var progress = new Progress<double>(value =>
{
// To split the progress bar into two halves, fill one half and then the next,
// maximum of both progress bars is 50
if (downloadProgressOne.Value != 50)
{
downloadProgressOne.Value = value * 100.00f;
}
else
{
downloadProgressTwo.Value = (value * 100.00f) - 50;
}
// Taskbar icon progress bar
taskbarIcon.ProgressValue = value;
downloadStatus.Text = $"Downloading... {Convert.ToInt32(value * 100.00f)}%";
});
try
{
// Download content
await youtube.Videos.DownloadAsync(link, $"{path}\\{title}.{format}", o => o.SetContainer(format).SetPreset(ConversionPreset.UltraFast), progress, cancellationToken);
}
catch (TaskCanceledException)
{
new Thread(() =>
{
MessageBox.Show($"Successfully cancelled the download of: \"{title}\".", "Downloader", MessageBoxButton.OK, MessageBoxImage.Information);
}).Start();
File.Delete($"{path}\\{title}.{format}");
return;
}
catch (Exception ex)
{
new Thread(() =>
{
MessageBox.Show($"Failed to download video: \"{title}\" due to an error.\n\nReason: \"{ex.Message}\".", "Downloader", MessageBoxButton.OK, MessageBoxImage.Warning);
}).Start();
return;
}
new Thread(() =>
{
MessageBox.Show($"Successfully downloaded video: \"{title}\".", "Downloader", MessageBoxButton.OK, MessageBoxImage.Information);
}).Start();
}
public async Task DownloadPlaylist(string link, string path, string format)
{
// Create a string list incase any videos fail to download
List<string> failedVideosTitles = new();
string finalList = "";
int failedVideosAmount = 0;
// Needed for security
var handler = new HttpClientHandler();
var httpClient = new HttpClient(handler, true);
handler.UseCookies = false;
// Get playlist data
var youtube = new YoutubeClient(httpClient);
var playlistData = await youtube.Playlists.GetAsync(link);
var playlistName = ReplaceInvalidCharacters(playlistData.Title);
var total = await youtube.Playlists.GetVideosAsync(link);
var totalNumber = total.Count;
int currentNumber = 0;
// Foreach video in the playlist try to download them as the desired format
await foreach (var video in youtube.Playlists.GetVideosAsync(playlistData.Id))
{
currentNumber++;
var title = ReplaceInvalidCharacters(video.Title);
// Skip download of video if it already exists
if (File.Exists($"{path}\\{title}.{format}"))
{
downloadStatus.Text = $"Skipping {currentNumber}/{totalNumber}...";
await Task.Delay(100);
continue;
}
var progress = new Progress<double>(value =>
{
// To split the progress bar into two halves, fill one half and then the next,
// maximum of both progress bars is 50
if (value < 0.5f || downloadProgressOne.Value < 50)
{
downloadProgressOne.Value = value * 100.00f;
downloadProgressTwo.Value = 0;
}
else
downloadProgressTwo.Value = (value * 100.00f) - 50;
// Taskbar icon progress bar
taskbarIcon.ProgressValue = value;
downloadStatus.Text = $"Downloading... {currentNumber}/{totalNumber} - {Convert.ToInt32(value * 100.00f)}%";
});
try
{
// Download content
await youtube.Videos.DownloadAsync(video.Id, $"{path}\\{title}.{format}", o => o.SetContainer(format).SetPreset(ConversionPreset.UltraFast), progress, cancellationToken);
}
catch (TaskCanceledException)
{
new Thread(() =>
{
MessageBox.Show($"Successfully cancelled the download of playlist: \"{playlistName}\".\n\nFiles have not been deleted.", "Downloader", MessageBoxButton.OK, MessageBoxImage.Information);
}).Start();
File.Delete($"{path}\\{title}.{format}");
return;
}
catch (Exception ex)
{
new Thread(() =>
{
// Increase the failed videos amount by one and add the title to the list
failedVideosAmount++;
failedVideosTitles.Add($"\"{title}\"");
MessageBox.Show($"Skipping download of video: \"{title}\" due to an error.\n\nReason: \"{ex.Message}\".", "Downloader", MessageBoxButton.OK, MessageBoxImage.Warning);
}).Start();
}
}
if (failedVideosAmount != 0)
{
new Thread(() =>
{
// Show a messagebox telling the user it failed to download X amount of videos
MessageBox.Show($"Downloaded playlist: \"{playlistName}\" but failed to download {failedVideosAmount} of the videos.\n\nPress OK to see list of failed videos.", "Downloader", MessageBoxButton.OK, MessageBoxImage.Warning);
// Loop for the length of the string list, build a final string containing
// a list of titles of failed videos then display it in a messagebox for the user
for (int i = 0; i < failedVideosTitles.Count; i++)
{
if (i == 0) { finalList = $"{finalList}{i + 1}. {failedVideosTitles[i]}."; }
else { finalList = $"{finalList}\n\n{i + 1}. {failedVideosTitles[i]}."; }
}
MessageBox.Show(finalList, "Downloader", MessageBoxButton.OK, MessageBoxImage.Information);
}).Start();
}
else
{
new Thread(() =>
{
// The entire playlist was downloaded successfully
MessageBox.Show($"Successfully downloaded playlist: \"{playlistName}\".", "Downloader", MessageBoxButton.OK, MessageBoxImage.Information);
}).Start();
}
}
my converted code
public async Task DownloadSingle(string link, string path, string format)
{
// Needed for security
var handler = new HttpClientHandler();
var httpClient = new HttpClient(handler, true);
handler.UseCookies = false;
// Get video data
var youtube = new YoutubeClient(httpClient);
var streamData = await youtube.Videos.GetAsync(link);
var title = ReplaceInvalidCharacters(streamData.Title);
var progress = new Progress<double>(value =>
{
// To split the progress bar into two halves, fill one half and then the next,
// maximum of both progress bars is 50
if (downloadProgressOne.Value != 50)
{
downloadProgressOne.Value = (int)(value * 100.00f);
}
else
{
downloadProgressTwo.Value = (int)((value * 100.00f) - 50);
}
// Taskbar icon progress bar
//taskbarIcon.ProgressValue = value;
downloadStatus.Text = $"Downloading... {Convert.ToInt32(value * 100.00f)}%";
});
try
{
// Download content
await youtube.Videos.DownloadAsync(link, $"{path}\\{title}.{format}", o => o.SetContainer(format).SetPreset(ConversionPreset.UltraFast), progress, cancellationToken);
}
catch (TaskCanceledException)
{
new Thread(() =>
{
MessageBox.Show($"Successfully cancelled the download of: \"{title}\".", "Downloader", MessageBoxButtons.OK, MessageBoxIcon.Information);
}).Start();
File.Delete($"{path}\\{title}.{format}");
return;
}
catch (Exception ex)
{
new Thread(() =>
{
MessageBox.Show($"Failed to download video: \"{title}\" due to an error.\n\nReason: \"{ex.Message}\".", "Downloader", MessageBoxButtons.OK, MessageBoxIcon.Warning);
}).Start();
return;
}
new Thread(() =>
{
MessageBox.Show($"Successfully downloaded video: \"{title}\".", "Downloader", MessageBoxButtons.OK, MessageBoxIcon.Information);
}).Start();
}
Argh rookie mistake just had to update the nuget package for codepages.
Why is it that my script will produce the correct results when doing this:
let data = await page.evaluate(async () => {
let multipleVideosUnorderedList = await document
.querySelector('article > div')
.querySelector('ul');
let video = [];
if (multipleVideosUnorderedList != null) {
let multipleVideosList = multipleVideosUnorderedList.children;
console.log(multipleVideosList);
for (i = 0; i < multipleVideosList.length; i++) {
let rightBtn = document.querySelector(
'button > div.coreSpriteRightChevron'
);
if (rightBtn) {
await rightBtn.parentNode.click();
}
let videoUrl = multipleVideosList[i].querySelector('video');
if (videoUrl) {
video.push(videoUrl.getAttribute('src'));
}
}
} else {
video.push(document.querySelector('video').getAttribute('src'));
}
return {
video
};
});
console.log(data);
But when it deduce it down to just this:
let er = await page.evaluate(() => {
let multipleVideosUnorderedList = document.querySelector('article > div').querySelector('ul');
return {
multipleVideosUnorderedList
}
});
console.log(er);
the result is undefined. I know there's a lot more code in the former, but I just wanted to see it produce the correct element before I move on to grabbing everything else.
The idea was to take out the document.querySelector in code block and clean it up, to try to use page.$(selector) instead.
Only serializable objects can go into and out of page.evaluate, a NodeList and a Node, which are found with querySelectorAll/querySelector, are not such things.
You probably would like to find an unordered list wich may contain several videos. If this is the case you could rewrite the code in the following way:
let outerVideos = await page.evaluate(() => {
// convert the NodeList to an array
let videos = [...document.querySelectorAll('article > div video')]
// for each member of the array replace the video node with its src value
.map(video => video.getAttribute('src'));
return videos;
});
console.log(outerVideos);
I work with sounds in a browser game. I wrote sound manager. everything works fine, but not in Google chrome. I handled the error "uncaught (in promise) domexception", after the sounds were played in 50 percent of cases, in other cases it returns the error DOMException. What could be the problem?
export class AudioFile{
private audio: HTMLAudioElement;
private fileMP3: string;
private fileOGG: string;
private volume = 1;
private loop = false;
constructor(MP3:string, OGG:string) {
this.audio = new Audio();
this.fileMP3 = MP3;
this.fileOGG = OGG;
this.audio.canPlayType('audio/mpeg') ? this.audio.src = this.fileMP3 : this.audio.src = this.fileOGG;
this.audio.load();
this.audio.volume = this.volume;
this.audio.loop = this.loop;
}
public play() {
this.audio.currentTime = 0;
const playPromise = this.audio.play();
if (playPromise !== undefined) {
playPromise.then(_ => {
})
.catch(error => {
console.log(error);
});
}
}
public stop() {
this.audio.pause();
}
}
``````````````sound manager`````````````
export class SoundManager {
private sounds = new Map();
private static _soundManager: SoundManager;
constructor(){
if (SoundManager._soundManager) {
throw new Error("Instantiation failed: "+
"use Singleton.getInstance() instead of new.");
}
SoundManager._soundManager = this;
}
public static get instance(): SoundManager {
if (this._soundManager)
return this._soundManager;
else
return this._soundManager = new SoundManager();
}
preload() {
const pathMP3 = SoundConfig.PATHMP3;
const pathOGG = SoundConfig.PATHOGG;
for (const item in SoundConfig.SOUNDS) {
const name = SoundConfig.SOUNDS[item].NAME;
this.sounds.set(name, new AudioFile(pathMP3 + name + '.mp3', pathOGG + name + '.ogg'));
}
}
getSound(id: string): AudioFile {
return this.sounds.get(id);
}
}
Thank you spendr.
error: DOMException
code: 0
message: "play() failed because the user didn't interact with the document first.
Game runs through the iframe and I was needed to add a feature policy for autoplay.
<iframe src="..." allow="autoplay">
The article that helped me in solving the problem
I have a react component that I am using as checkpoint to check if the user has viewed a certain section of the site.
class ContentSection extends Component {
constructor(props) {
super(props);
}
render() {
const allParagraphs = [];
for (let i = 0; i < this.props.paragraphs.length; i++) {
let p = this.props.paragraphs[i];
allParagraphs.push(
<Paragraph key={i} image={p["img"]} text={p["text"]} />
);
}
return (
<div className="cs">
<ContentSectionCheckPointContainer
uniqueIndex={this.props.uniqueIndex}
/>
<h4 className="sectionTitle">THIS IS A SECTION!!!</h4>
{allParagraphs}
</div>
);
}
}
And this is the ContentSectionCheckPointContainer
const mapDispatchToProps = dispatch => {
return {
unlock: index => dispatch(Unlock_Index_Action(index))
};
};
const mapStateToProps = state => {
return {
CheckPoints: [...state.CheckPoints]
};
};
class ContentSectionCheckPoint extends Component {
constructor(props) {
super(props);
this.myRef = React.createRef();
this.myRect = null;
this.checkVisibility = this.checkVisibility.bind(this);
}
componentDidMount() {
this.checkVisibility();
window.addEventListener('scroll', this.checkVisibility);
}
componentWillUnmount() {
window.removeEventListener('scroll', this.checkVisibility);
}
checkVisibility() {
if (this.myRef.current) {
let rect = this.myRef.current.getBoundingClientRect();
var viewHeight = Math.max(
document.documentElement.clientHeight,
window.innerHeight
);
let b = !(rect.bottom < 0 || rect.top - viewHeight >= 0);
if (b !== this.props.CheckPoints[this.props.uniqueIndex]) {
if (b) {
this.props.unlock(this.props.uniqueIndex);
}else{
this.props.unlock(this.props.uniqueIndex);
}
}
}
}
render() {
this.checkVisibility();
return (
<div ref={this.myRef} className="cscp">
{this.props.CheckPoints[this.props.uniqueIndex] && <p>hi</p>}
</div>
);
}
}
const ContentSectionCheckPointContainer = connect(
mapStateToProps, mapDispatchToProps)(ContentSectionCheckPoint);
As you can see I ran a visibility check on scroll, which works fine. However, I wanted to also run the visibility check immediately when the page is loaded before any scrolling occur.
It is to my understanding that componentDidMount is when React already rendered an element for the first time, so I wanted to do the check then. However, I was trying to render two ContentSection components, each containing their own check point. The latter check point for unknown reason is positioned higher than it appears on screen during componentDidMount, resulting in my visibility check returning true even though it is not visible. If I refresh the page, its position is correct again and the visibility check is fine.
This problem only seem to occur during the first time when I open up a new tab to load my code, but no longer occurs after a refresh on that tab.
Any idea why?
I need to run test in two browsers with the same view but logged with different users. As the server is changing the cookie and logging out the first user because of the shared cookie between multiple windows in Chrome I cannot run the test. So, I wonder if it is possible to run a Chrome normal instance and an incognito one simultaneously.
Another option is to run a Chrome and a Firefox instance but I need to control what to do with each browser.
You can use two browsers. Run a script to find out which browser you are in and then have different users to log based on that.
First, get the browser, here is a script for that:
browser.getCapabilities()
.then(function(s) {
var platform = s.caps_.platform,
browserName = s.caps_.browserName,
browserVersion = s.caps_.version,
shortVersion = browserVersion.split('.')[0],
ie = /i.*explore/.test(browserName),
ff = /firefox/.test(browserName),
ch = /chrome/.test(browserName),
sa = /safari/.test(browserName),
shortName;
if (ie) {
shortName = 'ie';
} else if (ff) {
shortName = 'ff';
} else if (ch) {
shortName = 'ch';
} else if (sa) {
shortName = 'sa';
} else {
throw new Exception('Unsupported browser: '+ browserName);
}
// Returns one of these: ['ch', 'ff', 'sa', 'ie']
browser.getShortBrowserName = function() {
return shortName;
};
// Returns one of these: ['ch33', 'ff27', 'sa7', 'ie11', 'ie10', 'ie9']
browser.getShortNameVersionAll = function() {
return shortName + shortVersion;
};
// Returns one of these: ['ch', 'ff', 'sa', 'ie11', 'ie10', 'ie9']
browser.getShortNameVersion = function() {
if (ie) {
return shortName + shortVersion;
} else {
return shortName;
}
};
// Return if current browser is IE, optionally specifying if it is a particular IE version
browser.isIE = function(ver) {
if (!ver) {
return ie;
} else {
return ie && ver.toString() === shortVersion;
}
};
browser.isSafari = function() {
return sa;
};
browser.isFirefox = function() {
return ff;
};
// Return if current browser is Chrome, optionally specifying if it is a particular Chrome version
browser.isChrome = function(ver) {
if (!ver) {
return ch;
} else {
return ch && ver.toString() === shortVersion;
}
};
then you need a function to know which user to log in:
global.getUserAndPassword = function getUser() {
var rv_user = process.env.PROTRACTOR_USER;
if (browser.isFireFox() && typeof process.env.PROTRACTOR_USER_2 !== 'undefined') {
rv_user = process.env.PROTRACTOR_USER_2;
}
return [rv_user, process.env.PROTRACTOR_PASSWORD];
};
and then a login function:
global.loginFn = function loginFn() {
var user_and_pass = getUserAndPassword();
username.sendKeys(user_and_pass[0]);
password.sendKeys(user_and_pass[1]);
login.click();
};