mirror of
https://github.com/yt-dlp/yt-dlp.git
synced 2026-08-08 21:28:38 +03:00
Compare commits
8
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6fd35a1101 | ||
|
|
f5b1bca913 | ||
|
|
d9eebbc747 | ||
|
|
c3e6ffba53 | ||
|
|
8c04f0be96 | ||
|
|
ab8e5e516f | ||
|
|
62d80ba17c | ||
|
|
e8273c86a3 |
@@ -21,7 +21,7 @@ assignees: ''
|
|||||||
|
|
||||||
<!--
|
<!--
|
||||||
Carefully read and work through this check list in order to prevent the most common mistakes and misuse of youtube-dlc:
|
Carefully read and work through this check list in order to prevent the most common mistakes and misuse of youtube-dlc:
|
||||||
- First of, make sure you are using the latest version of youtube-dlc. Run `youtube-dlc --version` and ensure your version is 2021.01.07-1. If it's not, see https://github.com/pukkandan/yt-dlc on how to update. Issues with outdated version will be REJECTED.
|
- First of, make sure you are using the latest version of youtube-dlc. Run `youtube-dlc --version` and ensure your version is 2021.01.08. If it's not, see https://github.com/pukkandan/yt-dlc on how to update. Issues with outdated version will be REJECTED.
|
||||||
- Make sure that all provided video/audio/playlist URLs (if any) are alive and playable in a browser.
|
- Make sure that all provided video/audio/playlist URLs (if any) are alive and playable in a browser.
|
||||||
- Make sure that all URLs and arguments with special characters are properly quoted or escaped as explained in https://github.com/pukkandan/yt-dlc.
|
- Make sure that all URLs and arguments with special characters are properly quoted or escaped as explained in https://github.com/pukkandan/yt-dlc.
|
||||||
- Search the bugtracker for similar issues: https://github.com/pukkandan/yt-dlc. DO NOT post duplicates.
|
- Search the bugtracker for similar issues: https://github.com/pukkandan/yt-dlc. DO NOT post duplicates.
|
||||||
@@ -29,7 +29,7 @@ Carefully read and work through this check list in order to prevent the most com
|
|||||||
-->
|
-->
|
||||||
|
|
||||||
- [ ] I'm reporting a broken site support
|
- [ ] I'm reporting a broken site support
|
||||||
- [ ] I've verified that I'm running youtube-dlc version **2021.01.07-1**
|
- [ ] I've verified that I'm running youtube-dlc version **2021.01.08**
|
||||||
- [ ] I've checked that all provided URLs are alive and playable in a browser
|
- [ ] I've checked that all provided URLs are alive and playable in a browser
|
||||||
- [ ] I've checked that all URLs and arguments with special characters are properly quoted or escaped
|
- [ ] I've checked that all URLs and arguments with special characters are properly quoted or escaped
|
||||||
- [ ] I've searched the bugtracker for similar issues including closed ones
|
- [ ] I've searched the bugtracker for similar issues including closed ones
|
||||||
@@ -44,7 +44,7 @@ Add the `-v` flag to your command line you run youtube-dlc with (`youtube-dlc -v
|
|||||||
[debug] User config: []
|
[debug] User config: []
|
||||||
[debug] Command-line args: [u'-v', u'http://www.youtube.com/watch?v=BaW_jenozKcj']
|
[debug] Command-line args: [u'-v', u'http://www.youtube.com/watch?v=BaW_jenozKcj']
|
||||||
[debug] Encodings: locale cp1251, fs mbcs, out cp866, pref cp1251
|
[debug] Encodings: locale cp1251, fs mbcs, out cp866, pref cp1251
|
||||||
[debug] youtube-dlc version 2021.01.07-1
|
[debug] youtube-dlc version 2021.01.08
|
||||||
[debug] Python version 2.7.11 - Windows-2003Server-5.2.3790-SP2
|
[debug] Python version 2.7.11 - Windows-2003Server-5.2.3790-SP2
|
||||||
[debug] exe versions: ffmpeg N-75573-g1d0487f, ffprobe N-75573-g1d0487f, rtmpdump 2.4
|
[debug] exe versions: ffmpeg N-75573-g1d0487f, ffprobe N-75573-g1d0487f, rtmpdump 2.4
|
||||||
[debug] Proxy map: {}
|
[debug] Proxy map: {}
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ assignees: ''
|
|||||||
|
|
||||||
<!--
|
<!--
|
||||||
Carefully read and work through this check list in order to prevent the most common mistakes and misuse of youtube-dlc:
|
Carefully read and work through this check list in order to prevent the most common mistakes and misuse of youtube-dlc:
|
||||||
- First of, make sure you are using the latest version of youtube-dlc. Run `youtube-dlc --version` and ensure your version is 2021.01.07-1. If it's not, see https://github.com/pukkandan/yt-dlc on how to update. Issues with outdated version will be REJECTED.
|
- First of, make sure you are using the latest version of youtube-dlc. Run `youtube-dlc --version` and ensure your version is 2021.01.08. If it's not, see https://github.com/pukkandan/yt-dlc on how to update. Issues with outdated version will be REJECTED.
|
||||||
- Make sure that all provided video/audio/playlist URLs (if any) are alive and playable in a browser.
|
- Make sure that all provided video/audio/playlist URLs (if any) are alive and playable in a browser.
|
||||||
- Make sure that site you are requesting is not dedicated to copyright infringement, see https://github.com/pukkandan/yt-dlc. youtube-dlc does not support such sites. In order for site support request to be accepted all provided example URLs should not violate any copyrights.
|
- Make sure that site you are requesting is not dedicated to copyright infringement, see https://github.com/pukkandan/yt-dlc. youtube-dlc does not support such sites. In order for site support request to be accepted all provided example URLs should not violate any copyrights.
|
||||||
- Search the bugtracker for similar site support requests: https://github.com/pukkandan/yt-dlc. DO NOT post duplicates.
|
- Search the bugtracker for similar site support requests: https://github.com/pukkandan/yt-dlc. DO NOT post duplicates.
|
||||||
@@ -29,7 +29,7 @@ Carefully read and work through this check list in order to prevent the most com
|
|||||||
-->
|
-->
|
||||||
|
|
||||||
- [ ] I'm reporting a new site support request
|
- [ ] I'm reporting a new site support request
|
||||||
- [ ] I've verified that I'm running youtube-dlc version **2021.01.07-1**
|
- [ ] I've verified that I'm running youtube-dlc version **2021.01.08**
|
||||||
- [ ] I've checked that all provided URLs are alive and playable in a browser
|
- [ ] I've checked that all provided URLs are alive and playable in a browser
|
||||||
- [ ] I've checked that none of provided URLs violate any copyrights
|
- [ ] I've checked that none of provided URLs violate any copyrights
|
||||||
- [ ] I've searched the bugtracker for similar site support requests including closed ones
|
- [ ] I've searched the bugtracker for similar site support requests including closed ones
|
||||||
|
|||||||
@@ -21,13 +21,13 @@ assignees: ''
|
|||||||
|
|
||||||
<!--
|
<!--
|
||||||
Carefully read and work through this check list in order to prevent the most common mistakes and misuse of youtube-dlc:
|
Carefully read and work through this check list in order to prevent the most common mistakes and misuse of youtube-dlc:
|
||||||
- First of, make sure you are using the latest version of youtube-dlc. Run `youtube-dlc --version` and ensure your version is 2021.01.07-1. If it's not, see https://github.com/pukkandan/yt-dlc on how to update. Issues with outdated version will be REJECTED.
|
- First of, make sure you are using the latest version of youtube-dlc. Run `youtube-dlc --version` and ensure your version is 2021.01.08. If it's not, see https://github.com/pukkandan/yt-dlc on how to update. Issues with outdated version will be REJECTED.
|
||||||
- Search the bugtracker for similar site feature requests: https://github.com/pukkandan/yt-dlc. DO NOT post duplicates.
|
- Search the bugtracker for similar site feature requests: https://github.com/pukkandan/yt-dlc. DO NOT post duplicates.
|
||||||
- Finally, put x into all relevant boxes like this [x] (Dont forget to delete the empty space)
|
- Finally, put x into all relevant boxes like this [x] (Dont forget to delete the empty space)
|
||||||
-->
|
-->
|
||||||
|
|
||||||
- [ ] I'm reporting a site feature request
|
- [ ] I'm reporting a site feature request
|
||||||
- [ ] I've verified that I'm running youtube-dlc version **2021.01.07-1**
|
- [ ] I've verified that I'm running youtube-dlc version **2021.01.08**
|
||||||
- [ ] I've searched the bugtracker for similar site feature requests including closed ones
|
- [ ] I've searched the bugtracker for similar site feature requests including closed ones
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ assignees: ''
|
|||||||
|
|
||||||
<!--
|
<!--
|
||||||
Carefully read and work through this check list in order to prevent the most common mistakes and misuse of youtube-dlc:
|
Carefully read and work through this check list in order to prevent the most common mistakes and misuse of youtube-dlc:
|
||||||
- First of, make sure you are using the latest version of youtube-dlc. Run `youtube-dlc --version` and ensure your version is 2021.01.07-1. If it's not, see https://github.com/pukkandan/yt-dlc on how to update. Issues with outdated version will be REJECTED.
|
- First of, make sure you are using the latest version of youtube-dlc. Run `youtube-dlc --version` and ensure your version is 2021.01.08. If it's not, see https://github.com/pukkandan/yt-dlc on how to update. Issues with outdated version will be REJECTED.
|
||||||
- Make sure that all provided video/audio/playlist URLs (if any) are alive and playable in a browser.
|
- Make sure that all provided video/audio/playlist URLs (if any) are alive and playable in a browser.
|
||||||
- Make sure that all URLs and arguments with special characters are properly quoted or escaped as explained in https://github.com/pukkandan/yt-dlc.
|
- Make sure that all URLs and arguments with special characters are properly quoted or escaped as explained in https://github.com/pukkandan/yt-dlc.
|
||||||
- Search the bugtracker for similar issues: https://github.com/pukkandan/yt-dlc. DO NOT post duplicates.
|
- Search the bugtracker for similar issues: https://github.com/pukkandan/yt-dlc. DO NOT post duplicates.
|
||||||
@@ -30,7 +30,7 @@ Carefully read and work through this check list in order to prevent the most com
|
|||||||
-->
|
-->
|
||||||
|
|
||||||
- [ ] I'm reporting a broken site support issue
|
- [ ] I'm reporting a broken site support issue
|
||||||
- [ ] I've verified that I'm running youtube-dlc version **2021.01.07-1**
|
- [ ] I've verified that I'm running youtube-dlc version **2021.01.08**
|
||||||
- [ ] I've checked that all provided URLs are alive and playable in a browser
|
- [ ] I've checked that all provided URLs are alive and playable in a browser
|
||||||
- [ ] I've checked that all URLs and arguments with special characters are properly quoted or escaped
|
- [ ] I've checked that all URLs and arguments with special characters are properly quoted or escaped
|
||||||
- [ ] I've searched the bugtracker for similar bug reports including closed ones
|
- [ ] I've searched the bugtracker for similar bug reports including closed ones
|
||||||
@@ -46,7 +46,7 @@ Add the `-v` flag to your command line you run youtube-dlc with (`youtube-dlc -v
|
|||||||
[debug] User config: []
|
[debug] User config: []
|
||||||
[debug] Command-line args: [u'-v', u'http://www.youtube.com/watch?v=BaW_jenozKcj']
|
[debug] Command-line args: [u'-v', u'http://www.youtube.com/watch?v=BaW_jenozKcj']
|
||||||
[debug] Encodings: locale cp1251, fs mbcs, out cp866, pref cp1251
|
[debug] Encodings: locale cp1251, fs mbcs, out cp866, pref cp1251
|
||||||
[debug] youtube-dlc version 2021.01.07-1
|
[debug] youtube-dlc version 2021.01.08
|
||||||
[debug] Python version 2.7.11 - Windows-2003Server-5.2.3790-SP2
|
[debug] Python version 2.7.11 - Windows-2003Server-5.2.3790-SP2
|
||||||
[debug] exe versions: ffmpeg N-75573-g1d0487f, ffprobe N-75573-g1d0487f, rtmpdump 2.4
|
[debug] exe versions: ffmpeg N-75573-g1d0487f, ffprobe N-75573-g1d0487f, rtmpdump 2.4
|
||||||
[debug] Proxy map: {}
|
[debug] Proxy map: {}
|
||||||
|
|||||||
@@ -21,13 +21,13 @@ assignees: ''
|
|||||||
|
|
||||||
<!--
|
<!--
|
||||||
Carefully read and work through this check list in order to prevent the most common mistakes and misuse of youtube-dlc:
|
Carefully read and work through this check list in order to prevent the most common mistakes and misuse of youtube-dlc:
|
||||||
- First of, make sure you are using the latest version of youtube-dlc. Run `youtube-dlc --version` and ensure your version is 2021.01.07-1. If it's not, see https://github.com/pukkandan/yt-dlc on how to update. Issues with outdated version will be REJECTED.
|
- First of, make sure you are using the latest version of youtube-dlc. Run `youtube-dlc --version` and ensure your version is 2021.01.08. If it's not, see https://github.com/pukkandan/yt-dlc on how to update. Issues with outdated version will be REJECTED.
|
||||||
- Search the bugtracker for similar feature requests: https://github.com/pukkandan/yt-dlc. DO NOT post duplicates.
|
- Search the bugtracker for similar feature requests: https://github.com/pukkandan/yt-dlc. DO NOT post duplicates.
|
||||||
- Finally, put x into all relevant boxes like this [x] (Dont forget to delete the empty space)
|
- Finally, put x into all relevant boxes like this [x] (Dont forget to delete the empty space)
|
||||||
-->
|
-->
|
||||||
|
|
||||||
- [ ] I'm reporting a feature request
|
- [ ] I'm reporting a feature request
|
||||||
- [ ] I've verified that I'm running youtube-dlc version **2021.01.07-1**
|
- [ ] I've verified that I'm running youtube-dlc version **2021.01.08**
|
||||||
- [ ] I've searched the bugtracker for similar feature requests including closed ones
|
- [ ] I've searched the bugtracker for similar feature requests including closed ones
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -50,7 +50,8 @@ offlinetest: codetest
|
|||||||
--exclude test_subtitles.py \
|
--exclude test_subtitles.py \
|
||||||
--exclude test_write_annotations.py \
|
--exclude test_write_annotations.py \
|
||||||
--exclude test_youtube_lists.py \
|
--exclude test_youtube_lists.py \
|
||||||
--exclude test_youtube_signature.py
|
--exclude test_youtube_signature.py \
|
||||||
|
--exclude test_post_hooks.py
|
||||||
|
|
||||||
tar: youtube-dlc.tar.gz
|
tar: youtube-dlc.tar.gz
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
[](https://github.com/pukkandan/yt-dlc/releases/latest)
|
[](https://github.com/pukkandan/yt-dlc/releases/latest)
|
||||||
[](https://github.com/pukkandan/yt-dlc/blob/master/LICENSE)
|
[](https://github.com/pukkandan/yt-dlc/blob/master/LICENSE)
|
||||||
[](https://github.com/pukkandan/yt-dlc/actions?query=workflow%3ACore)
|
[](https://github.com/pukkandan/yt-dlc/actions?query=workflow%3ACore)
|
||||||
[](https://github.com/pukkandan/yt-dlc/actions?query=workflow%3AFull)
|
[](https://github.com/pukkandan/yt-dlc/actions?query=workflow%3AFull)
|
||||||
@@ -48,13 +48,13 @@ The major new features are:
|
|||||||
|
|
||||||
* **[SponSkrub Integration](#sponSkrub-options-sponsorblock)** - You can use [SponSkrub](https://github.com/faissaloo/SponSkrub) to mark/remove sponsor sections in youtube videos by utilizing the [SponsorBlock](https://sponsor.ajay.app) API
|
* **[SponSkrub Integration](#sponSkrub-options-sponsorblock)** - You can use [SponSkrub](https://github.com/faissaloo/SponSkrub) to mark/remove sponsor sections in youtube videos by utilizing the [SponsorBlock](https://sponsor.ajay.app) API
|
||||||
|
|
||||||
* **[Format Sorting](#sorting-format)** - The default format sorting options have been changed so that higher resolution and better codecs will be now prefered instead of simply using larger bitrate. Furthermore, the user can now specify the sort order if they want. This allows for much easier format selection that what is possible by simply using `--format` ([examples](#format-selection-examples))
|
* **[Format Sorting](#sorting-format)** - The default format sorting options have been changed so that higher resolution and better codecs will be now prefered instead of simply using larger bitrate. Furthermore, you can now specify the sort order using `-S`. This allows for much easier format selection that what is possible by simply using `--format` ([examples](#format-selection-examples))
|
||||||
|
|
||||||
* Merged with youtube-dl **v2020.01.08** - You get the new features and patches of [youtube-dl](https://github.com/ytdl-org/youtube-dl) in addition to all the features of [youtube-dlc](https://github.com/blackjack4494)
|
* Merged with youtube-dl **v2020.01.08** - You get the new features and patches of [youtube-dl](https://github.com/ytdl-org/youtube-dl) in addition to all the features of [youtube-dlc](https://github.com/blackjack4494)
|
||||||
|
|
||||||
* **New options** - `--list-formats-as-table`, `--write-link`, `--force-download-archive` etc
|
* **New options** - `--list-formats-as-table`, `--write-link`, `--force-download-archive` etc
|
||||||
|
|
||||||
and many other features and patches. See [changelog](changelog.md) or [commits](https://github.com/pukkandan/yt-dlc/commits) for the full list of changes
|
and many other features and patches. See [changelog](Changelog.md) or [commits](https://github.com/pukkandan/yt-dlc/commits) for the full list of changes
|
||||||
|
|
||||||
|
|
||||||
# INSTALLATION
|
# INSTALLATION
|
||||||
@@ -447,8 +447,8 @@ Then simply type this
|
|||||||
--no-audio-multistreams Only one audio stream is downloaded for
|
--no-audio-multistreams Only one audio stream is downloaded for
|
||||||
each output file (default)
|
each output file (default)
|
||||||
--all-formats Download all available video formats
|
--all-formats Download all available video formats
|
||||||
--prefer-free-formats Prefer free video formats unless a specific
|
--prefer-free-formats Prefer free video formats over non-free
|
||||||
one is requested
|
formats of same quality
|
||||||
-F, --list-formats List all available formats of requested
|
-F, --list-formats List all available formats of requested
|
||||||
videos
|
videos
|
||||||
--list-formats-as-table Present the output of -F in a more tabular
|
--list-formats-as-table Present the output of -F in a more tabular
|
||||||
@@ -919,9 +919,17 @@ $ youtube-dlc -f 'bv*+ba/b'
|
|||||||
# Same as above
|
# Same as above
|
||||||
$ youtube-dlc
|
$ youtube-dlc
|
||||||
|
|
||||||
|
# Download the best video-only format and the best audio-only format without merging them
|
||||||
|
# For this case, an output template should be used since
|
||||||
|
# by default, bestvideo and bestaudio will have the same file name.
|
||||||
|
$ youtube-dlc -f 'bv,ba' -o '%(title)s.f%(format_id)s.%(ext)s'
|
||||||
|
|
||||||
|
|
||||||
# Download the worst video available
|
|
||||||
|
# The following examples show the old method (without -S) of format selection
|
||||||
|
# and how to use -S to achieve a similar but better result
|
||||||
|
|
||||||
|
# Download the worst video available (old method)
|
||||||
$ youtube-dlc -f 'wv*+wa/w'
|
$ youtube-dlc -f 'wv*+wa/w'
|
||||||
|
|
||||||
# Download the best video available but with the smallest resolution
|
# Download the best video available but with the smallest resolution
|
||||||
@@ -980,13 +988,6 @@ $ youtube-dlc -S 'protocol'
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
# Download the best video-only format and the best audio-only format without merging them
|
|
||||||
# For this case, an output template should be used since
|
|
||||||
# by default, bestvideo and bestaudio will have the same file name.
|
|
||||||
$ youtube-dlc -f 'bv,ba' -o '%(title)s.f%(format_id)s.%(ext)s'
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# Download the best video with h264 codec, or the best video if there is no such video
|
# Download the best video with h264 codec, or the best video if there is no such video
|
||||||
$ youtube-dlc -f '(bv*+ba/b)[vcodec^=avc1] / (bv*+ba/b)'
|
$ youtube-dlc -f '(bv*+ba/b)[vcodec^=avc1] / (bv*+ba/b)'
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
@echo off
|
@echo off
|
||||||
|
|
||||||
rem Keep this list in sync with the `offlinetest` target in Makefile
|
rem Keep this list in sync with the `offlinetest` target in Makefile
|
||||||
set DOWNLOAD_TESTS="age_restriction^|download^|iqiyi_sdk_interpreter^|socks^|subtitles^|write_annotations^|youtube_lists^|youtube_signature"
|
set DOWNLOAD_TESTS="age_restriction^|download^|iqiyi_sdk_interpreter^|socks^|subtitles^|write_annotations^|youtube_lists^|youtube_signature^|post_hooks"
|
||||||
|
|
||||||
if "%YTDL_TEST_SET%" == "core" (
|
if "%YTDL_TEST_SET%" == "core" (
|
||||||
set test_set="-I test_("%DOWNLOAD_TESTS%")\.py"
|
set test_set="-I test_("%DOWNLOAD_TESTS%")\.py"
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
# Keep this list in sync with the `offlinetest` target in Makefile
|
# Keep this list in sync with the `offlinetest` target in Makefile
|
||||||
DOWNLOAD_TESTS="age_restriction|download|iqiyi_sdk_interpreter|socks|subtitles|write_annotations|youtube_lists|youtube_signature"
|
DOWNLOAD_TESTS="age_restriction|download|iqiyi_sdk_interpreter|socks|subtitles|write_annotations|youtube_lists|youtube_signature|post_hooks"
|
||||||
|
|
||||||
test_set=""
|
test_set=""
|
||||||
multiprocess_args=""
|
multiprocess_args=""
|
||||||
|
|||||||
@@ -0,0 +1,68 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
import unittest
|
||||||
|
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
||||||
|
|
||||||
|
from test.helper import get_params, try_rm
|
||||||
|
import youtube_dl.YoutubeDL
|
||||||
|
from youtube_dl.utils import DownloadError
|
||||||
|
|
||||||
|
|
||||||
|
class YoutubeDL(youtube_dl.YoutubeDL):
|
||||||
|
def __init__(self, *args, **kwargs):
|
||||||
|
super(YoutubeDL, self).__init__(*args, **kwargs)
|
||||||
|
self.to_stderr = self.to_screen
|
||||||
|
|
||||||
|
|
||||||
|
TEST_ID = 'gr51aVj-mLg'
|
||||||
|
EXPECTED_NAME = 'gr51aVj-mLg'
|
||||||
|
|
||||||
|
|
||||||
|
class TestPostHooks(unittest.TestCase):
|
||||||
|
def setUp(self):
|
||||||
|
self.stored_name_1 = None
|
||||||
|
self.stored_name_2 = None
|
||||||
|
self.params = get_params({
|
||||||
|
'skip_download': False,
|
||||||
|
'writeinfojson': False,
|
||||||
|
'quiet': True,
|
||||||
|
'verbose': False,
|
||||||
|
'cachedir': False,
|
||||||
|
})
|
||||||
|
self.files = []
|
||||||
|
|
||||||
|
def test_post_hooks(self):
|
||||||
|
self.params['post_hooks'] = [self.hook_one, self.hook_two]
|
||||||
|
ydl = YoutubeDL(self.params)
|
||||||
|
ydl.download([TEST_ID])
|
||||||
|
self.assertEqual(self.stored_name_1, EXPECTED_NAME, 'Not the expected name from hook 1')
|
||||||
|
self.assertEqual(self.stored_name_2, EXPECTED_NAME, 'Not the expected name from hook 2')
|
||||||
|
|
||||||
|
def test_post_hook_exception(self):
|
||||||
|
self.params['post_hooks'] = [self.hook_three]
|
||||||
|
ydl = YoutubeDL(self.params)
|
||||||
|
self.assertRaises(DownloadError, ydl.download, [TEST_ID])
|
||||||
|
|
||||||
|
def hook_one(self, filename):
|
||||||
|
self.stored_name_1, _ = os.path.splitext(os.path.basename(filename))
|
||||||
|
self.files.append(filename)
|
||||||
|
|
||||||
|
def hook_two(self, filename):
|
||||||
|
self.stored_name_2, _ = os.path.splitext(os.path.basename(filename))
|
||||||
|
self.files.append(filename)
|
||||||
|
|
||||||
|
def hook_three(self, filename):
|
||||||
|
self.files.append(filename)
|
||||||
|
raise Exception('Test exception for \'%s\'' % filename)
|
||||||
|
|
||||||
|
def tearDown(self):
|
||||||
|
for f in self.files:
|
||||||
|
try_rm(f)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
unittest.main()
|
||||||
@@ -99,6 +99,7 @@ from .utils import (
|
|||||||
YoutubeDLCookieProcessor,
|
YoutubeDLCookieProcessor,
|
||||||
YoutubeDLHandler,
|
YoutubeDLHandler,
|
||||||
YoutubeDLRedirectHandler,
|
YoutubeDLRedirectHandler,
|
||||||
|
process_communicate_or_kill,
|
||||||
)
|
)
|
||||||
from .cache import Cache
|
from .cache import Cache
|
||||||
from .extractor import get_info_extractor, gen_extractor_classes, _LAZY_LOADER
|
from .extractor import get_info_extractor, gen_extractor_classes, _LAZY_LOADER
|
||||||
@@ -252,6 +253,9 @@ class YoutubeDL(object):
|
|||||||
youtube_dlc/postprocessor/__init__.py for a list.
|
youtube_dlc/postprocessor/__init__.py for a list.
|
||||||
as well as any further keyword arguments for the
|
as well as any further keyword arguments for the
|
||||||
postprocessor.
|
postprocessor.
|
||||||
|
post_hooks: A list of functions that get called as the final step
|
||||||
|
for each video file, after all postprocessors have been
|
||||||
|
called. The filename will be passed as the only argument.
|
||||||
progress_hooks: A list of functions that get called on download
|
progress_hooks: A list of functions that get called on download
|
||||||
progress, with a dictionary with the entries
|
progress, with a dictionary with the entries
|
||||||
* status: One of "downloading", "error", or "finished".
|
* status: One of "downloading", "error", or "finished".
|
||||||
@@ -369,6 +373,7 @@ class YoutubeDL(object):
|
|||||||
self._ies = []
|
self._ies = []
|
||||||
self._ies_instances = {}
|
self._ies_instances = {}
|
||||||
self._pps = []
|
self._pps = []
|
||||||
|
self._post_hooks = []
|
||||||
self._progress_hooks = []
|
self._progress_hooks = []
|
||||||
self._download_retcode = 0
|
self._download_retcode = 0
|
||||||
self._num_downloads = 0
|
self._num_downloads = 0
|
||||||
@@ -472,6 +477,9 @@ class YoutubeDL(object):
|
|||||||
pp = pp_class(self, **compat_kwargs(pp_def))
|
pp = pp_class(self, **compat_kwargs(pp_def))
|
||||||
self.add_post_processor(pp)
|
self.add_post_processor(pp)
|
||||||
|
|
||||||
|
for ph in self.params.get('post_hooks', []):
|
||||||
|
self.add_post_hook(ph)
|
||||||
|
|
||||||
for ph in self.params.get('progress_hooks', []):
|
for ph in self.params.get('progress_hooks', []):
|
||||||
self.add_progress_hook(ph)
|
self.add_progress_hook(ph)
|
||||||
|
|
||||||
@@ -524,6 +532,10 @@ class YoutubeDL(object):
|
|||||||
self._pps.append(pp)
|
self._pps.append(pp)
|
||||||
pp.set_downloader(self)
|
pp.set_downloader(self)
|
||||||
|
|
||||||
|
def add_post_hook(self, ph):
|
||||||
|
"""Add the post hook"""
|
||||||
|
self._post_hooks.append(ph)
|
||||||
|
|
||||||
def add_progress_hook(self, ph):
|
def add_progress_hook(self, ph):
|
||||||
"""Add the progress hook (currently only for the file downloader)"""
|
"""Add the progress hook (currently only for the file downloader)"""
|
||||||
self._progress_hooks.append(ph)
|
self._progress_hooks.append(ph)
|
||||||
@@ -578,7 +590,7 @@ class YoutubeDL(object):
|
|||||||
# already of type unicode()
|
# already of type unicode()
|
||||||
ctypes.windll.kernel32.SetConsoleTitleW(ctypes.c_wchar_p(message))
|
ctypes.windll.kernel32.SetConsoleTitleW(ctypes.c_wchar_p(message))
|
||||||
elif 'TERM' in os.environ:
|
elif 'TERM' in os.environ:
|
||||||
self._write_string('\033]0;%s\007' % message, self._screen_file)
|
self._write_string('\033[0;%s\007' % message, self._screen_file)
|
||||||
|
|
||||||
def save_console_title(self):
|
def save_console_title(self):
|
||||||
if not self.params.get('consoletitle', False):
|
if not self.params.get('consoletitle', False):
|
||||||
@@ -2199,10 +2211,19 @@ class YoutubeDL(object):
|
|||||||
except (PostProcessingError) as err:
|
except (PostProcessingError) as err:
|
||||||
self.report_error('postprocessing: %s' % str(err))
|
self.report_error('postprocessing: %s' % str(err))
|
||||||
return
|
return
|
||||||
|
try:
|
||||||
|
for ph in self._post_hooks:
|
||||||
|
ph(filename)
|
||||||
|
except Exception as err:
|
||||||
|
self.report_error('post hooks: %s' % str(err))
|
||||||
|
return
|
||||||
must_record_download_archive = True
|
must_record_download_archive = True
|
||||||
|
|
||||||
if must_record_download_archive or self.params.get('force_write_download_archive', False):
|
if must_record_download_archive or self.params.get('force_write_download_archive', False):
|
||||||
self.record_download_archive(info_dict)
|
self.record_download_archive(info_dict)
|
||||||
|
max_downloads = self.params.get('max_downloads')
|
||||||
|
if max_downloads is not None and self._num_downloads >= int(max_downloads):
|
||||||
|
raise MaxDownloadsReached()
|
||||||
|
|
||||||
def download(self, url_list):
|
def download(self, url_list):
|
||||||
"""Download a given list of URLs."""
|
"""Download a given list of URLs."""
|
||||||
@@ -2501,7 +2522,7 @@ class YoutubeDL(object):
|
|||||||
['git', 'rev-parse', '--short', 'HEAD'],
|
['git', 'rev-parse', '--short', 'HEAD'],
|
||||||
stdout=subprocess.PIPE, stderr=subprocess.PIPE,
|
stdout=subprocess.PIPE, stderr=subprocess.PIPE,
|
||||||
cwd=os.path.dirname(os.path.abspath(__file__)))
|
cwd=os.path.dirname(os.path.abspath(__file__)))
|
||||||
out, err = sp.communicate()
|
out, err = process_communicate_or_kill(sp)
|
||||||
out = out.decode().strip()
|
out = out.decode().strip()
|
||||||
if re.match('[0-9a-f]+', out):
|
if re.match('[0-9a-f]+', out):
|
||||||
self._write_string('[debug] Git HEAD: ' + out + '\n')
|
self._write_string('[debug] Git HEAD: ' + out + '\n')
|
||||||
|
|||||||
@@ -2896,6 +2896,7 @@ else:
|
|||||||
_terminal_size = collections.namedtuple('terminal_size', ['columns', 'lines'])
|
_terminal_size = collections.namedtuple('terminal_size', ['columns', 'lines'])
|
||||||
|
|
||||||
def compat_get_terminal_size(fallback=(80, 24)):
|
def compat_get_terminal_size(fallback=(80, 24)):
|
||||||
|
from .utils import process_communicate_or_kill
|
||||||
columns = compat_getenv('COLUMNS')
|
columns = compat_getenv('COLUMNS')
|
||||||
if columns:
|
if columns:
|
||||||
columns = int(columns)
|
columns = int(columns)
|
||||||
@@ -2912,7 +2913,7 @@ else:
|
|||||||
sp = subprocess.Popen(
|
sp = subprocess.Popen(
|
||||||
['stty', 'size'],
|
['stty', 'size'],
|
||||||
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
||||||
out, err = sp.communicate()
|
out, err = process_communicate_or_kill(sp)
|
||||||
_lines, _columns = map(int, out.split())
|
_lines, _columns = map(int, out.split())
|
||||||
except Exception:
|
except Exception:
|
||||||
_columns, _lines = _terminal_size(*fallback)
|
_columns, _lines = _terminal_size(*fallback)
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ from ..utils import (
|
|||||||
handle_youtubedl_headers,
|
handle_youtubedl_headers,
|
||||||
check_executable,
|
check_executable,
|
||||||
is_outdated_version,
|
is_outdated_version,
|
||||||
|
process_communicate_or_kill,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@@ -104,7 +105,7 @@ class ExternalFD(FileDownloader):
|
|||||||
|
|
||||||
p = subprocess.Popen(
|
p = subprocess.Popen(
|
||||||
cmd, stderr=subprocess.PIPE)
|
cmd, stderr=subprocess.PIPE)
|
||||||
_, stderr = p.communicate()
|
_, stderr = process_communicate_or_kill(p)
|
||||||
if p.returncode != 0:
|
if p.returncode != 0:
|
||||||
self.to_stderr(stderr.decode('utf-8', 'replace'))
|
self.to_stderr(stderr.decode('utf-8', 'replace'))
|
||||||
return p.returncode
|
return p.returncode
|
||||||
@@ -143,7 +144,7 @@ class CurlFD(ExternalFD):
|
|||||||
|
|
||||||
# curl writes the progress to stderr so don't capture it.
|
# curl writes the progress to stderr so don't capture it.
|
||||||
p = subprocess.Popen(cmd)
|
p = subprocess.Popen(cmd)
|
||||||
p.communicate()
|
process_communicate_or_kill(p)
|
||||||
return p.returncode
|
return p.returncode
|
||||||
|
|
||||||
|
|
||||||
@@ -343,14 +344,17 @@ class FFmpegFD(ExternalFD):
|
|||||||
proc = subprocess.Popen(args, stdin=subprocess.PIPE, env=env)
|
proc = subprocess.Popen(args, stdin=subprocess.PIPE, env=env)
|
||||||
try:
|
try:
|
||||||
retval = proc.wait()
|
retval = proc.wait()
|
||||||
except KeyboardInterrupt:
|
except BaseException as e:
|
||||||
# subprocces.run would send the SIGKILL signal to ffmpeg and the
|
# subprocces.run would send the SIGKILL signal to ffmpeg and the
|
||||||
# mp4 file couldn't be played, but if we ask ffmpeg to quit it
|
# mp4 file couldn't be played, but if we ask ffmpeg to quit it
|
||||||
# produces a file that is playable (this is mostly useful for live
|
# produces a file that is playable (this is mostly useful for live
|
||||||
# streams). Note that Windows is not affected and produces playable
|
# streams). Note that Windows is not affected and produces playable
|
||||||
# files (see https://github.com/ytdl-org/youtube-dl/issues/8300).
|
# files (see https://github.com/ytdl-org/youtube-dl/issues/8300).
|
||||||
if sys.platform != 'win32':
|
if isinstance(e, KeyboardInterrupt) and sys.platform != 'win32':
|
||||||
proc.communicate(b'q')
|
process_communicate_or_kill(proc, b'q')
|
||||||
|
else:
|
||||||
|
proc.kill()
|
||||||
|
proc.wait()
|
||||||
raise
|
raise
|
||||||
return retval
|
return retval
|
||||||
|
|
||||||
|
|||||||
@@ -89,11 +89,13 @@ class RtmpFD(FileDownloader):
|
|||||||
self.to_screen('')
|
self.to_screen('')
|
||||||
cursor_in_new_line = True
|
cursor_in_new_line = True
|
||||||
self.to_screen('[rtmpdump] ' + line)
|
self.to_screen('[rtmpdump] ' + line)
|
||||||
finally:
|
if not cursor_in_new_line:
|
||||||
|
self.to_screen('')
|
||||||
|
return proc.wait()
|
||||||
|
except BaseException: # Including KeyboardInterrupt
|
||||||
|
proc.kill()
|
||||||
proc.wait()
|
proc.wait()
|
||||||
if not cursor_in_new_line:
|
raise
|
||||||
self.to_screen('')
|
|
||||||
return proc.returncode
|
|
||||||
|
|
||||||
url = info_dict['url']
|
url = info_dict['url']
|
||||||
player_url = info_dict.get('player_url')
|
player_url = info_dict.get('player_url')
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ from ..utils import (
|
|||||||
get_exe_version,
|
get_exe_version,
|
||||||
is_outdated_version,
|
is_outdated_version,
|
||||||
std_headers,
|
std_headers,
|
||||||
|
process_communicate_or_kill,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@@ -226,7 +227,7 @@ class PhantomJSwrapper(object):
|
|||||||
self.exe, '--ssl-protocol=any',
|
self.exe, '--ssl-protocol=any',
|
||||||
self._TMP_FILES['script'].name
|
self._TMP_FILES['script'].name
|
||||||
], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
||||||
out, err = p.communicate()
|
out, err = process_communicate_or_kill(p)
|
||||||
if p.returncode != 0:
|
if p.returncode != 0:
|
||||||
raise ExtractorError(
|
raise ExtractorError(
|
||||||
'Executing JS failed\n:' + encodeArgument(err))
|
'Executing JS failed\n:' + encodeArgument(err))
|
||||||
|
|||||||
@@ -1686,11 +1686,12 @@ class YoutubeIE(YoutubeBaseInfoExtractor):
|
|||||||
if embedded_config:
|
if embedded_config:
|
||||||
return embedded_config
|
return embedded_config
|
||||||
|
|
||||||
|
video_info = {}
|
||||||
player_response = {}
|
player_response = {}
|
||||||
|
ytplayer_config = None
|
||||||
|
embed_webpage = None
|
||||||
|
|
||||||
# Get video info
|
# Get video info
|
||||||
video_info = {}
|
|
||||||
embed_webpage = None
|
|
||||||
if (self._og_search_property('restrictions:age', video_webpage, default=None) == '18+'
|
if (self._og_search_property('restrictions:age', video_webpage, default=None) == '18+'
|
||||||
or re.search(r'player-age-gate-content">', video_webpage) is not None):
|
or re.search(r'player-age-gate-content">', video_webpage) is not None):
|
||||||
cookie_keys = self._get_cookies('https://www.youtube.com').keys()
|
cookie_keys = self._get_cookies('https://www.youtube.com').keys()
|
||||||
|
|||||||
@@ -466,7 +466,7 @@ def parseOpts(overrideArguments=None):
|
|||||||
video_format.add_option(
|
video_format.add_option(
|
||||||
'--prefer-free-formats',
|
'--prefer-free-formats',
|
||||||
action='store_true', dest='prefer_free_formats', default=False,
|
action='store_true', dest='prefer_free_formats', default=False,
|
||||||
help='Prefer free video formats unless a specific one is requested')
|
help='Prefer free video formats over non-free formats of same quality')
|
||||||
video_format.add_option(
|
video_format.add_option(
|
||||||
'-F', '--list-formats',
|
'-F', '--list-formats',
|
||||||
action='store_true', dest='listformats',
|
action='store_true', dest='listformats',
|
||||||
|
|||||||
@@ -14,7 +14,8 @@ from ..utils import (
|
|||||||
PostProcessingError,
|
PostProcessingError,
|
||||||
prepend_extension,
|
prepend_extension,
|
||||||
replace_extension,
|
replace_extension,
|
||||||
shell_quote
|
shell_quote,
|
||||||
|
process_communicate_or_kill,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@@ -128,7 +129,7 @@ class EmbedThumbnailPP(FFmpegPostProcessor):
|
|||||||
self._downloader.to_screen('[debug] AtomicParsley command line: %s' % shell_quote(cmd))
|
self._downloader.to_screen('[debug] AtomicParsley command line: %s' % shell_quote(cmd))
|
||||||
|
|
||||||
p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
||||||
stdout, stderr = p.communicate()
|
stdout, stderr = process_communicate_or_kill(p)
|
||||||
|
|
||||||
if p.returncode != 0:
|
if p.returncode != 0:
|
||||||
msg = stderr.decode('utf-8', 'replace').strip()
|
msg = stderr.decode('utf-8', 'replace').strip()
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ from ..utils import (
|
|||||||
dfxp2srt,
|
dfxp2srt,
|
||||||
ISO639Utils,
|
ISO639Utils,
|
||||||
replace_extension,
|
replace_extension,
|
||||||
|
process_communicate_or_kill,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@@ -182,7 +183,7 @@ class FFmpegPostProcessor(PostProcessor):
|
|||||||
handle = subprocess.Popen(
|
handle = subprocess.Popen(
|
||||||
cmd, stderr=subprocess.PIPE,
|
cmd, stderr=subprocess.PIPE,
|
||||||
stdout=subprocess.PIPE, stdin=subprocess.PIPE)
|
stdout=subprocess.PIPE, stdin=subprocess.PIPE)
|
||||||
stdout_data, stderr_data = handle.communicate()
|
stdout_data, stderr_data = process_communicate_or_kill(handle)
|
||||||
expected_ret = 0 if self.probe_available else 1
|
expected_ret = 0 if self.probe_available else 1
|
||||||
if handle.wait() != expected_ret:
|
if handle.wait() != expected_ret:
|
||||||
return None
|
return None
|
||||||
@@ -230,7 +231,7 @@ class FFmpegPostProcessor(PostProcessor):
|
|||||||
if self._downloader.params.get('verbose', False):
|
if self._downloader.params.get('verbose', False):
|
||||||
self._downloader.to_screen('[debug] ffmpeg command line: %s' % shell_quote(cmd))
|
self._downloader.to_screen('[debug] ffmpeg command line: %s' % shell_quote(cmd))
|
||||||
p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE)
|
p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE)
|
||||||
stdout, stderr = p.communicate()
|
stdout, stderr = process_communicate_or_kill(p)
|
||||||
if p.returncode != 0:
|
if p.returncode != 0:
|
||||||
stderr = stderr.decode('utf-8', 'replace')
|
stderr = stderr.decode('utf-8', 'replace')
|
||||||
msg = stderr.strip().split('\n')[-1]
|
msg = stderr.strip().split('\n')[-1]
|
||||||
|
|||||||
+23
-10
@@ -2215,6 +2215,15 @@ def unescapeHTML(s):
|
|||||||
r'&([^&;]+;)', lambda m: _htmlentity_transform(m.group(1)), s)
|
r'&([^&;]+;)', lambda m: _htmlentity_transform(m.group(1)), s)
|
||||||
|
|
||||||
|
|
||||||
|
def process_communicate_or_kill(p, *args, **kwargs):
|
||||||
|
try:
|
||||||
|
return p.communicate(*args, **kwargs)
|
||||||
|
except BaseException: # Including KeyboardInterrupt
|
||||||
|
p.kill()
|
||||||
|
p.wait()
|
||||||
|
raise
|
||||||
|
|
||||||
|
|
||||||
def get_subprocess_encoding():
|
def get_subprocess_encoding():
|
||||||
if sys.platform == 'win32' and sys.getwindowsversion()[0] >= 5:
|
if sys.platform == 'win32' and sys.getwindowsversion()[0] >= 5:
|
||||||
# For subprocess calls, encode with locale encoding
|
# For subprocess calls, encode with locale encoding
|
||||||
@@ -3730,7 +3739,8 @@ def check_executable(exe, args=[]):
|
|||||||
""" Checks if the given binary is installed somewhere in PATH, and returns its name.
|
""" Checks if the given binary is installed somewhere in PATH, and returns its name.
|
||||||
args can be a list of arguments for a short output (like -version) """
|
args can be a list of arguments for a short output (like -version) """
|
||||||
try:
|
try:
|
||||||
subprocess.Popen([exe] + args, stdout=subprocess.PIPE, stderr=subprocess.PIPE).communicate()
|
process_communicate_or_kill(subprocess.Popen(
|
||||||
|
[exe] + args, stdout=subprocess.PIPE, stderr=subprocess.PIPE))
|
||||||
except OSError:
|
except OSError:
|
||||||
return False
|
return False
|
||||||
return exe
|
return exe
|
||||||
@@ -3744,10 +3754,10 @@ def get_exe_version(exe, args=['--version'],
|
|||||||
# STDIN should be redirected too. On UNIX-like systems, ffmpeg triggers
|
# STDIN should be redirected too. On UNIX-like systems, ffmpeg triggers
|
||||||
# SIGTTOU if youtube-dlc is run in the background.
|
# SIGTTOU if youtube-dlc is run in the background.
|
||||||
# See https://github.com/ytdl-org/youtube-dl/issues/955#issuecomment-209789656
|
# See https://github.com/ytdl-org/youtube-dl/issues/955#issuecomment-209789656
|
||||||
out, _ = subprocess.Popen(
|
out, _ = process_communicate_or_kill(subprocess.Popen(
|
||||||
[encodeArgument(exe)] + args,
|
[encodeArgument(exe)] + args,
|
||||||
stdin=subprocess.PIPE,
|
stdin=subprocess.PIPE,
|
||||||
stdout=subprocess.PIPE, stderr=subprocess.STDOUT).communicate()
|
stdout=subprocess.PIPE, stderr=subprocess.STDOUT))
|
||||||
except OSError:
|
except OSError:
|
||||||
return False
|
return False
|
||||||
if isinstance(out, bytes): # Python 2.x
|
if isinstance(out, bytes): # Python 2.x
|
||||||
@@ -3892,13 +3902,16 @@ def read_batch_urls(batch_fd):
|
|||||||
def fixup(url):
|
def fixup(url):
|
||||||
if not isinstance(url, compat_str):
|
if not isinstance(url, compat_str):
|
||||||
url = url.decode('utf-8', 'replace')
|
url = url.decode('utf-8', 'replace')
|
||||||
BOM_UTF8 = '\xef\xbb\xbf'
|
BOM_UTF8 = ('\xef\xbb\xbf', '\ufeff')
|
||||||
if url.startswith(BOM_UTF8):
|
for bom in BOM_UTF8:
|
||||||
url = url[len(BOM_UTF8):]
|
if url.startswith(bom):
|
||||||
url = url.strip()
|
url = url[len(bom):]
|
||||||
if url.startswith(('#', ';', ']')):
|
url = url.lstrip()
|
||||||
|
if not url or url.startswith(('#', ';', ']')):
|
||||||
return False
|
return False
|
||||||
return url
|
# "#" cannot be stripped out since it is part of the URI
|
||||||
|
# However, it can be safely stipped out if follwing a whitespace
|
||||||
|
return re.split(r'\s#', url, 1)[0].rstrip()
|
||||||
|
|
||||||
with contextlib.closing(batch_fd) as fd:
|
with contextlib.closing(batch_fd) as fd:
|
||||||
return [url for url in map(fixup, fd) if url]
|
return [url for url in map(fixup, fd) if url]
|
||||||
@@ -5703,7 +5716,7 @@ def write_xattr(path, key, value):
|
|||||||
cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE)
|
cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE)
|
||||||
except EnvironmentError as e:
|
except EnvironmentError as e:
|
||||||
raise XAttrMetadataError(e.errno, e.strerror)
|
raise XAttrMetadataError(e.errno, e.strerror)
|
||||||
stdout, stderr = p.communicate()
|
stdout, stderr = process_communicate_or_kill(p)
|
||||||
stderr = stderr.decode('utf-8', 'replace')
|
stderr = stderr.decode('utf-8', 'replace')
|
||||||
if p.returncode != 0:
|
if p.returncode != 0:
|
||||||
raise XAttrMetadataError(p.returncode, stderr)
|
raise XAttrMetadataError(p.returncode, stderr)
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
__version__ = '2021.01.07-1'
|
__version__ = '2021.01.08'
|
||||||
|
|||||||
Reference in New Issue
Block a user