From e4829e509056bcab6e32876ba78072ad38471d19 Mon Sep 17 00:00:00 2001 From: Nicholas Parkanyi Date: Sat, 9 Sep 2017 21:11:15 -0400 Subject: [PATCH 01/26] isYoutubeURL() --- src/mpc-hc/PlayerPlaylistBar.cpp | 23 +++++++++++++++++++---- src/mpc-hc/PlayerPlaylistBar.h | 5 ++++- 2 files changed, 23 insertions(+), 5 deletions(-) diff --git a/src/mpc-hc/PlayerPlaylistBar.cpp b/src/mpc-hc/PlayerPlaylistBar.cpp index 61accd7dc7e..a4a734af081 100644 --- a/src/mpc-hc/PlayerPlaylistBar.cpp +++ b/src/mpc-hc/PlayerPlaylistBar.cpp @@ -804,10 +804,12 @@ OpenMediaData* CPlayerPlaylistBar::GetCurOMD(REFERENCE_TIME rtStart) } } else { if (OpenFileData* p = DEBUG_NEW OpenFileData()) { - p->fns.AddTailList(&pli->m_fns); - p->subs.AddTailList(&pli->m_subs); - p->rtStart = rtStart; - return p; + if (!isYoutubeURL(pli->m_fns.GetHead()) { + p->fns.AddTailList(&pli->m_fns); + p->subs.AddTailList(&pli->m_subs); + p->rtStart = rtStart; + return p; + } } } @@ -1808,3 +1810,16 @@ void CPlayerPlaylistBar::OnXButtonDblClk(UINT nFlags, UINT nButton, CPoint point { OnXButtonDown(nFlags, nButton, point); } + +bool CPlayerPlaylistBar::isYoutubeURL(CString url) +{ + if (url.Left(8) == _T("https:\\")) { + url = url.Right(url.GetLength() - 8); + } + + if (url.Left(4) == _T("www.")) { + url = url.Right(url.GetLength() - 4); + } + + return url.Left(17) == _T("youtube.com/watch"); +} \ No newline at end of file diff --git a/src/mpc-hc/PlayerPlaylistBar.h b/src/mpc-hc/PlayerPlaylistBar.h index 4c3c962ec2b..fe089aa2243 100644 --- a/src/mpc-hc/PlayerPlaylistBar.h +++ b/src/mpc-hc/PlayerPlaylistBar.h @@ -160,4 +160,7 @@ class CPlayerPlaylistBar : public CPlayerBar, public CDropClient afx_msg void OnXButtonDown(UINT nFlags, UINT nButton, CPoint point); afx_msg void OnXButtonUp(UINT nFlags, UINT nButton, CPoint point); afx_msg void OnXButtonDblClk(UINT nFlags, UINT nButton, CPoint point); -}; + +private: + bool isYoutubeURL(CString url); +}; \ No newline at end of file From bb275f1216ae71ce1a9de476f969395faa1c0162 Mon Sep 17 00:00:00 2001 From: Nicholas Parkanyi Date: Sat, 9 Sep 2017 21:28:20 -0400 Subject: [PATCH 02/26] update copyright --- src/mpc-hc/PlayerPlaylistBar.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mpc-hc/PlayerPlaylistBar.h b/src/mpc-hc/PlayerPlaylistBar.h index fe089aa2243..c13a1a542f4 100644 --- a/src/mpc-hc/PlayerPlaylistBar.h +++ b/src/mpc-hc/PlayerPlaylistBar.h @@ -1,6 +1,6 @@ /* * (C) 2003-2006 Gabest - * (C) 2006-2016 see Authors.txt + * (C) 2006-2017 see Authors.txt * * This file is part of MPC-HC. * From 583dabcbe728edd2347be698494976d8fdd8bae9 Mon Sep 17 00:00:00 2001 From: Nicholas Parkanyi Date: Sun, 10 Sep 2017 02:12:54 -0400 Subject: [PATCH 03/26] simplified isYoutubeURL, fixed typo --- src/mpc-hc/PlayerPlaylistBar.cpp | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/src/mpc-hc/PlayerPlaylistBar.cpp b/src/mpc-hc/PlayerPlaylistBar.cpp index a4a734af081..22dea882fd3 100644 --- a/src/mpc-hc/PlayerPlaylistBar.cpp +++ b/src/mpc-hc/PlayerPlaylistBar.cpp @@ -804,7 +804,7 @@ OpenMediaData* CPlayerPlaylistBar::GetCurOMD(REFERENCE_TIME rtStart) } } else { if (OpenFileData* p = DEBUG_NEW OpenFileData()) { - if (!isYoutubeURL(pli->m_fns.GetHead()) { + if (!isYoutubeURL(pli->m_fns.GetHead())) { p->fns.AddTailList(&pli->m_fns); p->subs.AddTailList(&pli->m_subs); p->rtStart = rtStart; @@ -1813,13 +1813,6 @@ void CPlayerPlaylistBar::OnXButtonDblClk(UINT nFlags, UINT nButton, CPoint point bool CPlayerPlaylistBar::isYoutubeURL(CString url) { - if (url.Left(8) == _T("https:\\")) { - url = url.Right(url.GetLength() - 8); - } - - if (url.Left(4) == _T("www.")) { - url = url.Right(url.GetLength() - 4); - } - - return url.Left(17) == _T("youtube.com/watch"); -} \ No newline at end of file + return url.Left(29) == _T("https://www.youtube.com/watch") || + url.Left(25) == _T("https://youtube.com/watch"); +} From dbdb2d28f8c617595640a3e393c61ad1711816f1 Mon Sep 17 00:00:00 2001 From: Nicholas Parkanyi Date: Tue, 12 Sep 2017 01:28:43 -0400 Subject: [PATCH 04/26] Moved youtube-dl stuff to MainFrm, initial GetYoutubeHttpsStreams test implementation. --- src/mpc-hc/MainFrm.cpp | 57 ++++++++++++++++++++++++++++++++ src/mpc-hc/MainFrm.h | 5 +++ src/mpc-hc/PlayerPlaylistBar.cpp | 16 +++------ src/mpc-hc/PlayerPlaylistBar.h | 5 +-- 4 files changed, 67 insertions(+), 16 deletions(-) diff --git a/src/mpc-hc/MainFrm.cpp b/src/mpc-hc/MainFrm.cpp index 720d340b7fe..d3fc6d96c8c 100644 --- a/src/mpc-hc/MainFrm.cpp +++ b/src/mpc-hc/MainFrm.cpp @@ -3830,6 +3830,14 @@ void CMainFrame::OnFileOpenmedia() SetForegroundWindow(); CAtlList filenames; + + if (IsYoutubeURL(dlg.GetFileNames().GetHead())) { + CString vstream; + CString astream; + GetYoutubeHttpsStreams(vstream, astream); + return; + } + filenames.AddHeadList(&dlg.GetFileNames()); if (!dlg.HasMultipleFiles()) { @@ -16982,3 +16990,52 @@ LRESULT CMainFrame::OnGetSubtitles(WPARAM, LPARAM lParam) pSubtitlesInfo->fileContents = UTF16To8(content); return TRUE; } + +bool CMainFrame::IsYoutubeURL(CString url) +{ + return url.Left(29) == _T("https://www.youtube.com/watch") || + url.Left(25) == _T("https://youtube.com/watch"); +} + +bool CMainFrame::GetYoutubeHttpsStreams(CString &video, CString &audio) +{ + const int bufsize = 2000; //2KB + PROCESS_INFORMATION proc_info; + STARTUPINFO startup_info; + SECURITY_ATTRIBUTES sec_attrib; + HANDLE hStdout_r, hStdout_w; + HANDLE hStderr_r, hStderr_w; + CString cmd(L"youtube-dl \"https://www.youtube.com/watch?v=FIcxqVRLEWI\""); + + ZeroMemory(&proc_info, sizeof(PROCESS_INFORMATION)); + ZeroMemory(&startup_info, sizeof(STARTUPINFO)); + + //child process must inherit the handles + sec_attrib.nLength = sizeof(SECURITY_ATTRIBUTES); + sec_attrib.lpSecurityDescriptor = NULL; + sec_attrib.bInheritHandle = true; + + if (!CreatePipe(&hStdout_r, &hStdout_w, &sec_attrib, bufsize)) { + return false; + } + if (!CreatePipe(&hStderr_r, &hStderr_w, &sec_attrib, bufsize)) { + return false; + } + + startup_info.cb = sizeof(STARTUPINFO); + startup_info.hStdOutput = hStdout_w; + startup_info.hStdError = hStderr_w; + startup_info.wShowWindow = SW_HIDE; + startup_info.dwFlags |= STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW; + + if (!CreateProcess(NULL, cmd.GetBuffer(), NULL, NULL, true, 0, + NULL, NULL, &startup_info, &proc_info)) { + return false; + } + + WaitForSingleObject(proc_info.hProcess, 0); + + CloseHandle(proc_info.hProcess); + CloseHandle(proc_info.hThread); + return true; +} diff --git a/src/mpc-hc/MainFrm.h b/src/mpc-hc/MainFrm.h index 768c84ca24d..0dcf0036b62 100644 --- a/src/mpc-hc/MainFrm.h +++ b/src/mpc-hc/MainFrm.h @@ -1094,4 +1094,9 @@ class CMainFrame : public CFrameWnd, public CDropClient bool OpenBD(CString Path); bool GetDecoderType(CString& type) const; + +private: + //youtube-dl integration methods + bool IsYoutubeURL(CString url); + bool GetYoutubeHttpsStreams(CString &video, CString &audio); }; diff --git a/src/mpc-hc/PlayerPlaylistBar.cpp b/src/mpc-hc/PlayerPlaylistBar.cpp index 22dea882fd3..61accd7dc7e 100644 --- a/src/mpc-hc/PlayerPlaylistBar.cpp +++ b/src/mpc-hc/PlayerPlaylistBar.cpp @@ -804,12 +804,10 @@ OpenMediaData* CPlayerPlaylistBar::GetCurOMD(REFERENCE_TIME rtStart) } } else { if (OpenFileData* p = DEBUG_NEW OpenFileData()) { - if (!isYoutubeURL(pli->m_fns.GetHead())) { - p->fns.AddTailList(&pli->m_fns); - p->subs.AddTailList(&pli->m_subs); - p->rtStart = rtStart; - return p; - } + p->fns.AddTailList(&pli->m_fns); + p->subs.AddTailList(&pli->m_subs); + p->rtStart = rtStart; + return p; } } @@ -1810,9 +1808,3 @@ void CPlayerPlaylistBar::OnXButtonDblClk(UINT nFlags, UINT nButton, CPoint point { OnXButtonDown(nFlags, nButton, point); } - -bool CPlayerPlaylistBar::isYoutubeURL(CString url) -{ - return url.Left(29) == _T("https://www.youtube.com/watch") || - url.Left(25) == _T("https://youtube.com/watch"); -} diff --git a/src/mpc-hc/PlayerPlaylistBar.h b/src/mpc-hc/PlayerPlaylistBar.h index c13a1a542f4..2590b0a127a 100644 --- a/src/mpc-hc/PlayerPlaylistBar.h +++ b/src/mpc-hc/PlayerPlaylistBar.h @@ -160,7 +160,4 @@ class CPlayerPlaylistBar : public CPlayerBar, public CDropClient afx_msg void OnXButtonDown(UINT nFlags, UINT nButton, CPoint point); afx_msg void OnXButtonUp(UINT nFlags, UINT nButton, CPoint point); afx_msg void OnXButtonDblClk(UINT nFlags, UINT nButton, CPoint point); - -private: - bool isYoutubeURL(CString url); -}; \ No newline at end of file +}; From fae6b343f6041c749be4b6dbdbab8b4192df515e Mon Sep 17 00:00:00 2001 From: Nicholas Parkanyi Date: Tue, 12 Sep 2017 01:52:37 -0400 Subject: [PATCH 05/26] properly wait for process completion --- src/mpc-hc/MainFrm.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mpc-hc/MainFrm.cpp b/src/mpc-hc/MainFrm.cpp index d3fc6d96c8c..d66898cab85 100644 --- a/src/mpc-hc/MainFrm.cpp +++ b/src/mpc-hc/MainFrm.cpp @@ -17033,7 +17033,7 @@ bool CMainFrame::GetYoutubeHttpsStreams(CString &video, CString &audio) return false; } - WaitForSingleObject(proc_info.hProcess, 0); + WaitForSingleObject(proc_info.hProcess, INFINITE); CloseHandle(proc_info.hProcess); CloseHandle(proc_info.hThread); From d1389a5c5c27cb1d47cc841b6c96fe743f626a2b Mon Sep 17 00:00:00 2001 From: Nicholas Parkanyi Date: Wed, 13 Sep 2017 00:15:00 -0400 Subject: [PATCH 06/26] initial youtube-dl pipe buffer implementation --- src/mpc-hc/MainFrm.cpp | 50 +++++++++++++++++++++++++++++++++--------- src/mpc-hc/MainFrm.h | 3 ++- 2 files changed, 42 insertions(+), 11 deletions(-) diff --git a/src/mpc-hc/MainFrm.cpp b/src/mpc-hc/MainFrm.cpp index d66898cab85..6c948482558 100644 --- a/src/mpc-hc/MainFrm.cpp +++ b/src/mpc-hc/MainFrm.cpp @@ -3832,9 +3832,9 @@ void CMainFrame::OnFileOpenmedia() CAtlList filenames; if (IsYoutubeURL(dlg.GetFileNames().GetHead())) { - CString vstream; - CString astream; - GetYoutubeHttpsStreams(vstream, astream); + CAtlList vstreams; + CAtlList astreams; + GetYoutubeHttpsStreams(vstreams, astreams); return; } @@ -16994,18 +16994,22 @@ LRESULT CMainFrame::OnGetSubtitles(WPARAM, LPARAM lParam) bool CMainFrame::IsYoutubeURL(CString url) { return url.Left(29) == _T("https://www.youtube.com/watch") || - url.Left(25) == _T("https://youtube.com/watch"); + url.Left(25) == _T("https://youtube.com/watch") || + url.Left(32) == _T("https://www.youtube.com/playlist") || + url.Left(28) == _T("https://youtube.com/playlist"); } -bool CMainFrame::GetYoutubeHttpsStreams(CString &video, CString &audio) +bool CMainFrame::CallYoutubeDL(CString args, CString &out, CString &err) { - const int bufsize = 2000; //2KB + const int bufsize = 2000; + std::vector buf(bufsize, 0); //2KB PROCESS_INFORMATION proc_info; STARTUPINFO startup_info; SECURITY_ATTRIBUTES sec_attrib; HANDLE hStdout_r, hStdout_w; HANDLE hStderr_r, hStderr_w; - CString cmd(L"youtube-dl \"https://www.youtube.com/watch?v=FIcxqVRLEWI\""); + + args = "youtube-dl " + args; ZeroMemory(&proc_info, sizeof(PROCESS_INFORMATION)); ZeroMemory(&startup_info, sizeof(STARTUPINFO)); @@ -17028,14 +17032,40 @@ bool CMainFrame::GetYoutubeHttpsStreams(CString &video, CString &audio) startup_info.wShowWindow = SW_HIDE; startup_info.dwFlags |= STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW; - if (!CreateProcess(NULL, cmd.GetBuffer(), NULL, NULL, true, 0, - NULL, NULL, &startup_info, &proc_info)) { + if (!CreateProcess(NULL, args.GetBuffer(), NULL, NULL, true, 0, + NULL, NULL, &startup_info, &proc_info)) { return false; } - WaitForSingleObject(proc_info.hProcess, INFINITE); + CloseHandle(hStdout_w); + CloseHandle(hStderr_w); + + DWORD read = 0; + DWORD exitcode; + bool bRes; + int idx = 0; + while (true) { + bRes = ReadFile(hStdout_r, buf.data() + idx, buf.capacity() - idx, &read, NULL); + idx += read; + + if (!bRes && GetLastError() == ERROR_BROKEN_PIPE) { + break; + } else if (!bRes){ + return false; + } + + if (idx == buf.capacity()) { + buf.reserve(buf.capacity() * 2); + } + } CloseHandle(proc_info.hProcess); CloseHandle(proc_info.hThread); return true; } + +bool CMainFrame::GetYoutubeHttpsStreams(CAtlList &video, CAtlList &audio) +{ + CString out, err; + return CallYoutubeDL(CString("-g -- \"https://www.youtube.com/playlist?list=PLX4gVg4r8QaEUW7iVCGGBCUCx-1BTfCNa\""), out, err); +} diff --git a/src/mpc-hc/MainFrm.h b/src/mpc-hc/MainFrm.h index 0dcf0036b62..c91e53ebfcd 100644 --- a/src/mpc-hc/MainFrm.h +++ b/src/mpc-hc/MainFrm.h @@ -1098,5 +1098,6 @@ class CMainFrame : public CFrameWnd, public CDropClient private: //youtube-dl integration methods bool IsYoutubeURL(CString url); - bool GetYoutubeHttpsStreams(CString &video, CString &audio); + bool CallYoutubeDL(CString cmd, CString &out, CString &err); + bool GetYoutubeHttpsStreams(CAtlList &video, CAtlList &audio); }; From 2ff8d8637f00c4c16ade3f54e7b9c303d2454271 Mon Sep 17 00:00:00 2001 From: Nicholas Parkanyi Date: Thu, 14 Sep 2017 02:00:10 -0400 Subject: [PATCH 07/26] youtube-dl pipe buffering relegated to worker threads to prevent I/O deadlock --- src/mpc-hc/MainFrm.cpp | 87 ++++++++++++++++++++++++++++++++---------- 1 file changed, 67 insertions(+), 20 deletions(-) diff --git a/src/mpc-hc/MainFrm.cpp b/src/mpc-hc/MainFrm.cpp index 6c948482558..00ec35cff9e 100644 --- a/src/mpc-hc/MainFrm.cpp +++ b/src/mpc-hc/MainFrm.cpp @@ -16999,15 +16999,58 @@ bool CMainFrame::IsYoutubeURL(CString url) url.Left(28) == _T("https://youtube.com/playlist"); } + +////////////////////////////////////// +// Worker threads for CallYoutubeDL() +////////////////////////////////////// + +HANDLE hStdout_r, hStdout_w; +HANDLE hStderr_r, hStderr_w; +int idx_out = 0; +int idx_err = 0; + +DWORD WINAPI BuffOutThread(void *buf) +{ + auto buf_out = static_cast*>(buf); + DWORD read; + + while (ReadFile(hStdout_r, buf_out->data() + idx_out, buf_out->capacity() - idx_out, &read, NULL)){ + idx_out += read; + if (idx_out == buf_out->capacity()) { + buf_out->reserve(buf_out->capacity() * 2); + } + } + + return GetLastError() == ERROR_BROKEN_PIPE ? 0 : GetLastError(); +} + +DWORD WINAPI BuffErrThread(void *buf) +{ + auto buf_err = static_cast*>(buf); + DWORD read; + + while (ReadFile(hStderr_r, buf_err->data() + idx_err, buf_err->capacity() - idx_err, &read, NULL)) { + idx_err += read; + if (idx_err == buf_err->capacity()) { + buf_err->reserve(buf_err->capacity() * 2); + } + } + + return GetLastError() == ERROR_BROKEN_PIPE ? 0 : GetLastError(); +} + bool CMainFrame::CallYoutubeDL(CString args, CString &out, CString &err) { - const int bufsize = 2000; - std::vector buf(bufsize, 0); //2KB + const int bufsize = 2000; //2KB initial buffer size + + ///////////////////////////// + // Set up youtube-dl process + ///////////////////////////// + PROCESS_INFORMATION proc_info; STARTUPINFO startup_info; SECURITY_ATTRIBUTES sec_attrib; - HANDLE hStdout_r, hStdout_w; - HANDLE hStderr_r, hStderr_w; + args = "youtube-dl " + args; @@ -17037,30 +17080,34 @@ bool CMainFrame::CallYoutubeDL(CString args, CString &out, CString &err) return false; } + //we must close the parent process's write handles before calling ReadFile, + // otherwise it will block forever. CloseHandle(hStdout_w); CloseHandle(hStderr_w); - DWORD read = 0; - DWORD exitcode; - bool bRes; - int idx = 0; - while (true) { - bRes = ReadFile(hStdout_r, buf.data() + idx, buf.capacity() - idx, &read, NULL); - idx += read; - if (!bRes && GetLastError() == ERROR_BROKEN_PIPE) { - break; - } else if (!bRes){ - return false; - } + ///////////////////////////////////////////////////// + // Read in stdout and stderr through the pipe buffer + ///////////////////////////////////////////////////// - if (idx == buf.capacity()) { - buf.reserve(buf.capacity() * 2); - } - } + std::vector buf_out(bufsize, 0); + std::vector buf_err(bufsize, 0); + HANDLE hThreadOut, hThreadErr; + idx_out = 0; + idx_err = 0; + + hThreadOut = CreateThread(NULL, 0, BuffOutThread, &buf_out, NULL, NULL); + hThreadErr = CreateThread(NULL, 0, BuffErrThread, &buf_err, NULL, NULL); + + WaitForSingleObject(hThreadOut, INFINITE); + WaitForSingleObject(hThreadErr, INFINITE); CloseHandle(proc_info.hProcess); CloseHandle(proc_info.hThread); + CloseHandle(hThreadOut); + CloseHandle(hThreadErr); + CloseHandle(hStdout_r); + CloseHandle(hStderr_r); return true; } From deafa66599ee0fa24ce30b301f5bf6a81010ed3b Mon Sep 17 00:00:00 2001 From: Nicholas Parkanyi Date: Fri, 15 Sep 2017 02:23:47 -0400 Subject: [PATCH 08/26] load youtube videos and playlists through the Open File dialogue. --- src/mpc-hc/MainFrm.cpp | 114 ++++++++++++++++++++++++++++++++--------- src/mpc-hc/MainFrm.h | 2 +- 2 files changed, 92 insertions(+), 24 deletions(-) diff --git a/src/mpc-hc/MainFrm.cpp b/src/mpc-hc/MainFrm.cpp index 00ec35cff9e..ea6f42f1d25 100644 --- a/src/mpc-hc/MainFrm.cpp +++ b/src/mpc-hc/MainFrm.cpp @@ -3735,14 +3735,14 @@ void CMainFrame::OnDvdSubOnOff() return; } - if (m_pDVDI && m_pDVDC) { - ULONG ulStreamsAvailable, ulCurrentStream; - BOOL bIsDisabled; - if (SUCCEEDED(m_pDVDI->GetCurrentSubpicture(&ulStreamsAvailable, &ulCurrentStream, &bIsDisabled))) { - m_pDVDC->SetSubpictureState(bIsDisabled, DVD_CMD_FLAG_Block, nullptr); - } +if (m_pDVDI && m_pDVDC) { + ULONG ulStreamsAvailable, ulCurrentStream; + BOOL bIsDisabled; + if (SUCCEEDED(m_pDVDI->GetCurrentSubpicture(&ulStreamsAvailable, &ulCurrentStream, &bIsDisabled))) { + m_pDVDC->SetSubpictureState(bIsDisabled, DVD_CMD_FLAG_Block, nullptr); } } +} // // menu item handlers @@ -3781,9 +3781,9 @@ void CMainFrame::OnFileOpenQuick() bool fMultipleFiles = false; if (fns.GetCount() > 1 - || fns.GetCount() == 1 - && (fns.GetHead()[fns.GetHead().GetLength() - 1] == '\\' - || fns.GetHead()[fns.GetHead().GetLength() - 1] == '*')) { + || fns.GetCount() == 1 + && (fns.GetHead()[fns.GetHead().GetLength() - 1] == '\\' + || fns.GetHead()[fns.GetHead().GetLength() - 1] == '*')) { fMultipleFiles = true; } @@ -3834,7 +3834,20 @@ void CMainFrame::OnFileOpenmedia() if (IsYoutubeURL(dlg.GetFileNames().GetHead())) { CAtlList vstreams; CAtlList astreams; - GetYoutubeHttpsStreams(vstreams, astreams); + + GetYoutubeHttpsStreams(dlg.GetFileNames().GetHead(), vstreams, astreams); + + for (int i = 0; i < vstreams.GetCount(); i++) { + filenames.RemoveAll(); + filenames.AddTail(vstreams.GetAt(vstreams.FindIndex(i))); + filenames.AddTail(astreams.GetAt(astreams.FindIndex(i))); + m_wndPlaylistBar.Append(filenames, false); + } + + if (!dlg.GetAppendToPlaylist()) { + m_wndPlaylistBar.SetFirst(); + OpenCurPlaylistItem(); + } return; } @@ -17008,16 +17021,21 @@ HANDLE hStdout_r, hStdout_w; HANDLE hStderr_r, hStderr_w; int idx_out = 0; int idx_err = 0; +size_t capacity_out, capacity_err; DWORD WINAPI BuffOutThread(void *buf) { - auto buf_out = static_cast*>(buf); + char** buf_out = static_cast(buf); DWORD read; - while (ReadFile(hStdout_r, buf_out->data() + idx_out, buf_out->capacity() - idx_out, &read, NULL)){ + while (ReadFile(hStdout_r, *buf_out + idx_out, capacity_out - idx_out, &read, NULL)){ idx_out += read; - if (idx_out == buf_out->capacity()) { - buf_out->reserve(buf_out->capacity() * 2); + if (idx_out == capacity_out) { + capacity_out *= 2; + char* tmp = static_cast(std::realloc(*buf_out, capacity_out)); + if (tmp) { + *buf_out = tmp; + } } } @@ -17026,13 +17044,17 @@ DWORD WINAPI BuffOutThread(void *buf) DWORD WINAPI BuffErrThread(void *buf) { - auto buf_err = static_cast*>(buf); + char** buf_err = static_cast(buf); DWORD read; - while (ReadFile(hStderr_r, buf_err->data() + idx_err, buf_err->capacity() - idx_err, &read, NULL)) { + while (ReadFile(hStderr_r, *buf_err + idx_err, capacity_err - idx_err, &read, NULL)) { idx_err += read; - if (idx_err == buf_err->capacity()) { - buf_err->reserve(buf_err->capacity() * 2); + if (idx_err == capacity_err) { + capacity_err *= 2; + char* tmp = static_cast(std::realloc(*buf_err, capacity_err)); + if (tmp) { + *buf_err = tmp; + } } } @@ -17041,7 +17063,7 @@ DWORD WINAPI BuffErrThread(void *buf) bool CMainFrame::CallYoutubeDL(CString args, CString &out, CString &err) { - const int bufsize = 2000; //2KB initial buffer size + const size_t bufsize = 2000; //2KB initial buffer size ///////////////////////////// // Set up youtube-dl process @@ -17090,8 +17112,11 @@ bool CMainFrame::CallYoutubeDL(CString args, CString &out, CString &err) // Read in stdout and stderr through the pipe buffer ///////////////////////////////////////////////////// - std::vector buf_out(bufsize, 0); - std::vector buf_err(bufsize, 0); + char* buf_out = static_cast(std::malloc(bufsize)); + char* buf_err = static_cast(std::malloc(bufsize)); + capacity_out = bufsize; + capacity_err = bufsize; + HANDLE hThreadOut, hThreadErr; idx_out = 0; idx_err = 0; @@ -17102,6 +17127,29 @@ bool CMainFrame::CallYoutubeDL(CString args, CString &out, CString &err) WaitForSingleObject(hThreadOut, INFINITE); WaitForSingleObject(hThreadErr, INFINITE); + //NULL-terminate the data + char* tmp; + if (idx_out == capacity_out) { + tmp = static_cast(std::realloc(buf_out, capacity_out + 1)); + if (tmp) { + buf_out = tmp; + } + } + buf_out[idx_out] = '\0'; + + if (idx_err == capacity_err) { + tmp = static_cast(std::realloc(buf_err, capacity_err + 1)); + if (tmp) { + buf_err = tmp; + } + } + buf_err[idx_err] = '\0'; + + out = buf_out; + err = buf_err; + + std::free(buf_out); + std::free(buf_err); CloseHandle(proc_info.hProcess); CloseHandle(proc_info.hThread); CloseHandle(hThreadOut); @@ -17111,8 +17159,28 @@ bool CMainFrame::CallYoutubeDL(CString args, CString &out, CString &err) return true; } -bool CMainFrame::GetYoutubeHttpsStreams(CAtlList &video, CAtlList &audio) +bool CMainFrame::GetYoutubeHttpsStreams(CString url, CAtlList &video, CAtlList &audio) { CString out, err; - return CallYoutubeDL(CString("-g -- \"https://www.youtube.com/playlist?list=PLX4gVg4r8QaEUW7iVCGGBCUCx-1BTfCNa\""), out, err); + CallYoutubeDL(CString("-g -- \"" + url + "\""), out, err); + + int idx = 0; + int next; + while(true) { + next = out.Find('\n', idx); + if (next == -1) { + break; + } + video.AddTail(out.Left(next).Right(next - idx)); + idx = next + 1; + + next = out.Find('\n', idx); + if (next == -1) { + return false; + } + audio.AddTail(out.Left(next).Right(next - idx)); + idx = next + 1; + } + + return true; } diff --git a/src/mpc-hc/MainFrm.h b/src/mpc-hc/MainFrm.h index c91e53ebfcd..982256fad48 100644 --- a/src/mpc-hc/MainFrm.h +++ b/src/mpc-hc/MainFrm.h @@ -1099,5 +1099,5 @@ class CMainFrame : public CFrameWnd, public CDropClient //youtube-dl integration methods bool IsYoutubeURL(CString url); bool CallYoutubeDL(CString cmd, CString &out, CString &err); - bool GetYoutubeHttpsStreams(CAtlList &video, CAtlList &audio); + bool GetYoutubeHttpsStreams(CString url, CAtlList &video, CAtlList &audio); }; From b78a4294b02d48797a0f5531d537e8341a0560b6 Mon Sep 17 00:00:00 2001 From: Nicholas Parkanyi Date: Fri, 15 Sep 2017 16:53:26 -0400 Subject: [PATCH 09/26] clear playlist when not appending --- src/mpc-hc/MainFrm.cpp | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/mpc-hc/MainFrm.cpp b/src/mpc-hc/MainFrm.cpp index ea6f42f1d25..f9898b901b9 100644 --- a/src/mpc-hc/MainFrm.cpp +++ b/src/mpc-hc/MainFrm.cpp @@ -3737,10 +3737,10 @@ void CMainFrame::OnDvdSubOnOff() if (m_pDVDI && m_pDVDC) { ULONG ulStreamsAvailable, ulCurrentStream; - BOOL bIsDisabled; - if (SUCCEEDED(m_pDVDI->GetCurrentSubpicture(&ulStreamsAvailable, &ulCurrentStream, &bIsDisabled))) { - m_pDVDC->SetSubpictureState(bIsDisabled, DVD_CMD_FLAG_Block, nullptr); - } +BOOL bIsDisabled; +if (SUCCEEDED(m_pDVDI->GetCurrentSubpicture(&ulStreamsAvailable, &ulCurrentStream, &bIsDisabled))) { + m_pDVDC->SetSubpictureState(bIsDisabled, DVD_CMD_FLAG_Block, nullptr); +} } } @@ -3837,6 +3837,9 @@ void CMainFrame::OnFileOpenmedia() GetYoutubeHttpsStreams(dlg.GetFileNames().GetHead(), vstreams, astreams); + if (!dlg.GetAppendToPlaylist()) { + m_wndPlaylistBar.Empty(); + } for (int i = 0; i < vstreams.GetCount(); i++) { filenames.RemoveAll(); filenames.AddTail(vstreams.GetAt(vstreams.FindIndex(i))); From 3c3615a8457091f85e9649c5fe97c4d036cb4840 Mon Sep 17 00:00:00 2001 From: Nicholas Parkanyi Date: Fri, 15 Sep 2017 19:53:31 -0400 Subject: [PATCH 10/26] some proper error handling for youtube-dl stuff --- src/mpc-hc/MainFrm.cpp | 76 ++++++++++++++++++++++++++++-------------- src/mpc-hc/MainFrm.h | 20 +++++++---- src/mpc-hc/mpc-hc.rc | 53 ++++++++++++++++------------- src/mpc-hc/resource.h | 1 + 4 files changed, 95 insertions(+), 55 deletions(-) diff --git a/src/mpc-hc/MainFrm.cpp b/src/mpc-hc/MainFrm.cpp index f9898b901b9..fbc1b97ba89 100644 --- a/src/mpc-hc/MainFrm.cpp +++ b/src/mpc-hc/MainFrm.cpp @@ -3735,13 +3735,13 @@ void CMainFrame::OnDvdSubOnOff() return; } -if (m_pDVDI && m_pDVDC) { - ULONG ulStreamsAvailable, ulCurrentStream; -BOOL bIsDisabled; -if (SUCCEEDED(m_pDVDI->GetCurrentSubpicture(&ulStreamsAvailable, &ulCurrentStream, &bIsDisabled))) { - m_pDVDC->SetSubpictureState(bIsDisabled, DVD_CMD_FLAG_Block, nullptr); -} -} + if (m_pDVDI && m_pDVDC) { + ULONG ulStreamsAvailable, ulCurrentStream; + BOOL bIsDisabled; + if (SUCCEEDED(m_pDVDI->GetCurrentSubpicture(&ulStreamsAvailable, &ulCurrentStream, &bIsDisabled))) { + m_pDVDC->SetSubpictureState(bIsDisabled, DVD_CMD_FLAG_Block, nullptr); + } + } } // @@ -3781,9 +3781,9 @@ void CMainFrame::OnFileOpenQuick() bool fMultipleFiles = false; if (fns.GetCount() > 1 - || fns.GetCount() == 1 - && (fns.GetHead()[fns.GetHead().GetLength() - 1] == '\\' - || fns.GetHead()[fns.GetHead().GetLength() - 1] == '*')) { + || fns.GetCount() == 1 + && (fns.GetHead()[fns.GetHead().GetLength() - 1] == '\\' + || fns.GetHead()[fns.GetHead().GetLength() - 1] == '*')) { fMultipleFiles = true; } @@ -3835,7 +3835,9 @@ void CMainFrame::OnFileOpenmedia() CAtlList vstreams; CAtlList astreams; - GetYoutubeHttpsStreams(dlg.GetFileNames().GetHead(), vstreams, astreams); + if (!GetYoutubeHttpsStreams(dlg.GetFileNames().GetHead(), vstreams, astreams)) { + return; + } if (!dlg.GetAppendToPlaylist()) { m_wndPlaylistBar.Empty(); @@ -12640,7 +12642,7 @@ void CMainFrame::SetupAudioSubMenu() ATR.bQuantization, ATR.bNumberOfChannels, ResStr(ATR.bNumberOfChannels > 1 ? IDS_MAINFRM_13 : IDS_MAINFRM_12).GetString() - ); + ); } } @@ -16752,10 +16754,11 @@ void CMainFrame::UpdateDXVAStatus() bool CMainFrame::GetDecoderType(CString& type) const { if (!m_fAudioOnly) { - if (m_bUsingDXVA) + if (m_bUsingDXVA) { type = m_HWAccelType; - else + } else { type.LoadString(IDS_TOOLTIP_SOFTWARE_DECODING); + } return true; } return false; @@ -17010,9 +17013,9 @@ LRESULT CMainFrame::OnGetSubtitles(WPARAM, LPARAM lParam) bool CMainFrame::IsYoutubeURL(CString url) { return url.Left(29) == _T("https://www.youtube.com/watch") || - url.Left(25) == _T("https://youtube.com/watch") || - url.Left(32) == _T("https://www.youtube.com/playlist") || - url.Left(28) == _T("https://youtube.com/playlist"); + url.Left(25) == _T("https://youtube.com/watch") || + url.Left(32) == _T("https://www.youtube.com/playlist") || + url.Left(28) == _T("https://youtube.com/playlist"); } @@ -17026,18 +17029,22 @@ int idx_out = 0; int idx_err = 0; size_t capacity_out, capacity_err; -DWORD WINAPI BuffOutThread(void *buf) +DWORD WINAPI BuffOutThread(void* buf) { char** buf_out = static_cast(buf); DWORD read; - while (ReadFile(hStdout_r, *buf_out + idx_out, capacity_out - idx_out, &read, NULL)){ + while (ReadFile(hStdout_r, *buf_out + idx_out, capacity_out - idx_out, &read, NULL)) { idx_out += read; if (idx_out == capacity_out) { capacity_out *= 2; char* tmp = static_cast(std::realloc(*buf_out, capacity_out)); if (tmp) { *buf_out = tmp; + } else { + std::free(*buf_out); + *buf_out = nullptr; + return 0; } } } @@ -17045,7 +17052,7 @@ DWORD WINAPI BuffOutThread(void *buf) return GetLastError() == ERROR_BROKEN_PIPE ? 0 : GetLastError(); } -DWORD WINAPI BuffErrThread(void *buf) +DWORD WINAPI BuffErrThread(void* buf) { char** buf_err = static_cast(buf); DWORD read; @@ -17057,6 +17064,10 @@ DWORD WINAPI BuffErrThread(void *buf) char* tmp = static_cast(std::realloc(*buf_err, capacity_err)); if (tmp) { *buf_err = tmp; + } else { + std::free(*buf_err); + *buf_err = nullptr; + return 0; } } } @@ -17064,7 +17075,7 @@ DWORD WINAPI BuffErrThread(void *buf) return GetLastError() == ERROR_BROKEN_PIPE ? 0 : GetLastError(); } -bool CMainFrame::CallYoutubeDL(CString args, CString &out, CString &err) +bool CMainFrame::CallYoutubeDL(CString args, CString& out, CString& err) { const size_t bufsize = 2000; //2KB initial buffer size @@ -17101,7 +17112,8 @@ bool CMainFrame::CallYoutubeDL(CString args, CString &out, CString &err) startup_info.dwFlags |= STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW; if (!CreateProcess(NULL, args.GetBuffer(), NULL, NULL, true, 0, - NULL, NULL, &startup_info, &proc_info)) { + NULL, NULL, &startup_info, &proc_info)) { + AfxMessageBox(IDS_YOUTUBEDL_NOT_FOUND, MB_ICONERROR | MB_OK, 0); return false; } @@ -17130,6 +17142,10 @@ bool CMainFrame::CallYoutubeDL(CString args, CString &out, CString &err) WaitForSingleObject(hThreadOut, INFINITE); WaitForSingleObject(hThreadErr, INFINITE); + if (!buf_out || !buf_err) { + throw std::bad_alloc(); + } + //NULL-terminate the data char* tmp; if (idx_out == capacity_out) { @@ -17153,6 +17169,14 @@ bool CMainFrame::CallYoutubeDL(CString args, CString &out, CString &err) std::free(buf_out); std::free(buf_err); + + DWORD exitcode; + GetExitCodeProcess(proc_info.hProcess, &exitcode); + if (exitcode) { + AfxMessageBox(err.GetBuffer(), MB_ICONERROR, 0); + return false; + } + CloseHandle(proc_info.hProcess); CloseHandle(proc_info.hThread); CloseHandle(hThreadOut); @@ -17162,14 +17186,16 @@ bool CMainFrame::CallYoutubeDL(CString args, CString &out, CString &err) return true; } -bool CMainFrame::GetYoutubeHttpsStreams(CString url, CAtlList &video, CAtlList &audio) +bool CMainFrame::GetYoutubeHttpsStreams(CString url, CAtlList& video, CAtlList& audio) { CString out, err; - CallYoutubeDL(CString("-g -- \"" + url + "\""), out, err); + if (!CallYoutubeDL(CString("-g -- \"" + url + "\""), out, err)) { + return false; + } int idx = 0; int next; - while(true) { + while (true) { next = out.Find('\n', idx); if (next == -1) { break; diff --git a/src/mpc-hc/MainFrm.h b/src/mpc-hc/MainFrm.h index 982256fad48..8599f4cee88 100644 --- a/src/mpc-hc/MainFrm.h +++ b/src/mpc-hc/MainFrm.h @@ -387,11 +387,19 @@ class CMainFrame : public CFrameWnd, public CDropClient void StartWebServer(int nPort); void StopWebServer(); - int GetPlaybackMode() const { return m_iPlaybackMode; } - bool IsPlaybackCaptureMode() const { return GetPlaybackMode() == PM_ANALOG_CAPTURE || GetPlaybackMode() == PM_DIGITAL_CAPTURE; } + int GetPlaybackMode() const { + return m_iPlaybackMode; + } + bool IsPlaybackCaptureMode() const { + return GetPlaybackMode() == PM_ANALOG_CAPTURE || GetPlaybackMode() == PM_DIGITAL_CAPTURE; + } void SetPlaybackMode(int iNewStatus); - bool IsMuted() { return m_wndToolBar.GetVolume() == -10000; } - int GetVolume() { return m_wndToolBar.m_volctrl.GetPos(); } + bool IsMuted() { + return m_wndToolBar.GetVolume() == -10000; + } + int GetVolume() { + return m_wndToolBar.m_volctrl.GetPos(); + } public: CMainFrame(); @@ -1098,6 +1106,6 @@ class CMainFrame : public CFrameWnd, public CDropClient private: //youtube-dl integration methods bool IsYoutubeURL(CString url); - bool CallYoutubeDL(CString cmd, CString &out, CString &err); - bool GetYoutubeHttpsStreams(CString url, CAtlList &video, CAtlList &audio); + bool CallYoutubeDL(CString cmd, CString& out, CString& err); + bool GetYoutubeHttpsStreams(CString url, CAtlList& video, CAtlList& audio); }; diff --git a/src/mpc-hc/mpc-hc.rc b/src/mpc-hc/mpc-hc.rc index afefb6bc49b..08f8ec23247 100644 --- a/src/mpc-hc/mpc-hc.rc +++ b/src/mpc-hc/mpc-hc.rc @@ -3549,7 +3549,6 @@ STRINGTABLE BEGIN IDS_SUBTITLE_RENDERER_VS_FILTER "VSFilter / DirectVobSub" IDS_SUBTITLE_RENDERER_XY_SUB_FILTER "XySubFilter" - IDS_SUBTITLE_RENDERER_ASS_FILTER "AssFilter" IDS_SUBDL_DLG_PROVIDER_COL "Provider" IDS_SUBDL_DLG_HI_COL "Hearing Impaired" IDS_SUBDL_DLG_DOWNLOADS_COL "Downloads" @@ -3566,6 +3565,28 @@ BEGIN IDS_SUBUL_DLG_STATUS_READY "Ready..." END +STRINGTABLE +BEGIN + IDS_CMD_PNS "/pns ""name""\tSpecify Pan & Scan preset name to use" + IDS_CMD_ICONASSOC "/iconsassoc\tReassociate format icons" + IDS_CMD_NOFOCUS "/nofocus\t\tOpen MPC-HC in background" + IDS_CMD_WEBPORT "/webport N\tStart web interface on specified port" + IDS_CMD_DEBUG "/debug\t\tShow debug information in OSD" + IDS_CMD_NOCRASHREPORTER "/nocrashreporter\tDisable the crash reporter" + IDS_CMD_SLAVE "/slave ""hWnd""\tUse MPC-HC as slave" + IDS_CMD_HWGPU "/hwgpu ""index""\tSet the index of the GPU used for hardware decoding.\n\t\tOnly available for CUVID and DXVA2 (copy-back)" + IDS_CMD_RESET "/reset\t\tRestore default settings" + IDS_CMD_HELP "/help /h /?\tShow help about command line switches" + IDS_PPAGEADVANCED_SCORE "Threshold value for subtitles score which are going to be automatically downloaded. Higher values means that more accurately matched subtitles will be loaded, lower values could result in incorrect subtitles being loaded, but there is no one perfect value. Pick one that works best for you." + IDS_PPAGE_FS_CLN_AUDIO_DELAY "Audio Delay (ms)" + IDS_PPAGEADVANCED_DEFAULTTOOLBARSIZE + "Size in pixels of the default toolbar." + IDS_PPAGEADVANCED_USE_LEGACY_TOOLBAR + "Use legacy toolbar instead of new vectorized one." + IDS_SUBTITLE_RENDERER_ASS_FILTER "AssFilter" + IDS_SUBMENU_COPYURL "Copy URL" +END + STRINGTABLE BEGIN IDS_SUBUL_DLG_STATUS_NOTIMPLEMENTED "Not implemented." @@ -3627,18 +3648,23 @@ BEGIN IDS_CMD_LOCK "/lock\t\tLock workstation after playback" IDS_CMD_MONITOROFF "/monitoroff\tTurn off the monitor after playback" IDS_CMD_PLAYNEXT "/playnext\t\tOpen next file in the folder after playback" +END + +STRINGTABLE +BEGIN + IDS_CMD_VIEWPRESET "/viewpreset N\tStart with specific preset,\n\t\twhere N is either ""1"" Minimal, ""2"" Compact or ""3"" Normal" IDS_CMD_MUTE "/mute\t\tMute the audio" + IDS_CMD_VOLUME "/volume N\tSet Volume, where N is a range from 0 to 100" + IDS_YOUTUBEDL_NOT_FOUND "Youtube-dl failed to launch. Make sure youtube-dl is in PATH." END STRINGTABLE BEGIN IDS_CMD_FULLSCREEN "/fullscreen\tStart in fullscreen mode" - IDS_CMD_VIEWPRESET "/viewpreset N\tStart with specific preset,\n\t\twhere N is either ""1"" Minimal, ""2"" Compact or ""3"" Normal" IDS_CMD_MINIMIZED "/minimized\tStart in minimized mode" IDS_CMD_NEW "/new\t\tUse a new instance of the player" IDS_CMD_ADD "/add\t\tAdd ""pathname"" to playlist, can be combined with /open and /play" IDS_CMD_RANDOMIZE "/randomize\tRandomize the playlist" - IDS_CMD_VOLUME "/volume N\tSet Volume, where N is a range from 0 to 100" IDS_CMD_REGVID "/regvid\t\tCreate file associations for video files" IDS_CMD_REGAUD "/regaud\t\tCreate file associations for audio files" IDS_CMD_REGPL "/regpl\t\tCreate file associations for playlist files" @@ -3652,27 +3678,6 @@ BEGIN IDS_CMD_SHADERPRESET "/shaderpreset ""Pr""\tStart using ""Pr"" shader preset" END -STRINGTABLE -BEGIN - IDS_CMD_PNS "/pns ""name""\tSpecify Pan & Scan preset name to use" - IDS_CMD_ICONASSOC "/iconsassoc\tReassociate format icons" - IDS_CMD_NOFOCUS "/nofocus\t\tOpen MPC-HC in background" - IDS_CMD_WEBPORT "/webport N\tStart web interface on specified port" - IDS_CMD_DEBUG "/debug\t\tShow debug information in OSD" - IDS_CMD_NOCRASHREPORTER "/nocrashreporter\tDisable the crash reporter" - IDS_CMD_SLAVE "/slave ""hWnd""\tUse MPC-HC as slave" - IDS_CMD_HWGPU "/hwgpu ""index""\tSet the index of the GPU used for hardware decoding.\n\t\tOnly available for CUVID and DXVA2 (copy-back)" - IDS_CMD_RESET "/reset\t\tRestore default settings" - IDS_CMD_HELP "/help /h /?\tShow help about command line switches" - IDS_PPAGEADVANCED_SCORE "Threshold value for subtitles score which are going to be automatically downloaded. Higher values means that more accurately matched subtitles will be loaded, lower values could result in incorrect subtitles being loaded, but there is no one perfect value. Pick one that works best for you." - IDS_PPAGE_FS_CLN_AUDIO_DELAY "Audio Delay (ms)" - IDS_PPAGEADVANCED_DEFAULTTOOLBARSIZE - "Size in pixels of the default toolbar." - IDS_PPAGEADVANCED_USE_LEGACY_TOOLBAR - "Use legacy toolbar instead of new vectorized one." - IDS_SUBMENU_COPYURL "Copy URL" -END - #endif // English (United States) resources ///////////////////////////////////////////////////////////////////////////// diff --git a/src/mpc-hc/resource.h b/src/mpc-hc/resource.h index a8888166b92..0bd14028a6f 100644 --- a/src/mpc-hc/resource.h +++ b/src/mpc-hc/resource.h @@ -1572,6 +1572,7 @@ #define IDS_CMD_VIEWPRESET 57536 #define IDS_CMD_MUTE 57537 #define IDS_CMD_VOLUME 57538 +#define IDS_YOUTUBEDL_NOT_FOUND 57539 // Next default values for new objects // From 6f7fa186176152fa96b35022e43ee432b9038831 Mon Sep 17 00:00:00 2001 From: Nicholas Parkanyi Date: Mon, 18 Sep 2017 02:30:53 -0400 Subject: [PATCH 11/26] Use video title instead of unwieldy raw youtube stream urls. --- src/mpc-hc/MainFrm.cpp | 37 +++++++++++++++++++++++++++----- src/mpc-hc/MainFrm.h | 1 + src/mpc-hc/PlayerPlaylistBar.cpp | 19 ++++++++++------ src/mpc-hc/PlayerPlaylistBar.h | 6 +++--- src/mpc-hc/Playlist.cpp | 1 + src/mpc-hc/Playlist.h | 3 ++- 6 files changed, 52 insertions(+), 15 deletions(-) diff --git a/src/mpc-hc/MainFrm.cpp b/src/mpc-hc/MainFrm.cpp index fbc1b97ba89..3f271b641c9 100644 --- a/src/mpc-hc/MainFrm.cpp +++ b/src/mpc-hc/MainFrm.cpp @@ -3834,10 +3834,14 @@ void CMainFrame::OnFileOpenmedia() if (IsYoutubeURL(dlg.GetFileNames().GetHead())) { CAtlList vstreams; CAtlList astreams; + CAtlList names; if (!GetYoutubeHttpsStreams(dlg.GetFileNames().GetHead(), vstreams, astreams)) { return; } + if (!GetYoutubeNames(dlg.GetFileNames().GetHead(), names)) { + return; + } if (!dlg.GetAppendToPlaylist()) { m_wndPlaylistBar.Empty(); @@ -3846,7 +3850,9 @@ void CMainFrame::OnFileOpenmedia() filenames.RemoveAll(); filenames.AddTail(vstreams.GetAt(vstreams.FindIndex(i))); filenames.AddTail(astreams.GetAt(astreams.FindIndex(i))); - m_wndPlaylistBar.Append(filenames, false); + m_wndPlaylistBar.Append(filenames, false, nullptr, + names.GetAt(names.FindIndex(i)) + + " (" + dlg.GetFileNames().GetHead() + ")"); } if (!dlg.GetAppendToPlaylist()) { @@ -6962,7 +6968,7 @@ void CMainFrame::OnPlayPlay() strOSD.LoadString(IDS_PLAY_BD); } else { strOSD = GetFileName(); - if (!strOSD.IsEmpty()) { + if (!strOSD.IsEmpty() && !m_wndPlaylistBar.GetCur()->m_bUseLabelAsFilename) { strOSD.TrimRight('/'); strOSD.Replace('\\', '/'); strOSD = strOSD.Mid(strOSD.ReverseFind('/') + 1); @@ -12257,7 +12263,7 @@ void CMainFrame::SendNowPlayingToSkype() if (GetPlaybackMode() == PM_FILE) { CString fn = label; - if (fn.Find(_T("://")) >= 0) { + if (!pli.m_bUseLabelAsFilename && fn.Find(_T("://")) >= 0) { int i = fn.Find('?'); if (i >= 0) { fn = fn.Left(i); @@ -16678,14 +16684,14 @@ CString CMainFrame::GetFileName() { CString path(m_wndPlaylistBar.GetCurFileName()); - if (m_pFSF) { + if (!m_wndPlaylistBar.GetCur()->m_bUseLabelAsFilename && m_pFSF) { CComHeapPtr pFN; if (SUCCEEDED(m_pFSF->GetCurFile(&pFN, nullptr))) { path = pFN; } } - return PathUtils::StripPathOrUrl(path); + return m_wndPlaylistBar.GetCur()->m_bUseLabelAsFilename ? path : PathUtils::StripPathOrUrl(path); } CString CMainFrame::GetCaptureTitle() @@ -17213,3 +17219,24 @@ bool CMainFrame::GetYoutubeHttpsStreams(CString url, CAtlList& video, C return true; } + +bool CMainFrame::GetYoutubeNames(CString url, CAtlList& names) +{ + CString out, err; + if (!CallYoutubeDL(CString("-e -- \"" + url + "\""), out, err)) { + return false; + } + + int idx = 0; + int next; + while (true) { + next = out.Find('\n', idx); + if (next == -1) { + break; + } + names.AddTail(out.Left(next).Right(next - idx)); + idx = next + 1; + } + + return true; +} diff --git a/src/mpc-hc/MainFrm.h b/src/mpc-hc/MainFrm.h index 8599f4cee88..c24d8fd23a8 100644 --- a/src/mpc-hc/MainFrm.h +++ b/src/mpc-hc/MainFrm.h @@ -1108,4 +1108,5 @@ class CMainFrame : public CFrameWnd, public CDropClient bool IsYoutubeURL(CString url); bool CallYoutubeDL(CString cmd, CString& out, CString& err); bool GetYoutubeHttpsStreams(CString url, CAtlList& video, CAtlList& audio); + bool GetYoutubeNames(CString url, CAtlList& names); }; diff --git a/src/mpc-hc/PlayerPlaylistBar.cpp b/src/mpc-hc/PlayerPlaylistBar.cpp index 61accd7dc7e..d00cb80844b 100644 --- a/src/mpc-hc/PlayerPlaylistBar.cpp +++ b/src/mpc-hc/PlayerPlaylistBar.cpp @@ -153,7 +153,7 @@ void CPlayerPlaylistBar::AddItem(CString fn, CAtlList* subs) AddItem(sl, subs); } -void CPlayerPlaylistBar::AddItem(CAtlList& fns, CAtlList* subs) +void CPlayerPlaylistBar::AddItem(CAtlList& fns, CAtlList* subs, CString label) { CPlaylistItem pli; @@ -180,6 +180,10 @@ void CPlayerPlaylistBar::AddItem(CAtlList& fns, CAtlList* subs } pli.AutoLoadFiles(); + if (!label.IsEmpty()) { + pli.m_label = label; + pli.m_bUseLabelAsFilename = true; + } m_pl.AddTail(pli); } @@ -270,7 +274,7 @@ void CPlayerPlaylistBar::ResolveLinkFiles(CAtlList& fns) } } -void CPlayerPlaylistBar::ParsePlayList(CAtlList& fns, CAtlList* subs) +void CPlayerPlaylistBar::ParsePlayList(CAtlList& fns, CAtlList* subs, CString label) { if (fns.IsEmpty()) { return; @@ -314,7 +318,7 @@ void CPlayerPlaylistBar::ParsePlayList(CAtlList& fns, CAtlList #endif } - AddItem(fns, subs); + AddItem(fns, subs, label); } static CString CombinePath(CPath p, CString fn) @@ -500,7 +504,7 @@ void CPlayerPlaylistBar::Open(CAtlList& fns, bool fMulti, CAtlList& fns, bool fMulti, CAtlList* subs) +void CPlayerPlaylistBar::Append(CAtlList& fns, bool fMulti, CAtlList* subs, CString label) { POSITION posFirstAdded = m_pl.GetTailPosition(); int iFirstAdded = (int)m_pl.GetCount(); @@ -512,7 +516,7 @@ void CPlayerPlaylistBar::Append(CAtlList& fns, bool fMulti, CAtlListm_fns.IsEmpty()) { + + if (pli && pli->m_bUseLabelAsFilename) { + fn = pli->m_label; + } else if (pli && !pli->m_fns.IsEmpty()) { fn = pli->m_fns.GetHead(); } return fn; diff --git a/src/mpc-hc/PlayerPlaylistBar.h b/src/mpc-hc/PlayerPlaylistBar.h index 2590b0a127a..a868bfc29ed 100644 --- a/src/mpc-hc/PlayerPlaylistBar.h +++ b/src/mpc-hc/PlayerPlaylistBar.h @@ -56,9 +56,9 @@ class CPlayerPlaylistBar : public CPlayerBar, public CDropClient void ResizeListColumn(); void AddItem(CString fn, CAtlList* subs); - void AddItem(CAtlList& fns, CAtlList* subs); + void AddItem(CAtlList& fns, CAtlList* subs, CString label = _T("")); void ParsePlayList(CString fn, CAtlList* subs); - void ParsePlayList(CAtlList& fns, CAtlList* subs); + void ParsePlayList(CAtlList& fns, CAtlList* subs, CString label = _T("")); void ResolveLinkFiles(CAtlList& fns); bool ParseBDMVPlayList(CString fn); @@ -121,7 +121,7 @@ class CPlayerPlaylistBar : public CPlayerBar, public CDropClient bool Empty(); void Open(CAtlList& fns, bool fMulti, CAtlList* subs = nullptr); - void Append(CAtlList& fns, bool fMulti, CAtlList* subs = nullptr); + void Append(CAtlList& fns, bool fMulti, CAtlList* subs = nullptr, CString label = _T("")); void Open(CStringW vdn, CStringW adn, int vinput, int vchannel, int ainput); void Append(CStringW vdn, CStringW adn, int vinput, int vchannel, int ainput); diff --git a/src/mpc-hc/Playlist.cpp b/src/mpc-hc/Playlist.cpp index 5396a5ebf55..48f9bbc8067 100644 --- a/src/mpc-hc/Playlist.cpp +++ b/src/mpc-hc/Playlist.cpp @@ -41,6 +41,7 @@ CPlaylistItem::CPlaylistItem() , m_ainput(-1) , m_country(0) , m_fInvalid(false) + , m_bUseLabelAsFilename(false) { m_id = m_globalid++; } diff --git a/src/mpc-hc/Playlist.h b/src/mpc-hc/Playlist.h index 48a9f2aad95..9a570c6b711 100644 --- a/src/mpc-hc/Playlist.h +++ b/src/mpc-hc/Playlist.h @@ -1,6 +1,6 @@ /* * (C) 2003-2006 Gabest - * (C) 2006-2012, 2015 see Authors.txt + * (C) 2006-2012, 2015, 2017 see Authors.txt * * This file is part of MPC-HC. * @@ -35,6 +35,7 @@ class CPlaylistItem public: UINT m_id; CString m_label; + bool m_bUseLabelAsFilename; CAtlList m_fns; CAtlList m_subs; enum type_t { file, device } m_type; From e9367726ba66f30dd8d66c8d493e90692531a46b Mon Sep 17 00:00:00 2001 From: Nicholas Parkanyi Date: Thu, 21 Sep 2017 23:08:33 -0400 Subject: [PATCH 12/26] add normal youtube url to recent files list instead of raw https stream url. --- src/mpc-hc/MainFrm.cpp | 76 ++++++++++++++++++++------------ src/mpc-hc/MainFrm.h | 4 +- src/mpc-hc/PlayerPlaylistBar.cpp | 1 + src/mpc-hc/Playlist.cpp | 1 + 4 files changed, 53 insertions(+), 29 deletions(-) diff --git a/src/mpc-hc/MainFrm.cpp b/src/mpc-hc/MainFrm.cpp index 3f271b641c9..1636ce692b2 100644 --- a/src/mpc-hc/MainFrm.cpp +++ b/src/mpc-hc/MainFrm.cpp @@ -3832,33 +3832,7 @@ void CMainFrame::OnFileOpenmedia() CAtlList filenames; if (IsYoutubeURL(dlg.GetFileNames().GetHead())) { - CAtlList vstreams; - CAtlList astreams; - CAtlList names; - - if (!GetYoutubeHttpsStreams(dlg.GetFileNames().GetHead(), vstreams, astreams)) { - return; - } - if (!GetYoutubeNames(dlg.GetFileNames().GetHead(), names)) { - return; - } - - if (!dlg.GetAppendToPlaylist()) { - m_wndPlaylistBar.Empty(); - } - for (int i = 0; i < vstreams.GetCount(); i++) { - filenames.RemoveAll(); - filenames.AddTail(vstreams.GetAt(vstreams.FindIndex(i))); - filenames.AddTail(astreams.GetAt(astreams.FindIndex(i))); - m_wndPlaylistBar.Append(filenames, false, nullptr, - names.GetAt(names.FindIndex(i)) - + " (" + dlg.GetFileNames().GetHead() + ")"); - } - - if (!dlg.GetAppendToPlaylist()) { - m_wndPlaylistBar.SetFirst(); - OpenCurPlaylistItem(); - } + ProcessYoutubeURL(dlg.GetFileNames().GetHead(), dlg.GetAppendToPlaylist()); return; } @@ -9072,6 +9046,13 @@ void CMainFrame::OnRecentFile(UINT nID) nID -= ID_RECENT_FILE_START; CString fn; m_recentFilesMenu.GetMenuString(nID + 2, fn, MF_BYPOSITION); + + if (IsYoutubeURL(fn)) { + OnPlayStop(); + ProcessYoutubeURL(fn, false); + return; + } + if (!m_wndPlaylistBar.SelectFileInPlaylist(fn)) { CAtlList fns; fns.AddTail(fn); @@ -10602,7 +10583,7 @@ void CMainFrame::OpenFile(OpenFileData* pOFD) } // We don't keep track of piped inputs since that hardly makes any sense - if (s.fKeepHistory && fn.Find(_T("pipe:")) != 0) { + if (s.fKeepHistory && fn.Find(_T("pipe:")) != 0 && pOFD->bAddToRecent) { CRecentFileList* pMRU = bMainFile ? &s.MRU : &s.MRUDub; pMRU->ReadList(); pMRU->Add(fn); @@ -17240,3 +17221,42 @@ bool CMainFrame::GetYoutubeNames(CString url, CAtlList& names) return true; } + +void CMainFrame::ProcessYoutubeURL(CString url, bool append) +{ + auto& s = AfxGetAppSettings(); + CAtlList vstreams; + CAtlList astreams; + CAtlList names; + CAtlList filenames; + + if (!GetYoutubeHttpsStreams(url, vstreams, astreams)) { + return; + } + if (!GetYoutubeNames(url, names)) { + return; + } + + if (!append) { + m_wndPlaylistBar.Empty(); + } + for (int i = 0; i < vstreams.GetCount(); i++) { + filenames.RemoveAll(); + filenames.AddTail(vstreams.GetAt(vstreams.FindIndex(i))); + filenames.AddTail(astreams.GetAt(astreams.FindIndex(i))); + m_wndPlaylistBar.Append(filenames, false, nullptr, + names.GetAt(names.FindIndex(i)) + + " (" + url + ")"); + } + + CRecentFileList* mru = &s.MRU; + mru->ReadList(); + mru->Add(url); + mru->WriteList(); + + if (!append) { + m_wndPlaylistBar.SetFirst(); + OpenCurPlaylistItem(); + } + return; +} diff --git a/src/mpc-hc/MainFrm.h b/src/mpc-hc/MainFrm.h index c24d8fd23a8..719efa93fe5 100644 --- a/src/mpc-hc/MainFrm.h +++ b/src/mpc-hc/MainFrm.h @@ -95,9 +95,10 @@ class OpenMediaData class OpenFileData : public OpenMediaData { public: - OpenFileData() : rtStart(0) {} + OpenFileData() : rtStart(0), bAddToRecent(true) {} CAtlList fns; REFERENCE_TIME rtStart; + bool bAddToRecent; }; class OpenDVDData : public OpenMediaData @@ -1109,4 +1110,5 @@ class CMainFrame : public CFrameWnd, public CDropClient bool CallYoutubeDL(CString cmd, CString& out, CString& err); bool GetYoutubeHttpsStreams(CString url, CAtlList& video, CAtlList& audio); bool GetYoutubeNames(CString url, CAtlList& names); + void ProcessYoutubeURL(CString url, bool append); }; diff --git a/src/mpc-hc/PlayerPlaylistBar.cpp b/src/mpc-hc/PlayerPlaylistBar.cpp index d00cb80844b..a4ccd18f4ed 100644 --- a/src/mpc-hc/PlayerPlaylistBar.cpp +++ b/src/mpc-hc/PlayerPlaylistBar.cpp @@ -814,6 +814,7 @@ OpenMediaData* CPlayerPlaylistBar::GetCurOMD(REFERENCE_TIME rtStart) p->fns.AddTailList(&pli->m_fns); p->subs.AddTailList(&pli->m_subs); p->rtStart = rtStart; + p->bAddToRecent = !pli->m_bUseLabelAsFilename; return p; } } diff --git a/src/mpc-hc/Playlist.cpp b/src/mpc-hc/Playlist.cpp index 48f9bbc8067..60d94b04018 100644 --- a/src/mpc-hc/Playlist.cpp +++ b/src/mpc-hc/Playlist.cpp @@ -73,6 +73,7 @@ CPlaylistItem& CPlaylistItem::operator=(const CPlaylistItem& pli) m_country = pli.m_country; m_posNextShuffle = pli.m_posNextShuffle; m_posPrevShuffle = pli.m_posPrevShuffle; + m_bUseLabelAsFilename = pli.m_bUseLabelAsFilename; } return *this; } From b1baada7e1cb7e9c15f9146c2882e447bea710dd Mon Sep 17 00:00:00 2001 From: Nicholas Parkanyi Date: Thu, 21 Sep 2017 23:59:42 -0400 Subject: [PATCH 13/26] only call youtube-dl once --- src/mpc-hc/MainFrm.cpp | 35 ++++++++--------------------------- src/mpc-hc/MainFrm.h | 3 +-- 2 files changed, 9 insertions(+), 29 deletions(-) diff --git a/src/mpc-hc/MainFrm.cpp b/src/mpc-hc/MainFrm.cpp index 1636ce692b2..0e4d6cf8ad7 100644 --- a/src/mpc-hc/MainFrm.cpp +++ b/src/mpc-hc/MainFrm.cpp @@ -17173,10 +17173,10 @@ bool CMainFrame::CallYoutubeDL(CString args, CString& out, CString& err) return true; } -bool CMainFrame::GetYoutubeHttpsStreams(CString url, CAtlList& video, CAtlList& audio) +bool CMainFrame::GetYoutubeHttpsStreams(CString url, CAtlList& video, CAtlList& audio, CAtlList& names) { CString out, err; - if (!CallYoutubeDL(CString("-g -- \"" + url + "\""), out, err)) { + if (!CallYoutubeDL(CString("-g -e -- \"" + url + "\""), out, err)) { return false; } @@ -17185,41 +17185,25 @@ bool CMainFrame::GetYoutubeHttpsStreams(CString url, CAtlList& video, C while (true) { next = out.Find('\n', idx); if (next == -1) { - break; + return true; } - video.AddTail(out.Left(next).Right(next - idx)); + names.AddTail(out.Left(next).Right(next - idx)); idx = next + 1; next = out.Find('\n', idx); if (next == -1) { return false; } - audio.AddTail(out.Left(next).Right(next - idx)); + video.AddTail(out.Left(next).Right(next - idx)); idx = next + 1; - } - return true; -} - -bool CMainFrame::GetYoutubeNames(CString url, CAtlList& names) -{ - CString out, err; - if (!CallYoutubeDL(CString("-e -- \"" + url + "\""), out, err)) { - return false; - } - - int idx = 0; - int next; - while (true) { next = out.Find('\n', idx); if (next == -1) { - break; + return false; } - names.AddTail(out.Left(next).Right(next - idx)); + audio.AddTail(out.Left(next).Right(next - idx)); idx = next + 1; } - - return true; } void CMainFrame::ProcessYoutubeURL(CString url, bool append) @@ -17230,10 +17214,7 @@ void CMainFrame::ProcessYoutubeURL(CString url, bool append) CAtlList names; CAtlList filenames; - if (!GetYoutubeHttpsStreams(url, vstreams, astreams)) { - return; - } - if (!GetYoutubeNames(url, names)) { + if (!GetYoutubeHttpsStreams(url, vstreams, astreams, names)) { return; } diff --git a/src/mpc-hc/MainFrm.h b/src/mpc-hc/MainFrm.h index 719efa93fe5..9c5c9f2e7c2 100644 --- a/src/mpc-hc/MainFrm.h +++ b/src/mpc-hc/MainFrm.h @@ -1108,7 +1108,6 @@ class CMainFrame : public CFrameWnd, public CDropClient //youtube-dl integration methods bool IsYoutubeURL(CString url); bool CallYoutubeDL(CString cmd, CString& out, CString& err); - bool GetYoutubeHttpsStreams(CString url, CAtlList& video, CAtlList& audio); - bool GetYoutubeNames(CString url, CAtlList& names); + bool GetYoutubeHttpsStreams(CString url, CAtlList& video, CAtlList& audio, CAtlList& names); void ProcessYoutubeURL(CString url, bool append); }; From 404ab864be88115674b2a9ae6cbef303c2ea7942 Mon Sep 17 00:00:00 2001 From: Nicholas Parkanyi Date: Sat, 23 Sep 2017 20:14:24 -0400 Subject: [PATCH 14/26] load Youtube links from command line --- src/mpc-hc/MainFrm.cpp | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/src/mpc-hc/MainFrm.cpp b/src/mpc-hc/MainFrm.cpp index 0e4d6cf8ad7..1fcf142afa3 100644 --- a/src/mpc-hc/MainFrm.cpp +++ b/src/mpc-hc/MainFrm.cpp @@ -3833,6 +3833,7 @@ void CMainFrame::OnFileOpenmedia() if (IsYoutubeURL(dlg.GetFileNames().GetHead())) { ProcessYoutubeURL(dlg.GetFileNames().GetHead(), dlg.GetAppendToPlaylist()); + OpenCurPlaylistItem(); return; } @@ -3997,6 +3998,7 @@ BOOL CMainFrame::OnCopyData(CWnd* pWnd, COPYDATASTRUCT* pCDS) PathUtils::ParseDirs(sl); bool fMulti = sl.GetCount() > 1; + bool fYoutube = IsYoutubeURL(sl.GetHead()); if (!fMulti) { sl.AddTailList(&s.slDubs); @@ -4021,7 +4023,11 @@ BOOL CMainFrame::OnCopyData(CWnd* pWnd, COPYDATASTRUCT* pCDS) m_dwLastRun = GetTickCount64(); if ((s.nCLSwitches & CLSW_ADD) && !IsPlaylistEmpty()) { - m_wndPlaylistBar.Append(sl, fMulti, &s.slSubs); + if (fYoutube) { + ProcessYoutubeURL(sl.GetHead(), true); + } else { + m_wndPlaylistBar.Append(sl, fMulti, &s.slSubs); + } applyRandomizeSwitch(); if (s.nCLSwitches & (CLSW_OPEN | CLSW_PLAY)) { @@ -4032,8 +4038,13 @@ BOOL CMainFrame::OnCopyData(CWnd* pWnd, COPYDATASTRUCT* pCDS) //SendMessage(WM_COMMAND, ID_FILE_CLOSEMEDIA); fSetForegroundWindow = true; - m_wndPlaylistBar.Open(sl, fMulti, &s.slSubs); + if (fYoutube) { + ProcessYoutubeURL(sl.GetHead(), false); + } else { + m_wndPlaylistBar.Open(sl, fMulti, &s.slSubs); + } applyRandomizeSwitch(); + m_wndPlaylistBar.SetFirst(); OpenCurPlaylistItem((s.nCLSwitches & CLSW_STARTVALID) ? s.rtStart : 0); s.nCLSwitches &= ~CLSW_STARTVALID; @@ -9050,6 +9061,7 @@ void CMainFrame::OnRecentFile(UINT nID) if (IsYoutubeURL(fn)) { OnPlayStop(); ProcessYoutubeURL(fn, false); + OpenCurPlaylistItem(); return; } @@ -17237,7 +17249,6 @@ void CMainFrame::ProcessYoutubeURL(CString url, bool append) if (!append) { m_wndPlaylistBar.SetFirst(); - OpenCurPlaylistItem(); } return; } From e6589a91aad00700aa32c434634d09fdde1d8b3a Mon Sep 17 00:00:00 2001 From: Nicholas Parkanyi Date: Sat, 23 Sep 2017 20:35:23 -0400 Subject: [PATCH 15/26] post to status bar when calling youtube-dl --- src/mpc-hc/MainFrm.cpp | 2 ++ src/mpc-hc/mpc-hc.rc | 1 + src/mpc-hc/resource.h | 1 + 3 files changed, 4 insertions(+) diff --git a/src/mpc-hc/MainFrm.cpp b/src/mpc-hc/MainFrm.cpp index 1fcf142afa3..8504aad182d 100644 --- a/src/mpc-hc/MainFrm.cpp +++ b/src/mpc-hc/MainFrm.cpp @@ -17226,6 +17226,8 @@ void CMainFrame::ProcessYoutubeURL(CString url, bool append) CAtlList names; CAtlList filenames; + m_wndStatusBar.SetStatusMessage(ResStr(IDS_CONTROLS_YOUTUBEDL)); + if (!GetYoutubeHttpsStreams(url, vstreams, astreams, names)) { return; } diff --git a/src/mpc-hc/mpc-hc.rc b/src/mpc-hc/mpc-hc.rc index 08f8ec23247..dc49c044157 100644 --- a/src/mpc-hc/mpc-hc.rc +++ b/src/mpc-hc/mpc-hc.rc @@ -3656,6 +3656,7 @@ BEGIN IDS_CMD_MUTE "/mute\t\tMute the audio" IDS_CMD_VOLUME "/volume N\tSet Volume, where N is a range from 0 to 100" IDS_YOUTUBEDL_NOT_FOUND "Youtube-dl failed to launch. Make sure youtube-dl is in PATH." + IDS_CONTROLS_YOUTUBEDL "Calling youtube-dl..." END STRINGTABLE diff --git a/src/mpc-hc/resource.h b/src/mpc-hc/resource.h index 0bd14028a6f..ce78a0254cc 100644 --- a/src/mpc-hc/resource.h +++ b/src/mpc-hc/resource.h @@ -1573,6 +1573,7 @@ #define IDS_CMD_MUTE 57537 #define IDS_CMD_VOLUME 57538 #define IDS_YOUTUBEDL_NOT_FOUND 57539 +#define IDS_CONTROLS_YOUTUBEDL 57540 // Next default values for new objects // From c4fbbfe7d7691ed447e076432ec054afd22ee511 Mon Sep 17 00:00:00 2001 From: Nicholas Parkanyi Date: Sat, 23 Sep 2017 20:45:37 -0400 Subject: [PATCH 16/26] fixed signed/unsigned mismatch --- src/mpc-hc/MainFrm.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/mpc-hc/MainFrm.cpp b/src/mpc-hc/MainFrm.cpp index 8504aad182d..a0379de6868 100644 --- a/src/mpc-hc/MainFrm.cpp +++ b/src/mpc-hc/MainFrm.cpp @@ -17024,8 +17024,8 @@ bool CMainFrame::IsYoutubeURL(CString url) HANDLE hStdout_r, hStdout_w; HANDLE hStderr_r, hStderr_w; -int idx_out = 0; -int idx_err = 0; +unsigned int idx_out = 0; +unsigned int idx_err = 0; size_t capacity_out, capacity_err; DWORD WINAPI BuffOutThread(void* buf) @@ -17235,7 +17235,7 @@ void CMainFrame::ProcessYoutubeURL(CString url, bool append) if (!append) { m_wndPlaylistBar.Empty(); } - for (int i = 0; i < vstreams.GetCount(); i++) { + for (unsigned int i = 0; i < vstreams.GetCount(); i++) { filenames.RemoveAll(); filenames.AddTail(vstreams.GetAt(vstreams.FindIndex(i))); filenames.AddTail(astreams.GetAt(astreams.FindIndex(i))); From 3319262751eeabe0ca74f384c1fc752cde1ec1bd Mon Sep 17 00:00:00 2001 From: Nicholas Parkanyi Date: Tue, 26 Sep 2017 23:42:09 -0400 Subject: [PATCH 17/26] Don't call OpenCurPlaylistItem() when appending youtube video to playlist. --- src/mpc-hc/MainFrm.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/mpc-hc/MainFrm.cpp b/src/mpc-hc/MainFrm.cpp index a0379de6868..5028f379b79 100644 --- a/src/mpc-hc/MainFrm.cpp +++ b/src/mpc-hc/MainFrm.cpp @@ -3833,7 +3833,9 @@ void CMainFrame::OnFileOpenmedia() if (IsYoutubeURL(dlg.GetFileNames().GetHead())) { ProcessYoutubeURL(dlg.GetFileNames().GetHead(), dlg.GetAppendToPlaylist()); - OpenCurPlaylistItem(); + if (!dlg.GetAppendToPlaylist()) { + OpenCurPlaylistItem(); + } return; } From 30784b80c03dcd207bcf1b98113099b0f9275a23 Mon Sep 17 00:00:00 2001 From: Nicholas Parkanyi Date: Wed, 27 Sep 2017 01:37:57 -0400 Subject: [PATCH 18/26] using -f option in youtube-dl allows us to get audio and video in one URL --- src/mpc-hc/MainFrm.cpp | 15 +++------------ src/mpc-hc/MainFrm.h | 2 +- 2 files changed, 4 insertions(+), 13 deletions(-) diff --git a/src/mpc-hc/MainFrm.cpp b/src/mpc-hc/MainFrm.cpp index 5028f379b79..eb6faddef42 100644 --- a/src/mpc-hc/MainFrm.cpp +++ b/src/mpc-hc/MainFrm.cpp @@ -17187,10 +17187,10 @@ bool CMainFrame::CallYoutubeDL(CString args, CString& out, CString& err) return true; } -bool CMainFrame::GetYoutubeHttpsStreams(CString url, CAtlList& video, CAtlList& audio, CAtlList& names) +bool CMainFrame::GetYoutubeHttpsStreams(CString url, CAtlList& video, CAtlList& names) { CString out, err; - if (!CallYoutubeDL(CString("-g -e -- \"" + url + "\""), out, err)) { + if (!CallYoutubeDL(CString("-g -f best -e -- \"" + url + "\""), out, err)) { return false; } @@ -17210,13 +17210,6 @@ bool CMainFrame::GetYoutubeHttpsStreams(CString url, CAtlList& video, C } video.AddTail(out.Left(next).Right(next - idx)); idx = next + 1; - - next = out.Find('\n', idx); - if (next == -1) { - return false; - } - audio.AddTail(out.Left(next).Right(next - idx)); - idx = next + 1; } } @@ -17224,13 +17217,12 @@ void CMainFrame::ProcessYoutubeURL(CString url, bool append) { auto& s = AfxGetAppSettings(); CAtlList vstreams; - CAtlList astreams; CAtlList names; CAtlList filenames; m_wndStatusBar.SetStatusMessage(ResStr(IDS_CONTROLS_YOUTUBEDL)); - if (!GetYoutubeHttpsStreams(url, vstreams, astreams, names)) { + if (!GetYoutubeHttpsStreams(url, vstreams, names)) { return; } @@ -17240,7 +17232,6 @@ void CMainFrame::ProcessYoutubeURL(CString url, bool append) for (unsigned int i = 0; i < vstreams.GetCount(); i++) { filenames.RemoveAll(); filenames.AddTail(vstreams.GetAt(vstreams.FindIndex(i))); - filenames.AddTail(astreams.GetAt(astreams.FindIndex(i))); m_wndPlaylistBar.Append(filenames, false, nullptr, names.GetAt(names.FindIndex(i)) + " (" + url + ")"); diff --git a/src/mpc-hc/MainFrm.h b/src/mpc-hc/MainFrm.h index 9c5c9f2e7c2..1f0c2cc5348 100644 --- a/src/mpc-hc/MainFrm.h +++ b/src/mpc-hc/MainFrm.h @@ -1108,6 +1108,6 @@ class CMainFrame : public CFrameWnd, public CDropClient //youtube-dl integration methods bool IsYoutubeURL(CString url); bool CallYoutubeDL(CString cmd, CString& out, CString& err); - bool GetYoutubeHttpsStreams(CString url, CAtlList& video, CAtlList& audio, CAtlList& names); + bool GetYoutubeHttpsStreams(CString url, CAtlList& video, CAtlList& names); void ProcessYoutubeURL(CString url, bool append); }; From aff39e1df3fb5916e33fa9370f329ac29e29bb44 Mon Sep 17 00:00:00 2001 From: Nicholas Parkanyi Date: Sat, 4 Nov 2017 22:41:48 -0400 Subject: [PATCH 19/26] Call youtube-dl -J and parse JSON with rapidjson (CYoutubeDLInstance) --- src/mpc-hc/MainFrm.cpp | 240 +++++----------------------------- src/mpc-hc/MainFrm.h | 6 +- src/mpc-hc/YoutubeDL.cpp | 274 +++++++++++++++++++++++++++++++++++++++ src/mpc-hc/YoutubeDL.h | 29 +++++ 4 files changed, 337 insertions(+), 212 deletions(-) create mode 100644 src/mpc-hc/YoutubeDL.cpp create mode 100644 src/mpc-hc/YoutubeDL.h diff --git a/src/mpc-hc/MainFrm.cpp b/src/mpc-hc/MainFrm.cpp index eb6faddef42..818fda8e27c 100644 --- a/src/mpc-hc/MainFrm.cpp +++ b/src/mpc-hc/MainFrm.cpp @@ -105,6 +105,9 @@ #include #include +#include "YoutubeDL.h" + + // IID_IAMLine21Decoder DECLARE_INTERFACE_IID_(IAMLine21Decoder_2, IAMLine21Decoder, "6E8D4A21-310C-11d0-B79A-00AA003767A7") {}; @@ -3831,8 +3834,8 @@ void CMainFrame::OnFileOpenmedia() CAtlList filenames; - if (IsYoutubeURL(dlg.GetFileNames().GetHead())) { - ProcessYoutubeURL(dlg.GetFileNames().GetHead(), dlg.GetAppendToPlaylist()); + if (dlg.GetFileNames().GetHead().Left(4) == _T("http") + && ProcessYoutubeDLURL(dlg.GetFileNames().GetHead(), dlg.GetAppendToPlaylist())) { if (!dlg.GetAppendToPlaylist()) { OpenCurPlaylistItem(); } @@ -4000,7 +4003,7 @@ BOOL CMainFrame::OnCopyData(CWnd* pWnd, COPYDATASTRUCT* pCDS) PathUtils::ParseDirs(sl); bool fMulti = sl.GetCount() > 1; - bool fYoutube = IsYoutubeURL(sl.GetHead()); + bool fYoutubeDL = sl.GetHead().Left(4) == _T("http"); if (!fMulti) { sl.AddTailList(&s.slDubs); @@ -4025,9 +4028,11 @@ BOOL CMainFrame::OnCopyData(CWnd* pWnd, COPYDATASTRUCT* pCDS) m_dwLastRun = GetTickCount64(); if ((s.nCLSwitches & CLSW_ADD) && !IsPlaylistEmpty()) { - if (fYoutube) { - ProcessYoutubeURL(sl.GetHead(), true); - } else { + float r = false; + if (fYoutubeDL) { + r = ProcessYoutubeDLURL(sl.GetHead(), true); + } + if (!r) { //not an http link, or youtube-dl unavailable m_wndPlaylistBar.Append(sl, fMulti, &s.slSubs); } applyRandomizeSwitch(); @@ -4040,9 +4045,11 @@ BOOL CMainFrame::OnCopyData(CWnd* pWnd, COPYDATASTRUCT* pCDS) //SendMessage(WM_COMMAND, ID_FILE_CLOSEMEDIA); fSetForegroundWindow = true; - if (fYoutube) { - ProcessYoutubeURL(sl.GetHead(), false); - } else { + float r = false; + if (fYoutubeDL) { //not an http link or youtube-dl unavailable + r = ProcessYoutubeDLURL(sl.GetHead(), false); + } + if (!r) { m_wndPlaylistBar.Open(sl, fMulti, &s.slSubs); } applyRandomizeSwitch(); @@ -9060,11 +9067,12 @@ void CMainFrame::OnRecentFile(UINT nID) CString fn; m_recentFilesMenu.GetMenuString(nID + 2, fn, MF_BYPOSITION); - if (IsYoutubeURL(fn)) { + if (fn.Left(4) == _T("http")) { OnPlayStop(); - ProcessYoutubeURL(fn, false); - OpenCurPlaylistItem(); - return; + if (ProcessYoutubeDLURL(fn, false)) { + OpenCurPlaylistItem(); + return; + } } if (!m_wndPlaylistBar.SelectFileInPlaylist(fn)) { @@ -17011,14 +17019,6 @@ LRESULT CMainFrame::OnGetSubtitles(WPARAM, LPARAM lParam) return TRUE; } -bool CMainFrame::IsYoutubeURL(CString url) -{ - return url.Left(29) == _T("https://www.youtube.com/watch") || - url.Left(25) == _T("https://youtube.com/watch") || - url.Left(32) == _T("https://www.youtube.com/playlist") || - url.Left(28) == _T("https://youtube.com/playlist"); -} - ////////////////////////////////////// // Worker threads for CallYoutubeDL() @@ -17030,200 +17030,23 @@ unsigned int idx_out = 0; unsigned int idx_err = 0; size_t capacity_out, capacity_err; -DWORD WINAPI BuffOutThread(void* buf) -{ - char** buf_out = static_cast(buf); - DWORD read; - - while (ReadFile(hStdout_r, *buf_out + idx_out, capacity_out - idx_out, &read, NULL)) { - idx_out += read; - if (idx_out == capacity_out) { - capacity_out *= 2; - char* tmp = static_cast(std::realloc(*buf_out, capacity_out)); - if (tmp) { - *buf_out = tmp; - } else { - std::free(*buf_out); - *buf_out = nullptr; - return 0; - } - } - } - - return GetLastError() == ERROR_BROKEN_PIPE ? 0 : GetLastError(); -} - -DWORD WINAPI BuffErrThread(void* buf) -{ - char** buf_err = static_cast(buf); - DWORD read; - - while (ReadFile(hStderr_r, *buf_err + idx_err, capacity_err - idx_err, &read, NULL)) { - idx_err += read; - if (idx_err == capacity_err) { - capacity_err *= 2; - char* tmp = static_cast(std::realloc(*buf_err, capacity_err)); - if (tmp) { - *buf_err = tmp; - } else { - std::free(*buf_err); - *buf_err = nullptr; - return 0; - } - } - } - - return GetLastError() == ERROR_BROKEN_PIPE ? 0 : GetLastError(); -} - -bool CMainFrame::CallYoutubeDL(CString args, CString& out, CString& err) -{ - const size_t bufsize = 2000; //2KB initial buffer size - - ///////////////////////////// - // Set up youtube-dl process - ///////////////////////////// - - PROCESS_INFORMATION proc_info; - STARTUPINFO startup_info; - SECURITY_ATTRIBUTES sec_attrib; - - - args = "youtube-dl " + args; - - ZeroMemory(&proc_info, sizeof(PROCESS_INFORMATION)); - ZeroMemory(&startup_info, sizeof(STARTUPINFO)); - - //child process must inherit the handles - sec_attrib.nLength = sizeof(SECURITY_ATTRIBUTES); - sec_attrib.lpSecurityDescriptor = NULL; - sec_attrib.bInheritHandle = true; - - if (!CreatePipe(&hStdout_r, &hStdout_w, &sec_attrib, bufsize)) { - return false; - } - if (!CreatePipe(&hStderr_r, &hStderr_w, &sec_attrib, bufsize)) { - return false; - } - - startup_info.cb = sizeof(STARTUPINFO); - startup_info.hStdOutput = hStdout_w; - startup_info.hStdError = hStderr_w; - startup_info.wShowWindow = SW_HIDE; - startup_info.dwFlags |= STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW; - - if (!CreateProcess(NULL, args.GetBuffer(), NULL, NULL, true, 0, - NULL, NULL, &startup_info, &proc_info)) { - AfxMessageBox(IDS_YOUTUBEDL_NOT_FOUND, MB_ICONERROR | MB_OK, 0); - return false; - } - - //we must close the parent process's write handles before calling ReadFile, - // otherwise it will block forever. - CloseHandle(hStdout_w); - CloseHandle(hStderr_w); - - - ///////////////////////////////////////////////////// - // Read in stdout and stderr through the pipe buffer - ///////////////////////////////////////////////////// - - char* buf_out = static_cast(std::malloc(bufsize)); - char* buf_err = static_cast(std::malloc(bufsize)); - capacity_out = bufsize; - capacity_err = bufsize; - - HANDLE hThreadOut, hThreadErr; - idx_out = 0; - idx_err = 0; - - hThreadOut = CreateThread(NULL, 0, BuffOutThread, &buf_out, NULL, NULL); - hThreadErr = CreateThread(NULL, 0, BuffErrThread, &buf_err, NULL, NULL); - - WaitForSingleObject(hThreadOut, INFINITE); - WaitForSingleObject(hThreadErr, INFINITE); - - if (!buf_out || !buf_err) { - throw std::bad_alloc(); - } - - //NULL-terminate the data - char* tmp; - if (idx_out == capacity_out) { - tmp = static_cast(std::realloc(buf_out, capacity_out + 1)); - if (tmp) { - buf_out = tmp; - } - } - buf_out[idx_out] = '\0'; - - if (idx_err == capacity_err) { - tmp = static_cast(std::realloc(buf_err, capacity_err + 1)); - if (tmp) { - buf_err = tmp; - } - } - buf_err[idx_err] = '\0'; - - out = buf_out; - err = buf_err; - - std::free(buf_out); - std::free(buf_err); - - DWORD exitcode; - GetExitCodeProcess(proc_info.hProcess, &exitcode); - if (exitcode) { - AfxMessageBox(err.GetBuffer(), MB_ICONERROR, 0); - return false; - } - - CloseHandle(proc_info.hProcess); - CloseHandle(proc_info.hThread); - CloseHandle(hThreadOut); - CloseHandle(hThreadErr); - CloseHandle(hStdout_r); - CloseHandle(hStderr_r); - return true; -} - -bool CMainFrame::GetYoutubeHttpsStreams(CString url, CAtlList& video, CAtlList& names) -{ - CString out, err; - if (!CallYoutubeDL(CString("-g -f best -e -- \"" + url + "\""), out, err)) { - return false; - } - - int idx = 0; - int next; - while (true) { - next = out.Find('\n', idx); - if (next == -1) { - return true; - } - names.AddTail(out.Left(next).Right(next - idx)); - idx = next + 1; - next = out.Find('\n', idx); - if (next == -1) { - return false; - } - video.AddTail(out.Left(next).Right(next - idx)); - idx = next + 1; - } -} - -void CMainFrame::ProcessYoutubeURL(CString url, bool append) +bool CMainFrame::ProcessYoutubeDLURL(CString url, bool append) { auto& s = AfxGetAppSettings(); CAtlList vstreams; + CAtlList astreams; CAtlList names; CAtlList filenames; + CYoutubeDLInstance ydl; m_wndStatusBar.SetStatusMessage(ResStr(IDS_CONTROLS_YOUTUBEDL)); - if (!GetYoutubeHttpsStreams(url, vstreams, names)) { - return; + if (!ydl.Run(url)) { + return false; + } + if (!ydl.GetHttpStreams(vstreams, astreams, names)) { + return false; } if (!append) { @@ -17232,6 +17055,9 @@ void CMainFrame::ProcessYoutubeURL(CString url, bool append) for (unsigned int i = 0; i < vstreams.GetCount(); i++) { filenames.RemoveAll(); filenames.AddTail(vstreams.GetAt(vstreams.FindIndex(i))); + if (!astreams.IsEmpty()) { + filenames.AddTail(astreams.GetAt(astreams.FindIndex(i))); + } m_wndPlaylistBar.Append(filenames, false, nullptr, names.GetAt(names.FindIndex(i)) + " (" + url + ")"); @@ -17245,5 +17071,5 @@ void CMainFrame::ProcessYoutubeURL(CString url, bool append) if (!append) { m_wndPlaylistBar.SetFirst(); } - return; + return true; } diff --git a/src/mpc-hc/MainFrm.h b/src/mpc-hc/MainFrm.h index 1f0c2cc5348..e34380b8182 100644 --- a/src/mpc-hc/MainFrm.h +++ b/src/mpc-hc/MainFrm.h @@ -1105,9 +1105,5 @@ class CMainFrame : public CFrameWnd, public CDropClient bool GetDecoderType(CString& type) const; private: - //youtube-dl integration methods - bool IsYoutubeURL(CString url); - bool CallYoutubeDL(CString cmd, CString& out, CString& err); - bool GetYoutubeHttpsStreams(CString url, CAtlList& video, CAtlList& names); - void ProcessYoutubeURL(CString url, bool append); + bool ProcessYoutubeDLURL(CString url, bool append); }; diff --git a/src/mpc-hc/YoutubeDL.cpp b/src/mpc-hc/YoutubeDL.cpp new file mode 100644 index 00000000000..79b1805f3f8 --- /dev/null +++ b/src/mpc-hc/YoutubeDL.cpp @@ -0,0 +1,274 @@ +#include "stdafx.h" +#include "YoutubeDL.h" +#include "rapidjson/include/rapidjson/document.h" + +typedef rapidjson::GenericValue> Value; + +struct CUtf16JSON { + rapidjson::GenericDocument> d; +}; + + +CYoutubeDLInstance::CYoutubeDLInstance() + : idx_out(0), idx_err(0), + buf_out(nullptr), buf_err(nullptr), + capacity_out(0), capacity_err(0), + pJSON(new CUtf16JSON) +{ +} + +CYoutubeDLInstance::~CYoutubeDLInstance() +{ + std::free(buf_out); + std::free(buf_err); + delete pJSON; +} + +bool CYoutubeDLInstance::Run(CString url) +{ + const size_t bufsize = 2000; //2KB initial buffer size + + ///////////////////////////// + // Set up youtube-dl process + ///////////////////////////// + + PROCESS_INFORMATION proc_info; + STARTUPINFO startup_info; + SECURITY_ATTRIBUTES sec_attrib; + + + CString args = "youtube-dl -J -- \"" + url + "\""; + + ZeroMemory(&proc_info, sizeof(PROCESS_INFORMATION)); + ZeroMemory(&startup_info, sizeof(STARTUPINFO)); + + //child process must inherit the handles + sec_attrib.nLength = sizeof(SECURITY_ATTRIBUTES); + sec_attrib.lpSecurityDescriptor = NULL; + sec_attrib.bInheritHandle = true; + + if (!CreatePipe(&hStdout_r, &hStdout_w, &sec_attrib, bufsize)) { + return false; + } + if (!CreatePipe(&hStderr_r, &hStderr_w, &sec_attrib, bufsize)) { + return false; + } + + startup_info.cb = sizeof(STARTUPINFO); + startup_info.hStdOutput = hStdout_w; + startup_info.hStdError = hStderr_w; + startup_info.wShowWindow = SW_HIDE; + startup_info.dwFlags |= STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW; + + if (!CreateProcess(NULL, args.GetBuffer(), NULL, NULL, true, 0, + NULL, NULL, &startup_info, &proc_info)) { + return false; + } + + //we must close the parent process's write handles before calling ReadFile, + // otherwise it will block forever. + CloseHandle(hStdout_w); + CloseHandle(hStderr_w); + + + ///////////////////////////////////////////////////// + // Read in stdout and stderr through the pipe buffer + ///////////////////////////////////////////////////// + + buf_out = static_cast(std::malloc(bufsize)); + buf_err = static_cast(std::malloc(bufsize)); + capacity_out = bufsize; + capacity_err = bufsize; + + HANDLE hThreadOut, hThreadErr; + idx_out = 0; + idx_err = 0; + + hThreadOut = CreateThread(NULL, 0, BuffOutThread, this, NULL, NULL); + hThreadErr = CreateThread(NULL, 0, BuffErrThread, this, NULL, NULL); + + WaitForSingleObject(hThreadOut, INFINITE); + WaitForSingleObject(hThreadErr, INFINITE); + + if (!buf_out || !buf_err) { + throw std::bad_alloc(); + } + + //NULL-terminate the data + char* tmp; + if (idx_out == capacity_out) { + tmp = static_cast(std::realloc(buf_out, capacity_out + 1)); + if (tmp) { + buf_out = tmp; + } + } + buf_out[idx_out] = '\0'; + + if (idx_err == capacity_err) { + tmp = static_cast(std::realloc(buf_err, capacity_err + 1)); + if (tmp) { + buf_err = tmp; + } + } + buf_err[idx_err] = '\0'; + + CString err = buf_err; + DWORD exitcode; + GetExitCodeProcess(proc_info.hProcess, &exitcode); + if (exitcode) { + AfxMessageBox(err.GetBuffer(), MB_ICONERROR, 0); + return false; + } + + CloseHandle(proc_info.hProcess); + CloseHandle(proc_info.hThread); + CloseHandle(hThreadOut); + CloseHandle(hThreadErr); + CloseHandle(hStdout_r); + CloseHandle(hStderr_r); + + return loadJSON(); +} + +DWORD WINAPI CYoutubeDLInstance::BuffOutThread(void* ydl_inst) +{ + auto ydl = static_cast(ydl_inst); + DWORD read; + + while (ReadFile(ydl->hStdout_r, ydl->buf_out + ydl->idx_out, ydl->capacity_out - ydl->idx_out, &read, NULL)) { + ydl->idx_out += read; + if (ydl->idx_out == ydl->capacity_out) { + ydl->capacity_out *= 2; + char* tmp = static_cast(std::realloc(ydl->buf_out, ydl->capacity_out)); + if (tmp) { + ydl->buf_out = tmp; + } else { + std::free(ydl->buf_out); + ydl->buf_out = nullptr; + return 0; + } + } + } + + return GetLastError() == ERROR_BROKEN_PIPE ? 0 : GetLastError(); +} + +DWORD WINAPI CYoutubeDLInstance::BuffErrThread(void* ydl_inst) +{ + auto ydl = static_cast(ydl_inst); + DWORD read; + + while (ReadFile(ydl->hStderr_r, ydl->buf_err + ydl->idx_err, ydl->capacity_err - ydl->idx_err, &read, NULL)) { + ydl->idx_err += read; + if (ydl->idx_err == ydl->capacity_err) { + ydl->capacity_err *= 2; + char* tmp = static_cast(std::realloc(ydl->buf_err, ydl->capacity_err)); + if (tmp) { + ydl->buf_err = tmp; + } else { + std::free(ydl->buf_err); + ydl->buf_err = nullptr; + return 0; + } + } + } + + return GetLastError() == ERROR_BROKEN_PIPE ? 0 : GetLastError(); +} + + +//find highest resolution +void filterVideo(const Value& formats, CString& url) +{ + int maxheight = 0; + + //no heights to compare, just return last format + if (formats[0].FindMember(_T("height")) == formats[0].MemberEnd()) { + url = formats[formats.Size() - 1][_T("url")].GetString(); + } + + for (rapidjson::SizeType i = 0; i < formats.Size(); i++) { + int curheight = 0; + if (formats[i].FindMember(_T("height")) != formats[i].MemberEnd() && !formats[i][_T("height")].IsNull()) { + curheight = formats[i][_T("height")].GetInt(); + } + if (curheight >= maxheight) { + maxheight = curheight; + url = formats[i][_T("url")].GetString(); + } + } +} + +//find audio track with highest bitrate (some sites (youtube, vidme) have audio and videos streams separate) +bool filterAudio(const Value& formats, CString& url) +{ + float maxtbr = 0.0; + bool found = false; + + for (rapidjson::SizeType i = 0; i < formats.Size(); i++) { + //only want audio streams + //youtube and vidme mark audio-only with vcodec = "none" + if (formats[i].HasMember(_T("vcodec")) && + !formats[i][_T("vcodec")].IsNull() && + CString(formats[i][_T("vcodec")].GetString()) == _T("none") && + formats[i].HasMember(_T("tbr")) && + !formats[i][_T("tbr")].IsNull()) { + float curtbr = formats[i][_T("tbr")].GetFloat(); + if (curtbr >= maxtbr) { + maxtbr = curtbr; + url = formats[i][_T("url")].GetString(); + found = true; + } + } + } + return found; +} + +bool CYoutubeDLInstance::GetHttpStreams(CAtlList& videos, CAtlList& audio, CAtlList& names) +{ + CString url; + CString extractor = pJSON->d[_T("extractor")].GetString(); + + if (!bIsPlaylist) { + names.AddTail(pJSON->d[_T("title")].GetString()); + + //detect generic http link; JSON fields below may not exist + if (extractor == _T("generic")) { + videos.AddTail(pJSON->d[_T("formats")][0][_T("url")].GetString()); + return true; + } + + filterVideo(pJSON->d[_T("formats")], url); + videos.AddTail(url); + + //find separate audio stream, if applicable + if (filterAudio(pJSON->d[_T("formats")], url)) { + audio.AddTail(url); + } + } else { + const Value& entries = pJSON->d[_T("entries")]; + + for (rapidjson::SizeType i = 0; i < entries.Size(); i++) { + filterVideo(entries[i][_T("formats")], url); + videos.AddTail(url); + names.AddTail(entries[i][_T("title")].GetString()); + + if (filterAudio(entries[i][_T("formats")], url)) { + audio.AddTail(url); + } + } + } + return true; +} + + +bool CYoutubeDLInstance::loadJSON() +{ + //the JSON buffer is ASCII with Unicode encoded with escape characters + pJSON->d.Parse>(buf_out); + if (pJSON->d.HasParseError()) { + return false; + } + bIsPlaylist = pJSON->d.FindMember(_T("entries")) != pJSON->d.MemberEnd(); + return true; +} diff --git a/src/mpc-hc/YoutubeDL.h b/src/mpc-hc/YoutubeDL.h new file mode 100644 index 00000000000..d326b36666a --- /dev/null +++ b/src/mpc-hc/YoutubeDL.h @@ -0,0 +1,29 @@ +#pragma once +#include "stdafx.h" + +struct CUtf16JSON; + +class CYoutubeDLInstance +{ +public: + CYoutubeDLInstance(); + ~CYoutubeDLInstance(); + + bool Run(CString url); + bool GetHttpStreams(CAtlList& videos, CAtlList& audio, CAtlList& names); + +private: + CUtf16JSON* pJSON; + bool bIsPlaylist; + HANDLE hStdout_r, hStdout_w; + HANDLE hStderr_r, hStderr_w; + char* buf_out; + char* buf_err; + DWORD idx_out; + DWORD idx_err; + DWORD capacity_out, capacity_err; + + bool loadJSON(); + static DWORD WINAPI BuffOutThread(void* ydl_inst); + static DWORD WINAPI BuffErrThread(void* ydl_inst); +}; From 77968225c10a93f2f746a9ddcc67ef0ab37650ed Mon Sep 17 00:00:00 2001 From: Nicholas Parkanyi Date: Sun, 5 Nov 2017 21:14:48 -0500 Subject: [PATCH 20/26] updated project files to include YoutubeDL.{cpp,h}. --- src/mpc-hc/mpc-hc.vcxproj | 2 ++ src/mpc-hc/mpc-hc.vcxproj.filters | 2 ++ 2 files changed, 4 insertions(+) diff --git a/src/mpc-hc/mpc-hc.vcxproj b/src/mpc-hc/mpc-hc.vcxproj index e083699fcfc..437246ed241 100644 --- a/src/mpc-hc/mpc-hc.vcxproj +++ b/src/mpc-hc/mpc-hc.vcxproj @@ -272,6 +272,7 @@ NotUsing + @@ -417,6 +418,7 @@ + diff --git a/src/mpc-hc/mpc-hc.vcxproj.filters b/src/mpc-hc/mpc-hc.vcxproj.filters index d5ff7f00372..cbf8550c00f 100644 --- a/src/mpc-hc/mpc-hc.vcxproj.filters +++ b/src/mpc-hc/mpc-hc.vcxproj.filters @@ -468,6 +468,7 @@ Helpers + @@ -875,6 +876,7 @@ Helpers + From 8e3ec16d7fd7744aa3589065387e5939039df6c7 Mon Sep 17 00:00:00 2001 From: Nicholas Parkanyi Date: Tue, 7 Nov 2017 23:28:14 -0500 Subject: [PATCH 21/26] drag-n-drop support for youtube-dl urls --- src/mpc-hc/MainFrm.cpp | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/mpc-hc/MainFrm.cpp b/src/mpc-hc/MainFrm.cpp index 818fda8e27c..dde75fc8ca5 100644 --- a/src/mpc-hc/MainFrm.cpp +++ b/src/mpc-hc/MainFrm.cpp @@ -4272,6 +4272,7 @@ void CMainFrame::OnDropFiles(CAtlList& slFiles, DROPEFFECT dropEffect) } } + bool bAppend = !!(dropEffect & DROPEFFECT_APPEND); // Use the first subtitle file that was just loaded if (subInputSelected.pSubStream) { AfxGetAppSettings().fEnableSubtitles = true; @@ -4286,7 +4287,17 @@ void CMainFrame::OnDropFiles(CAtlList& slFiles, DROPEFFECT dropEffect) } SendStatusMessage(filenames + ResStr(IDS_SUB_LOADED_SUCCESS), 3000); } else { - if (dropEffect & DROPEFFECT_APPEND) { + //load http url with youtube-dl, if available + if (slFiles.GetHead().Left(4) == _T("http")) { + if (ProcessYoutubeDLURL(slFiles.GetHead(), bAppend)) { + if (!bAppend) { + OpenCurPlaylistItem(); + } + return; + } + } + + if (bAppend) { m_wndPlaylistBar.Append(slFiles, true); } else { m_wndPlaylistBar.Open(slFiles, true); From 34fd9850f399eca435568d9176ca819e15ac4886 Mon Sep 17 00:00:00 2001 From: Nicholas Parkanyi Date: Thu, 23 Nov 2017 23:14:20 -0500 Subject: [PATCH 22/26] removed leftover crap --- src/mpc-hc/MainFrm.cpp | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/src/mpc-hc/MainFrm.cpp b/src/mpc-hc/MainFrm.cpp index dde75fc8ca5..f7616f2127a 100644 --- a/src/mpc-hc/MainFrm.cpp +++ b/src/mpc-hc/MainFrm.cpp @@ -17031,17 +17031,6 @@ LRESULT CMainFrame::OnGetSubtitles(WPARAM, LPARAM lParam) } -////////////////////////////////////// -// Worker threads for CallYoutubeDL() -////////////////////////////////////// - -HANDLE hStdout_r, hStdout_w; -HANDLE hStderr_r, hStderr_w; -unsigned int idx_out = 0; -unsigned int idx_err = 0; -size_t capacity_out, capacity_err; - - bool CMainFrame::ProcessYoutubeDLURL(CString url, bool append) { auto& s = AfxGetAppSettings(); From 1dd4a5c26fefbd8e86ecced071c171ddf0097c69 Mon Sep 17 00:00:00 2001 From: Nicholas Parkanyi Date: Thu, 25 Jan 2018 19:05:18 -0500 Subject: [PATCH 23/26] fixed typos --- src/mpc-hc/MainFrm.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/mpc-hc/MainFrm.cpp b/src/mpc-hc/MainFrm.cpp index f7616f2127a..86a5fb7490c 100644 --- a/src/mpc-hc/MainFrm.cpp +++ b/src/mpc-hc/MainFrm.cpp @@ -4028,7 +4028,7 @@ BOOL CMainFrame::OnCopyData(CWnd* pWnd, COPYDATASTRUCT* pCDS) m_dwLastRun = GetTickCount64(); if ((s.nCLSwitches & CLSW_ADD) && !IsPlaylistEmpty()) { - float r = false; + bool r = false; if (fYoutubeDL) { r = ProcessYoutubeDLURL(sl.GetHead(), true); } @@ -4045,11 +4045,11 @@ BOOL CMainFrame::OnCopyData(CWnd* pWnd, COPYDATASTRUCT* pCDS) //SendMessage(WM_COMMAND, ID_FILE_CLOSEMEDIA); fSetForegroundWindow = true; - float r = false; - if (fYoutubeDL) { //not an http link or youtube-dl unavailable + bool r = false; + if (fYoutubeDL) { r = ProcessYoutubeDLURL(sl.GetHead(), false); } - if (!r) { + if (!r) { //not an http link or youtube-dl unavailable m_wndPlaylistBar.Open(sl, fMulti, &s.slSubs); } applyRandomizeSwitch(); From c3b496bc4172dcd2ef4dcf2c552d471018530004 Mon Sep 17 00:00:00 2001 From: Nicholas Parkanyi Date: Sun, 11 Feb 2018 01:39:19 -0500 Subject: [PATCH 24/26] added maximum video height option under advanced settings --- src/mpc-hc/AppSettings.cpp | 8 ++++ src/mpc-hc/AppSettings.h | 38 +++++++++++++---- src/mpc-hc/PPageAdvanced.cpp | 2 + src/mpc-hc/PPageAdvanced.h | 82 +++++++++++++++++++++++++++--------- src/mpc-hc/SettingsDefines.h | 3 ++ src/mpc-hc/YoutubeDL.cpp | 10 +++-- 6 files changed, 111 insertions(+), 32 deletions(-) diff --git a/src/mpc-hc/AppSettings.cpp b/src/mpc-hc/AppSettings.cpp index 088a118e7e6..5b91ef26d4a 100644 --- a/src/mpc-hc/AppSettings.cpp +++ b/src/mpc-hc/AppSettings.cpp @@ -213,6 +213,8 @@ CAppSettings::CAppSettings() , iLAVGPUDevice(DWORD_MAX) , nCmdVolume(0) , eSubtitleRenderer(SubtitleRenderer::INTERNAL) + , iYDLMaxHeight(0) + , bYDLAudioOnly(false) { // Internal source filter #if INTERNAL_SOURCEFILTER_CDDA @@ -1089,6 +1091,9 @@ void CAppSettings::SaveSettings() pApp->WriteProfileInt(IDS_R_SANEAR, IDS_RS_SANEAR_CROSSFEED_LEVEL, uCrossfeedLevel); } + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_YDL_MAX_HEIGHT, iYDLMaxHeight); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_YDL_AUDIO_ONLY, bYDLAudioOnly); + pApp->FlushProfile(); } @@ -1826,6 +1831,9 @@ void CAppSettings::LoadSettings() pApp->GetProfileInt(IDS_R_SANEAR, IDS_RS_SANEAR_CROSSFEED_LEVEL, SaneAudioRenderer::ISettings::CROSSFEED_LEVEL_CMOY)); + iYDLMaxHeight = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_YDL_MAX_HEIGHT, 0); + bYDLAudioOnly = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_YDL_AUDIO_ONLY, FALSE); + bInitialized = true; } diff --git a/src/mpc-hc/AppSettings.h b/src/mpc-hc/AppSettings.h index 9dfb1fb3d47..a458e81ebd1 100644 --- a/src/mpc-hc/AppSettings.h +++ b/src/mpc-hc/AppSettings.h @@ -275,7 +275,9 @@ struct wmcmd_base : public ACCEL { }; wmcmd_base() - : ACCEL( { 0, 0, 0 }) + : ACCEL( { + 0, 0, 0 + }) , mouse(NONE) , mouseFS(NONE) , dwname(0) @@ -316,7 +318,9 @@ class wmcmd : public wmcmd_base return cmd > 0 && cmd == wc.cmd; } - CString GetName() const { return ResStr(dwname); } + CString GetName() const { + return ResStr(dwname); + } void Restore() { ASSERT(default_cmd); @@ -364,7 +368,9 @@ class CRemoteCtrlClient : public CAsyncSocket void SetHWND(HWND hWnd); void Connect(CString addr); void DisConnect(); - int GetStatus() const { return m_nStatus; } + int GetStatus() const { + return m_nStatus; + } }; class CWinLircClient : public CRemoteCtrlClient @@ -416,7 +422,9 @@ class CAppSettings DVD_HMSF_TIMECODE DVDPosition; CSize sizeFixedWindow; - bool HasFixedWindowSize() const { return sizeFixedWindow.cx > 0 || sizeFixedWindow.cy > 0; } + bool HasFixedWindowSize() const { + return sizeFixedWindow.cx > 0 || sizeFixedWindow.cy > 0; + } //int iFixedWidth, iFixedHeight; int iMonitor; @@ -722,7 +730,9 @@ class CAppSettings }; SubtitleRenderer GetSubtitleRenderer() const; - void SetSubtitleRenderer(SubtitleRenderer renderer) { eSubtitleRenderer = renderer; } + void SetSubtitleRenderer(SubtitleRenderer renderer) { + eSubtitleRenderer = renderer; + } static bool IsSubtitleRendererRegistered(SubtitleRenderer eSubtitleRenderer); @@ -732,7 +742,13 @@ class CAppSettings ASSERT(fKeepAspectRatio && "Keep Aspect Ratio option have to be enabled if override value is used."); return sizeAspectRatio; }; - void SetAspectRatioOverride(const CSize& ar) { sizeAspectRatio = ar; } + void SetAspectRatioOverride(const CSize& ar) { + sizeAspectRatio = ar; + } + + //YoutubeDL settings + int iYDLMaxHeight; + bool bYDLAudioOnly; private: struct FilterKey { @@ -779,10 +795,16 @@ class CAppSettings void SaveSettings(); void LoadSettings(); - void SaveExternalFilters() { if (bInitialized) { SaveExternalFilters(m_filters); } }; + void SaveExternalFilters() { + if (bInitialized) { + SaveExternalFilters(m_filters); + } + }; void UpdateSettings(); - void SetAsUninitialized() { bInitialized = false; }; + void SetAsUninitialized() { + bInitialized = false; + }; void GetFav(favtype ft, CAtlList& sl) const; void SetFav(favtype ft, CAtlList& sl); diff --git a/src/mpc-hc/PPageAdvanced.cpp b/src/mpc-hc/PPageAdvanced.cpp index 6039a9678d0..380222bd258 100644 --- a/src/mpc-hc/PPageAdvanced.cpp +++ b/src/mpc-hc/PPageAdvanced.cpp @@ -143,6 +143,8 @@ void CPPageAdvanced::InitSettings() addIntItem(DEFAULT_TOOLBAR_SIZE, IDS_RS_DEFAULTTOOLBARSIZE, 24, s.nDefaultToolbarSize, std::make_pair(16, 128), StrRes(IDS_PPAGEADVANCED_DEFAULTTOOLBARSIZE)); addBoolItem(USE_LEGACY_TOOLBAR, IDS_RS_USE_LEGACY_TOOLBAR, false, s.bUseLegacyToolbar, StrRes(IDS_PPAGEADVANCED_USE_LEGACY_TOOLBAR)); + addIntItem(YDL_MAX_HEIGHT, IDS_RS_YDL_MAX_HEIGHT, 0, s.iYDLMaxHeight, std::make_pair(0, INT_MAX), StrRes(IDS_RS_YDL_MAX_HEIGHT)); + addBoolItem(YDL_AUDIO_ONLY, IDS_RS_YDL_AUDIO_ONLY, false, s.bYDLAudioOnly, StrRes(IDS_RS_YDL_AUDIO_ONLY)); } BOOL CPPageAdvanced::OnApply() diff --git a/src/mpc-hc/PPageAdvanced.h b/src/mpc-hc/PPageAdvanced.h index 9dac3103ee3..5ae746a2283 100644 --- a/src/mpc-hc/PPageAdvanced.h +++ b/src/mpc-hc/PPageAdvanced.h @@ -40,8 +40,12 @@ class SettingsBase } virtual ~SettingsBase() = default; - CString GetToolTipText() const { return toolTipText; } - CString GetName() const { return name; } + CString GetToolTipText() const { + return toolTipText; + } + CString GetName() const { + return name; + } virtual bool IsDefault() const PURE; virtual void ResetDefault() PURE; virtual void Apply() PURE; @@ -61,12 +65,24 @@ class SettingsBool : public SettingsBase , settingReference(settingReference) { } - bool IsDefault() const { return currentValue == defaultValue; } - void ResetDefault() { SetValue(defaultValue); } - void SetValue(bool value) { currentValue = value; } - bool GetValue() const { return currentValue; } - void Apply() { settingReference = currentValue; } - void Toggle() { currentValue = !currentValue; } + bool IsDefault() const { + return currentValue == defaultValue; + } + void ResetDefault() { + SetValue(defaultValue); + } + void SetValue(bool value) { + currentValue = value; + } + bool GetValue() const { + return currentValue; + } + void Apply() { + settingReference = currentValue; + } + void Toggle() { + currentValue = !currentValue; + } }; class SettingsInt : public SettingsBase @@ -85,12 +101,24 @@ class SettingsInt : public SettingsBase , range(std::move(range)) { } - bool IsDefault() const { return currentValue == defaultValue; } - void ResetDefault() { SetValue(defaultValue); } - void SetValue(int value) { currentValue = value; } - int GetValue() const { return currentValue; } - void Apply() { settingReference = currentValue; } - std::pair GetRange() const { return range; } + bool IsDefault() const { + return currentValue == defaultValue; + } + void ResetDefault() { + SetValue(defaultValue); + } + void SetValue(int value) { + currentValue = value; + } + int GetValue() const { + return currentValue; + } + void Apply() { + settingReference = currentValue; + } + std::pair GetRange() const { + return range; + } }; class SettingsCombo : public SettingsInt @@ -103,7 +131,9 @@ class SettingsCombo : public SettingsInt , list(std::move(list)) { } - std::deque GetList() const { return list; } + std::deque GetList() const { + return list; + } }; class SettingsCString : public SettingsBase @@ -120,11 +150,21 @@ class SettingsCString : public SettingsBase , settingReference(settingReference) { } - bool IsDefault() const { return currentValue == defaultValue; } - void ResetDefault() { SetValue(defaultValue); } - void SetValue(const CString& value) { currentValue = value; } - CString GetValue() const { return currentValue; } - void Apply() { settingReference = currentValue; } + bool IsDefault() const { + return currentValue == defaultValue; + } + void ResetDefault() { + SetValue(defaultValue); + } + void SetValue(const CString& value) { + currentValue = value; + } + CString GetValue() const { + return currentValue; + } + void Apply() { + settingReference = currentValue; + } }; class CPPageAdvanced : public CPPageBase @@ -148,6 +188,8 @@ class CPPageAdvanced : public CPPageBase AUTO_DOWNLOAD_SCORE_SERIES, DEFAULT_TOOLBAR_SIZE, USE_LEGACY_TOOLBAR, + YDL_MAX_HEIGHT, + YDL_AUDIO_ONLY, }; enum { diff --git a/src/mpc-hc/SettingsDefines.h b/src/mpc-hc/SettingsDefines.h index efe017e66eb..2fb02a1a399 100644 --- a/src/mpc-hc/SettingsDefines.h +++ b/src/mpc-hc/SettingsDefines.h @@ -323,3 +323,6 @@ #define IDS_RS_SANEAR_CROSSFEED_ENABLED _T("CrossfeedEnabled") #define IDS_RS_SANEAR_CROSSFEED_CUTOFF_FREQ _T("CrossfeedCutoffFrequency") #define IDS_RS_SANEAR_CROSSFEED_LEVEL _T("CrossfeedLevel") + +#define IDS_RS_YDL_MAX_HEIGHT _T("YDLMaxHeight") +#define IDS_RS_YDL_AUDIO_ONLY _T("YDLAudioOnly") diff --git a/src/mpc-hc/YoutubeDL.cpp b/src/mpc-hc/YoutubeDL.cpp index 79b1805f3f8..bd2d93a0eb0 100644 --- a/src/mpc-hc/YoutubeDL.cpp +++ b/src/mpc-hc/YoutubeDL.cpp @@ -1,6 +1,7 @@ #include "stdafx.h" #include "YoutubeDL.h" #include "rapidjson/include/rapidjson/document.h" +#include "mplayerc.h" typedef rapidjson::GenericValue> Value; @@ -178,7 +179,7 @@ DWORD WINAPI CYoutubeDLInstance::BuffErrThread(void* ydl_inst) //find highest resolution -void filterVideo(const Value& formats, CString& url) +void filterVideo(const Value& formats, CString& url, int reqheight = 0) { int maxheight = 0; @@ -192,7 +193,7 @@ void filterVideo(const Value& formats, CString& url) if (formats[i].FindMember(_T("height")) != formats[i].MemberEnd() && !formats[i][_T("height")].IsNull()) { curheight = formats[i][_T("height")].GetInt(); } - if (curheight >= maxheight) { + if (curheight >= maxheight && (!reqheight || reqheight >= curheight)) { maxheight = curheight; url = formats[i][_T("url")].GetString(); } @@ -228,6 +229,7 @@ bool CYoutubeDLInstance::GetHttpStreams(CAtlList& videos, CAtlListd[_T("extractor")].GetString(); + auto& s = AfxGetAppSettings(); if (!bIsPlaylist) { names.AddTail(pJSON->d[_T("title")].GetString()); @@ -238,7 +240,7 @@ bool CYoutubeDLInstance::GetHttpStreams(CAtlList& videos, CAtlListd[_T("formats")], url); + filterVideo(pJSON->d[_T("formats")], url, s.iYDLMaxHeight); videos.AddTail(url); //find separate audio stream, if applicable @@ -249,7 +251,7 @@ bool CYoutubeDLInstance::GetHttpStreams(CAtlList& videos, CAtlListd[_T("entries")]; for (rapidjson::SizeType i = 0; i < entries.Size(); i++) { - filterVideo(entries[i][_T("formats")], url); + filterVideo(entries[i][_T("formats")], url, s.iYDLMaxHeight); videos.AddTail(url); names.AddTail(entries[i][_T("title")].GetString()); From ed393015fb050f2b105e71e66409eb17832106ab Mon Sep 17 00:00:00 2001 From: Nicholas Parkanyi Date: Fri, 2 Mar 2018 23:54:20 -0500 Subject: [PATCH 25/26] Use original URL when loading youtube-dl videos from Favorites. --- src/mpc-hc/MainFrm.cpp | 30 ++++++++++++++++++++---------- src/mpc-hc/PlayerPlaylistBar.cpp | 19 ++++++++++--------- src/mpc-hc/PlayerPlaylistBar.h | 6 +++--- src/mpc-hc/Playlist.cpp | 6 ++++-- src/mpc-hc/Playlist.h | 3 ++- 5 files changed, 39 insertions(+), 25 deletions(-) diff --git a/src/mpc-hc/MainFrm.cpp b/src/mpc-hc/MainFrm.cpp index 86a5fb7490c..ad316d461c8 100644 --- a/src/mpc-hc/MainFrm.cpp +++ b/src/mpc-hc/MainFrm.cpp @@ -6973,7 +6973,7 @@ void CMainFrame::OnPlayPlay() strOSD.LoadString(IDS_PLAY_BD); } else { strOSD = GetFileName(); - if (!strOSD.IsEmpty() && !m_wndPlaylistBar.GetCur()->m_bUseLabelAsFilename) { + if (!strOSD.IsEmpty() && !m_wndPlaylistBar.GetCur()->m_bYoutubeDL) { strOSD.TrimRight('/'); strOSD.Replace('\\', '/'); strOSD = strOSD.Mid(strOSD.ReverseFind('/') + 1); @@ -8862,9 +8862,13 @@ void CMainFrame::AddFavorite(bool fDisplayMessage, bool fShowDialog) } else { CPlaylistItem pli; if (m_wndPlaylistBar.GetCur(pli)) { - POSITION pos = pli.m_fns.GetHeadPosition(); - while (pos) { - args.AddTail(pli.m_fns.GetNext(pos)); + if (pli.m_bYoutubeDL) { + args.AddTail(pli.m_ydlSourceURL); + } else { + POSITION pos = pli.m_fns.GetHeadPosition(); + while (pos) { + args.AddTail(pli.m_fns.GetNext(pos)); + } } } } @@ -9058,7 +9062,13 @@ void CMainFrame::PlayFavoriteFile(CString fav) } } - m_wndPlaylistBar.Open(args, false); + SendMessage(WM_COMMAND, ID_FILE_CLOSEMEDIA); + + if (args.GetHead().Left(4) != _T("http") + || !ProcessYoutubeDLURL(args.GetHead(), false)) { + m_wndPlaylistBar.Open(args, false); + } + if (GetPlaybackMode() == PM_FILE && args.GetHead() == m_lastOMD->title) { m_pMS->SetPositions(&rtStart, AM_SEEKING_AbsolutePositioning, nullptr, AM_SEEKING_NoPositioning); OnPlayPlay(); @@ -9079,7 +9089,7 @@ void CMainFrame::OnRecentFile(UINT nID) m_recentFilesMenu.GetMenuString(nID + 2, fn, MF_BYPOSITION); if (fn.Left(4) == _T("http")) { - OnPlayStop(); + SendMessage(WM_COMMAND, ID_FILE_CLOSEMEDIA); if (ProcessYoutubeDLURL(fn, false)) { OpenCurPlaylistItem(); return; @@ -12277,7 +12287,7 @@ void CMainFrame::SendNowPlayingToSkype() if (GetPlaybackMode() == PM_FILE) { CString fn = label; - if (!pli.m_bUseLabelAsFilename && fn.Find(_T("://")) >= 0) { + if (!pli.m_bYoutubeDL && fn.Find(_T("://")) >= 0) { int i = fn.Find('?'); if (i >= 0) { fn = fn.Left(i); @@ -16698,14 +16708,14 @@ CString CMainFrame::GetFileName() { CString path(m_wndPlaylistBar.GetCurFileName()); - if (!m_wndPlaylistBar.GetCur()->m_bUseLabelAsFilename && m_pFSF) { + if (!m_wndPlaylistBar.GetCur()->m_bYoutubeDL && m_pFSF) { CComHeapPtr pFN; if (SUCCEEDED(m_pFSF->GetCurFile(&pFN, nullptr))) { path = pFN; } } - return m_wndPlaylistBar.GetCur()->m_bUseLabelAsFilename ? path : PathUtils::StripPathOrUrl(path); + return m_wndPlaylistBar.GetCur()->m_bYoutubeDL ? path : PathUtils::StripPathOrUrl(path); } CString CMainFrame::GetCaptureTitle() @@ -17060,7 +17070,7 @@ bool CMainFrame::ProcessYoutubeDLURL(CString url, bool append) } m_wndPlaylistBar.Append(filenames, false, nullptr, names.GetAt(names.FindIndex(i)) - + " (" + url + ")"); + + " (" + url + ")", url); } CRecentFileList* mru = &s.MRU; diff --git a/src/mpc-hc/PlayerPlaylistBar.cpp b/src/mpc-hc/PlayerPlaylistBar.cpp index a4ccd18f4ed..f1313448141 100644 --- a/src/mpc-hc/PlayerPlaylistBar.cpp +++ b/src/mpc-hc/PlayerPlaylistBar.cpp @@ -153,7 +153,7 @@ void CPlayerPlaylistBar::AddItem(CString fn, CAtlList* subs) AddItem(sl, subs); } -void CPlayerPlaylistBar::AddItem(CAtlList& fns, CAtlList* subs, CString label) +void CPlayerPlaylistBar::AddItem(CAtlList& fns, CAtlList* subs, CString label, CString ydl_src) { CPlaylistItem pli; @@ -180,9 +180,10 @@ void CPlayerPlaylistBar::AddItem(CAtlList& fns, CAtlList* subs } pli.AutoLoadFiles(); - if (!label.IsEmpty()) { + if (!ydl_src.IsEmpty()) { pli.m_label = label; - pli.m_bUseLabelAsFilename = true; + pli.m_ydlSourceURL = ydl_src; + pli.m_bYoutubeDL = true; } m_pl.AddTail(pli); @@ -274,7 +275,7 @@ void CPlayerPlaylistBar::ResolveLinkFiles(CAtlList& fns) } } -void CPlayerPlaylistBar::ParsePlayList(CAtlList& fns, CAtlList* subs, CString label) +void CPlayerPlaylistBar::ParsePlayList(CAtlList& fns, CAtlList* subs, CString label, CString ydl_src) { if (fns.IsEmpty()) { return; @@ -318,7 +319,7 @@ void CPlayerPlaylistBar::ParsePlayList(CAtlList& fns, CAtlList #endif } - AddItem(fns, subs, label); + AddItem(fns, subs, label, ydl_src); } static CString CombinePath(CPath p, CString fn) @@ -504,7 +505,7 @@ void CPlayerPlaylistBar::Open(CAtlList& fns, bool fMulti, CAtlList& fns, bool fMulti, CAtlList* subs, CString label) +void CPlayerPlaylistBar::Append(CAtlList& fns, bool fMulti, CAtlList* subs, CString label, CString ydl_src) { POSITION posFirstAdded = m_pl.GetTailPosition(); int iFirstAdded = (int)m_pl.GetCount(); @@ -516,7 +517,7 @@ void CPlayerPlaylistBar::Append(CAtlList& fns, bool fMulti, CAtlListm_bUseLabelAsFilename) { + if (pli && pli->m_bYoutubeDL) { fn = pli->m_label; } else if (pli && !pli->m_fns.IsEmpty()) { fn = pli->m_fns.GetHead(); @@ -814,7 +815,7 @@ OpenMediaData* CPlayerPlaylistBar::GetCurOMD(REFERENCE_TIME rtStart) p->fns.AddTailList(&pli->m_fns); p->subs.AddTailList(&pli->m_subs); p->rtStart = rtStart; - p->bAddToRecent = !pli->m_bUseLabelAsFilename; + p->bAddToRecent = !pli->m_bYoutubeDL; return p; } } diff --git a/src/mpc-hc/PlayerPlaylistBar.h b/src/mpc-hc/PlayerPlaylistBar.h index a868bfc29ed..b44fa3a7a5c 100644 --- a/src/mpc-hc/PlayerPlaylistBar.h +++ b/src/mpc-hc/PlayerPlaylistBar.h @@ -56,9 +56,9 @@ class CPlayerPlaylistBar : public CPlayerBar, public CDropClient void ResizeListColumn(); void AddItem(CString fn, CAtlList* subs); - void AddItem(CAtlList& fns, CAtlList* subs, CString label = _T("")); + void AddItem(CAtlList& fns, CAtlList* subs, CString label = _T(""), CString ydl_src = _T("")); void ParsePlayList(CString fn, CAtlList* subs); - void ParsePlayList(CAtlList& fns, CAtlList* subs, CString label = _T("")); + void ParsePlayList(CAtlList& fns, CAtlList* subs, CString label = _T(""), CString ydl_src = _T("")); void ResolveLinkFiles(CAtlList& fns); bool ParseBDMVPlayList(CString fn); @@ -121,7 +121,7 @@ class CPlayerPlaylistBar : public CPlayerBar, public CDropClient bool Empty(); void Open(CAtlList& fns, bool fMulti, CAtlList* subs = nullptr); - void Append(CAtlList& fns, bool fMulti, CAtlList* subs = nullptr, CString label = _T("")); + void Append(CAtlList& fns, bool fMulti, CAtlList* subs = nullptr, CString label = _T(""), CString ydl_src = _T("")); void Open(CStringW vdn, CStringW adn, int vinput, int vchannel, int ainput); void Append(CStringW vdn, CStringW adn, int vinput, int vchannel, int ainput); diff --git a/src/mpc-hc/Playlist.cpp b/src/mpc-hc/Playlist.cpp index 60d94b04018..d8f8d32c9ed 100644 --- a/src/mpc-hc/Playlist.cpp +++ b/src/mpc-hc/Playlist.cpp @@ -41,7 +41,8 @@ CPlaylistItem::CPlaylistItem() , m_ainput(-1) , m_country(0) , m_fInvalid(false) - , m_bUseLabelAsFilename(false) + , m_bYoutubeDL(false) + , m_ydlSourceURL(_T("")) { m_id = m_globalid++; } @@ -73,7 +74,8 @@ CPlaylistItem& CPlaylistItem::operator=(const CPlaylistItem& pli) m_country = pli.m_country; m_posNextShuffle = pli.m_posNextShuffle; m_posPrevShuffle = pli.m_posPrevShuffle; - m_bUseLabelAsFilename = pli.m_bUseLabelAsFilename; + m_bYoutubeDL = pli.m_bYoutubeDL; + m_ydlSourceURL = pli.m_ydlSourceURL; } return *this; } diff --git a/src/mpc-hc/Playlist.h b/src/mpc-hc/Playlist.h index 9a570c6b711..7c2a6e0d000 100644 --- a/src/mpc-hc/Playlist.h +++ b/src/mpc-hc/Playlist.h @@ -35,7 +35,8 @@ class CPlaylistItem public: UINT m_id; CString m_label; - bool m_bUseLabelAsFilename; + bool m_bYoutubeDL; + CString m_ydlSourceURL; CAtlList m_fns; CAtlList m_subs; enum type_t { file, device } m_type; From 6ef0b8b3c05ee1934ecce1295529341bd6a11947 Mon Sep 17 00:00:00 2001 From: Nicholas Parkanyi Date: Wed, 4 Apr 2018 22:08:12 -0400 Subject: [PATCH 26/26] obey youtube-dl audio-only flag on videos with split audio/video streams; added copyright header --- src/mpc-hc/MainFrm.cpp | 9 +++++++-- src/mpc-hc/YoutubeDL.cpp | 19 +++++++++++++++++++ src/mpc-hc/YoutubeDL.h | 19 +++++++++++++++++++ 3 files changed, 45 insertions(+), 2 deletions(-) diff --git a/src/mpc-hc/MainFrm.cpp b/src/mpc-hc/MainFrm.cpp index ad316d461c8..a1e9c38eee2 100644 --- a/src/mpc-hc/MainFrm.cpp +++ b/src/mpc-hc/MainFrm.cpp @@ -1,6 +1,6 @@ /* * (C) 2003-2006 Gabest - * (C) 2006-2017 see Authors.txt + * (C) 2006-2018 see Authors.txt * * This file is part of MPC-HC. * @@ -17064,7 +17064,12 @@ bool CMainFrame::ProcessYoutubeDLURL(CString url, bool append) } for (unsigned int i = 0; i < vstreams.GetCount(); i++) { filenames.RemoveAll(); - filenames.AddTail(vstreams.GetAt(vstreams.FindIndex(i))); + + //only respect the Audio Only flag for sources that actually have separate audio streams (i.e. youtube) + if (astreams.IsEmpty() || !s.bYDLAudioOnly) { + filenames.AddTail(vstreams.GetAt(vstreams.FindIndex(i))); + } + if (!astreams.IsEmpty()) { filenames.AddTail(astreams.GetAt(astreams.FindIndex(i))); } diff --git a/src/mpc-hc/YoutubeDL.cpp b/src/mpc-hc/YoutubeDL.cpp index bd2d93a0eb0..26d5e603961 100644 --- a/src/mpc-hc/YoutubeDL.cpp +++ b/src/mpc-hc/YoutubeDL.cpp @@ -1,3 +1,22 @@ +/* +* (C) 2018 Nicholas Parkanyi +* +* This file is part of MPC-HC. +* +* MPC-HC is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 3 of the License, or +* (at your option) any later version. +* +* MPC-HC is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see . +* +*/ #include "stdafx.h" #include "YoutubeDL.h" #include "rapidjson/include/rapidjson/document.h" diff --git a/src/mpc-hc/YoutubeDL.h b/src/mpc-hc/YoutubeDL.h index d326b36666a..15dd36cf407 100644 --- a/src/mpc-hc/YoutubeDL.h +++ b/src/mpc-hc/YoutubeDL.h @@ -1,3 +1,22 @@ +/* +* (C) 2018 Nicholas Parkanyi +* +* This file is part of MPC-HC. +* +* MPC-HC is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 3 of the License, or +* (at your option) any later version. +* +* MPC-HC is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see . +* +*/ #pragma once #include "stdafx.h"