From e1c8438739a329cae6c3c45afe54aedf7df96bc1 Mon Sep 17 00:00:00 2001 From: LecygneNoir Date: Mon, 10 Dec 2018 07:28:04 +0100 Subject: [PATCH 01/13] correct some typo in output, fix #23 --- lib/yt_upload.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/yt_upload.py b/lib/yt_upload.py index daebdc9..0dfbc57 100644 --- a/lib/yt_upload.py +++ b/lib/yt_upload.py @@ -254,7 +254,7 @@ def set_playlist(youtube, playlist_id, video_id): logging.error("Youtube: Error: " + str(e.message)) else: logging.error("Youtube: Error: " + str(e)) - logging.info('Youtube: Video is correclty added to the playlist.') + logging.info('Youtube: Video is correctly added to the playlist.') # This method implements an exponential backoff strategy to resume a -- 2.20.1 From 3ac6d008dfd8e31e3a676c2fb528da52b1b02e16 Mon Sep 17 00:00:00 2001 From: Zykino Date: Sat, 10 Nov 2018 18:56:26 +0100 Subject: [PATCH 02/13] decode stdin strins arguments --- lib/utils.py | 14 ++++++++++---- prismedia_upload.py | 9 ++------- 2 files changed, 12 insertions(+), 11 deletions(-) diff --git a/lib/utils.py b/lib/utils.py index 63083b0..2a20ad3 100644 --- a/lib/utils.py +++ b/lib/utils.py @@ -124,7 +124,6 @@ def searchThumbnail(options): options['--thumbnail'] = video_directory + video_file + ".jpeg" return options - # return the nfo as a RawConfigParser object def loadNFO(options): video_directory = dirname(options.get('--file')) + "/" @@ -169,7 +168,6 @@ def loadNFO(options): logging.info("No suitable NFO found, skipping.") return False - def parseNFO(options): nfo = loadNFO(options) if nfo: @@ -190,14 +188,22 @@ def parseNFO(options): exit(1) return options - def upcaseFirstLetter(s): return s[0].upper() + s[1:] - def cleanString(toclean): toclean = toclean.decode('utf-8') toclean = unidecode.unidecode(toclean) cleaned = re.sub('[^A-Za-z0-9]+', '', toclean) return cleaned + +def decodeArgumentStrings(options, encoding): + if options["--name"] is not None: + options["--name"] = options["--name"].decode(encoding) + + if options["--description"] is not None: + options["--description"] = options["--description"].decode(encoding) + + if options["--tags"] is not None: + options["--tags"] = options["--tags"].decode(encoding) diff --git a/prismedia_upload.py b/prismedia_upload.py index ba86b86..df6ab30 100755 --- a/prismedia_upload.py +++ b/prismedia_upload.py @@ -62,12 +62,12 @@ Languages: from os.path import dirname, realpath import sys import datetime +import locale import logging logging.basicConfig(format='%(asctime)s %(message)s', level=logging.INFO) from docopt import docopt - # Allows a relative import from the parent folder sys.path.insert(0, dirname(realpath(__file__)) + "/lib") @@ -108,7 +108,6 @@ VALID_LANGUAGES = ('arabic', 'english', 'french', 'japanese', 'korean', 'mandarin', 'portuguese', 'punjabi', 'russian', 'spanish') - def validateVideo(path): supported_types = ['video/mp4'] if magic.from_file(path, mime=True) in supported_types: @@ -116,21 +115,18 @@ def validateVideo(path): else: return False - def validateCategory(category): if category.lower() in VALID_CATEGORIES: return True else: return False - def validatePrivacy(privacy): if privacy.lower() in VALID_PRIVACY_STATUSES: return True else: return False - def validatePlatform(platform): for plfrm in platform.split(','): if plfrm.lower().replace(" ", "") not in VALID_PLATFORM: @@ -138,14 +134,12 @@ def validatePlatform(platform): return True - def validateLanguage(language): if language.lower() in VALID_LANGUAGES: return True else: return False - def validatePublish(publish): # Check date format and if date is future try: @@ -219,6 +213,7 @@ if __name__ == '__main__': '--version': bool }) + utils.decodeArgumentStrings(options, locale.getpreferredencoding()) options = utils.parseNFO(options) if not options.get('--thumbnail'): -- 2.20.1 From 535156d1b7e2c22bbdc1ca80170f0e627ec6829d Mon Sep 17 00:00:00 2001 From: Zykino Date: Sat, 10 Nov 2018 19:13:36 +0100 Subject: [PATCH 03/13] update the README --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index cd712e9..9bad074 100644 --- a/README.md +++ b/README.md @@ -149,8 +149,8 @@ Languages: - [x] set default language - [x] thumbnail/preview - [x] multiple lines description (see [issue 4](https://git.lecygnenoir.info/LecygneNoir/prismedia/issues/4)) - - [x] add videos to playlist for Peertube - - [x] add videos to playlist for Youtube + - [x] add videos to playlist + - [x] create playlist - [x] Use a config file (NFO) file to retrieve videos arguments - [x] Allow to choose peertube or youtube upload (to resume failed upload for example) - [x] Add publishAt option to plan your videos @@ -163,4 +163,4 @@ Languages: If your server uses peertube before 1.0.0-beta4, use the version inside tag 1.0.0-beta3! ## Sources -inspired by [peeror](https://git.rigelk.eu/rigelk/peeror) and [youtube-upload](https://github.com/tokland/youtube-upload) \ No newline at end of file +inspired by [peeror](https://git.rigelk.eu/rigelk/peeror) and [youtube-upload](https://github.com/tokland/youtube-upload) -- 2.20.1 From c1f3e56261e0ff15d9489cc92382aae1d8172d29 Mon Sep 17 00:00:00 2001 From: Zykino Date: Sun, 11 Nov 2018 13:00:47 +0100 Subject: [PATCH 04/13] fix error message --- prismedia_upload.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/prismedia_upload.py b/prismedia_upload.py index df6ab30..da143f2 100755 --- a/prismedia_upload.py +++ b/prismedia_upload.py @@ -172,7 +172,7 @@ if __name__ == '__main__': Optional('--description'): Or(None, And( str, lambda x: not x.isdigit(), - error="The video name should be a string") + error="The video description should be a string") ), Optional('--tags'): Or(None, And( str, -- 2.20.1 From 33e55bc18e72f2cec9b0e832dc42749a246f1c3f Mon Sep 17 00:00:00 2001 From: Zykino Date: Sun, 11 Nov 2018 14:31:51 +0100 Subject: [PATCH 05/13] prevent decoding unicode strings since python prefer to crash than doing nothing --- lib/utils.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/utils.py b/lib/utils.py index 2a20ad3..08bc82a 100644 --- a/lib/utils.py +++ b/lib/utils.py @@ -199,6 +199,10 @@ def cleanString(toclean): return cleaned def decodeArgumentStrings(options, encoding): + # Python crash when decding from UTF-8 to UTF-8, so we prevent this + if "utf-8" == encoding.lower(): + return; + if options["--name"] is not None: options["--name"] = options["--name"].decode(encoding) -- 2.20.1 From 2da64798c1c3918424eb7e9f32cce37c0c465f32 Mon Sep 17 00:00:00 2001 From: Zykino Date: Sun, 11 Nov 2018 16:52:48 +0100 Subject: [PATCH 06/13] The strings arguments should be in unicode --- prismedia_upload.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/prismedia_upload.py b/prismedia_upload.py index da143f2..4119272 100755 --- a/prismedia_upload.py +++ b/prismedia_upload.py @@ -165,17 +165,17 @@ if __name__ == '__main__': schema = Schema({ '--file': And(str, validateVideo, error='file is not supported, please use mp4'), Optional('--name'): Or(None, And( - str, + unicode, lambda x: not x.isdigit(), error="The video name should be a string") ), Optional('--description'): Or(None, And( - str, + unicode, lambda x: not x.isdigit(), error="The video description should be a string") ), Optional('--tags'): Or(None, And( - str, + unicode, lambda x: not x.isdigit(), error="Tags should be a string") ), -- 2.20.1 From 2f43a4839f4824f7ac95baf635ab2c0bc790b719 Mon Sep 17 00:00:00 2001 From: Zykino Date: Wed, 28 Nov 2018 00:50:38 +0100 Subject: [PATCH 07/13] string from URF-8 encoded files have not the "unicode" type --- README.md | 3 ++- prismedia_upload.py | 6 +++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 9bad074..a813848 100644 --- a/README.md +++ b/README.md @@ -98,7 +98,8 @@ Options: --disable-comments Disable comments (Peertube only as YT API does not support) (default: comments are enabled) --nsfw Set the video as No Safe For Work (Peertube only as YT API does not support) (default: video is safe) --nfo=STRING Configure a specific nfo file to set options for the video. - By default Prismedia search a .txt based on video name + By default Prismedia search a .txt based on the video name and will + decode the file as UTF-8 (so make sure your nfo file is UTF-8 encoded) See nfo_example.txt for more details --platform=STRING List of platform(s) to upload to, comma separated. Supported platforms are youtube and peertube (default is both) diff --git a/prismedia_upload.py b/prismedia_upload.py index 4119272..00f64ae 100755 --- a/prismedia_upload.py +++ b/prismedia_upload.py @@ -165,17 +165,17 @@ if __name__ == '__main__': schema = Schema({ '--file': And(str, validateVideo, error='file is not supported, please use mp4'), Optional('--name'): Or(None, And( - unicode, + basestring, lambda x: not x.isdigit(), error="The video name should be a string") ), Optional('--description'): Or(None, And( - unicode, + basestring, lambda x: not x.isdigit(), error="The video description should be a string") ), Optional('--tags'): Or(None, And( - unicode, + basestring, lambda x: not x.isdigit(), error="Tags should be a string") ), -- 2.20.1 From c07035426b067289d4af2330b9045b6de64df563 Mon Sep 17 00:00:00 2001 From: Zykino Date: Tue, 11 Dec 2018 01:17:23 +0100 Subject: [PATCH 08/13] fix typo --- lib/utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/utils.py b/lib/utils.py index 08bc82a..1602ab6 100644 --- a/lib/utils.py +++ b/lib/utils.py @@ -199,7 +199,7 @@ def cleanString(toclean): return cleaned def decodeArgumentStrings(options, encoding): - # Python crash when decding from UTF-8 to UTF-8, so we prevent this + # Python crash when decoding from UTF-8 to UTF-8, so we prevent this if "utf-8" == encoding.lower(): return; -- 2.20.1 From 0d898f200a27c611d11b676b52029f46d6ab0845 Mon Sep 17 00:00:00 2001 From: Rigel Kent Date: Mon, 18 Feb 2019 14:19:50 +0100 Subject: [PATCH 09/13] migrated to poetry and exported requirements --- .python-version | 1 + README.md | 37 +++++-- poetry.lock | 283 +++++++++++++++++++++++++++++++++++++++++++++++ pyproject.toml | 30 +++++ requirements.txt | 93 ++++++++++++++++ 5 files changed, 435 insertions(+), 9 deletions(-) create mode 100644 .python-version create mode 100644 poetry.lock create mode 100644 pyproject.toml create mode 100644 requirements.txt diff --git a/.python-version b/.python-version new file mode 100644 index 0000000..f24054f --- /dev/null +++ b/.python-version @@ -0,0 +1 @@ +2.7.15 diff --git a/README.md b/README.md index a813848..c643fad 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,10 @@ # Prismedia -A scripting way to upload videos to peertube and youtube written in python2 +Scripting your way to upload videos to peertube and youtube. ## Dependencies -Search in your package manager, otherwise use ``pip install --upgrade`` + +Search in your system package manager, otherwise use ``pip install --upgrade`` for the following packages: - google-auth - google-auth-oauthlib - google-auth-httplib2 @@ -15,16 +16,28 @@ Search in your package manager, otherwise use ``pip install --upgrade`` - requests-toolbelt - tzlocal +Otherwise, you can use the requirements file with `pip install -r requirements.txt`. (*note:* requirements are generated via `poetry export -f requirements.txt`) + +Otherwise, you can use [pyenv](https://github.com/pyenv/pyenv) and [poetry](https://poetry.eustace.io/): + +``` +pyenv install # installs the python version specified in .python-version +pyenv shell # activates the python version for the session +poetry install # installs the dependency in a virtualenv specific to the project +``` + ## Configuration -Edit peertube_secret and youtube_secret.json with your credentials. +Edit `peertube_secret` and `youtube_secret.json` with your credentials. ### Peertube + Set your credentials, peertube server URL. You can get client_id and client_secret by logging in your peertube website and reaching the URL: https://domain.example/api/v1/oauth-clients/local You can set ``OAUTHLIB_INSECURE_TRANSPORT`` to 1 if you do not use https (not recommended) ### Youtube + Youtube uses combination of oauth and API access to identify. **Credentials** @@ -48,9 +61,10 @@ If you plan an larger usage, please consider creating your own youtube_secret fi - Save this JSON as your youtube_secret.json file. ## How To -Currently in heavy development -Support only mp4 for cross compatibility between Youtube and Peertube +>> Currently in heavy development + +Supports only mp4 for cross compatibility between Youtube and Peertube. Simply upload a video: @@ -71,14 +85,12 @@ Provide a thumbnail: ./prismedia_upload.py --file="yourvideo.mp4" -d "Video with thumbnail" --thumbnail="/path/to/your/thumbnail.jpg" ``` - Use a NFO file to specify your video options: ``` ./prismedia_upload.py --file="yourvideo.mp4" --nfo /path/to/your/nfo.txt ``` - Use --help to get all available options: ``` @@ -161,7 +173,14 @@ Languages: ## Compatibility -If your server uses peertube before 1.0.0-beta4, use the version inside tag 1.0.0-beta3! +### Compatibility with PeerTube + +If your server uses PeerTube before `1.0.0-beta4`, use the version inside tag `1.0.0-beta3` of prismedia! + +### Compatibility with Operating Systems + +The script has been tested on Linux and Windows platforms. ## Sources -inspired by [peeror](https://git.rigelk.eu/rigelk/peeror) and [youtube-upload](https://github.com/tokland/youtube-upload) + +Prismedia has been inspired by [peeror](https://git.rigelk.eu/rigelk/peeror) and [youtube-upload](https://github.com/tokland/youtube-upload). diff --git a/poetry.lock b/poetry.lock new file mode 100644 index 0000000..715710f --- /dev/null +++ b/poetry.lock @@ -0,0 +1,283 @@ +[[package]] +category = "main" +description = "Extensible memoizing collections and decorators" +name = "cachetools" +optional = false +python-versions = "*" +version = "3.1.0" + +[[package]] +category = "main" +description = "Python package for providing Mozilla's CA Bundle." +name = "certifi" +optional = false +python-versions = "*" +version = "2018.11.29" + +[[package]] +category = "main" +description = "Universal encoding detector for Python 2 and 3" +name = "chardet" +optional = false +python-versions = "*" +version = "3.0.4" + +[[package]] +category = "main" +description = "Pythonic argument parser, that will make you smile" +name = "docopt" +optional = false +python-versions = "*" +version = "0.6.2" + +[[package]] +category = "main" +description = "Google API Client Library for Python" +name = "google-api-python-client" +optional = false +python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*" +version = "1.7.8" + +[package.dependencies] +google-auth = ">=1.4.1" +google-auth-httplib2 = ">=0.0.3" +httplib2 = ">=0.9.2,<1dev" +six = ">=1.6.1,<2dev" +uritemplate = ">=3.0.0,<4dev" + +[[package]] +category = "main" +description = "Google Authentication Library" +name = "google-auth" +optional = false +python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*" +version = "1.6.2" + +[package.dependencies] +cachetools = ">=2.0.0" +pyasn1-modules = ">=0.2.1" +rsa = ">=3.1.4" +six = ">=1.9.0" + +[[package]] +category = "main" +description = "Google Authentication Library: httplib2 transport" +name = "google-auth-httplib2" +optional = false +python-versions = "*" +version = "0.0.3" + +[package.dependencies] +google-auth = "*" +httplib2 = ">=0.9.1" + +[[package]] +category = "main" +description = "Google Authentication Library" +name = "google-auth-oauthlib" +optional = false +python-versions = "*" +version = "0.2.0" + +[package.dependencies] +google-auth = "*" +requests-oauthlib = ">=0.7.0" + +[package.extras] +tool = ["click"] + +[[package]] +category = "main" +description = "A comprehensive HTTP client library." +name = "httplib2" +optional = false +python-versions = "*" +version = "0.12.1" + +[[package]] +category = "main" +description = "Internationalized Domain Names in Applications (IDNA)" +name = "idna" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +version = "2.8" + +[[package]] +category = "main" +description = "A generic, spec-compliant, thorough implementation of the OAuth request-signing logic" +name = "oauthlib" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +version = "3.0.1" + +[package.extras] +rsa = ["cryptography"] +signals = ["blinker"] +signedtoken = ["cryptography", "pyjwt (>=1.0.0)"] + +[[package]] +category = "main" +description = "ASN.1 types and codecs" +name = "pyasn1" +optional = false +python-versions = "*" +version = "0.4.5" + +[[package]] +category = "main" +description = "A collection of ASN.1-based protocols modules." +name = "pyasn1-modules" +optional = false +python-versions = "*" +version = "0.2.4" + +[package.dependencies] +pyasn1 = ">=0.4.1,<0.5.0" + +[[package]] +category = "main" +description = "File type identification using libmagic" +name = "python-magic" +optional = false +python-versions = "*" +version = "0.4.15" + +[[package]] +category = "main" +description = "World timezone definitions, modern and historical" +name = "pytz" +optional = false +python-versions = "*" +version = "2018.9" + +[[package]] +category = "main" +description = "Python HTTP for Humans." +name = "requests" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +version = "2.21.0" + +[package.dependencies] +certifi = ">=2017.4.17" +chardet = ">=3.0.2,<3.1.0" +idna = ">=2.5,<2.9" +urllib3 = ">=1.21.1,<1.25" + +[package.extras] +security = ["pyOpenSSL (>=0.14)", "cryptography (>=1.3.4)", "idna (>=2.0.0)"] +socks = ["PySocks (>=1.5.6,<1.5.7 || >1.5.7)", "win-inet-pton"] + +[[package]] +category = "main" +description = "OAuthlib authentication support for Requests." +name = "requests-oauthlib" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +version = "1.2.0" + +[package.dependencies] +oauthlib = ">=3.0.0" +requests = ">=2.0.0" + +[package.extras] +rsa = ["oauthlib (>=3.0.0)"] + +[[package]] +category = "main" +description = "A utility belt for advanced users of python-requests" +name = "requests-toolbelt" +optional = false +python-versions = "*" +version = "0.9.1" + +[package.dependencies] +requests = ">=2.0.1,<3.0.0" + +[[package]] +category = "main" +description = "Pure-Python RSA implementation" +name = "rsa" +optional = false +python-versions = "*" +version = "4.0" + +[package.dependencies] +pyasn1 = ">=0.1.3" + +[[package]] +category = "main" +description = "Simple data validation library" +name = "schema" +optional = false +python-versions = "*" +version = "0.6.8" + +[[package]] +category = "main" +description = "Python 2 and 3 compatibility utilities" +name = "six" +optional = false +python-versions = ">=2.6, !=3.0.*, !=3.1.*" +version = "1.12.0" + +[[package]] +category = "main" +description = "tzinfo object for the local timezone" +name = "tzlocal" +optional = false +python-versions = "*" +version = "1.5.1" + +[package.dependencies] +pytz = "*" + +[[package]] +category = "main" +description = "URI templates" +name = "uritemplate" +optional = false +python-versions = "*" +version = "3.0.0" + +[[package]] +category = "main" +description = "HTTP library with thread-safe connection pooling, file post, and more." +name = "urllib3" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, <4" +version = "1.24.1" + +[package.extras] +secure = ["pyOpenSSL (>=0.14)", "cryptography (>=1.3.4)", "idna (>=2.0.0)", "certifi", "ipaddress"] +socks = ["PySocks (>=1.5.6,<1.5.7 || >1.5.7,<2.0)"] + +[metadata] +content-hash = "9e8128dce8edb5dddbe82929fdda23e4ff9ef4f2c400f033d92aa752f4de366b" +python-versions = "^2.7" + +[metadata.hashes] +cachetools = ["219b7dc6024195b6f2bc3d3f884d1fef458745cd323b04165378622dcc823852", "9efcc9fab3b49ab833475702b55edd5ae07af1af7a4c627678980b45e459c460"] +certifi = ["47f9c83ef4c0c621eaef743f133f09fa8a74a9b75f037e8624f83bd1b6626cb7", "993f830721089fef441cdfeb4b2c8c9df86f0c63239f06bd025a76a7daddb033"] +chardet = ["84ab92ed1c4d4f16916e05906b6b75a6c0fb5db821cc65e70cbd64a3e2a5eaae", "fc323ffcaeaed0e0a02bf4d117757b98aed530d9ed4531e3e15460124c106691"] +docopt = ["49b3a825280bd66b3aa83585ef59c4a8c82f2c8a522dbe754a8bc8d08c85c491"] +google-api-python-client = ["06907006ed5ce831018f03af3852d739c0b2489cdacfda6971bcc2075c762858", "937eabdc3940977f712fa648a096a5142766b6d0a0f58bc603e2ac0687397ef0"] +google-auth = ["b6081ba9946828d6417c15ecdc723fdb7c007cdd74e140747d3876a7440f0be5", "e8d64e9bc8cb6f0fc5360c693f86dc9ee6964081ee702e3b5ddc937f99efc950"] +google-auth-httplib2 = ["098fade613c25b4527b2c08fa42d11f3c2037dda8995d86de0745228e965d445", "f1c437842155680cf9918df9bc51c1182fda41feef88c34004bd1978c8157e08"] +google-auth-oauthlib = ["226d1d0960f86ba5d9efd426a70b291eaba96f47d071657e0254ea969025728a", "81ba22acada4d13b1d83f9371ab19fd61f1250a542d21cf49e4dcf0637a7344a"] +httplib2 = ["4ba6b8fd77d0038769bf3c33c9a96a6f752bc4cdf739701fdcaf210121f399d4"] +idna = ["c357b3f628cf53ae2c4c05627ecc484553142ca23264e593d327bcde5e9c3407", "ea8b7f6188e6fa117537c3df7da9fc686d485087abf6ac197f9c46432f7e4a3c"] +oauthlib = ["0ce32c5d989a1827e3f1148f98b9085ed2370fc939bf524c9c851d8714797298", "3e1e14f6cde7e5475128d30e97edc3bfb4dc857cb884d8714ec161fdbb3b358e"] +pyasn1 = ["061442c60842f6d11051d4fdae9bc197b64bd41573a12234a753a0cb80b4f30b", "0ee2449bf4c4e535823acc25624c45a8b454f328d59d3f3eeb82d3567100b9bd", "5f9fb05c33e53b9a6ee3b1ed1d292043f83df465852bec876e93b47fd2df7eed", "65201d28e081f690a32401e6253cca4449ccacc8f3988e811fae66bd822910ee", "79b336b073a52fa3c3d8728e78fa56b7d03138ef59f44084de5f39650265b5ff", "8ec20f61483764de281e0b4aba7d12716189700debcfa9e7935780850bf527f3", "9458d0273f95d035de4c0d5e0643f25daba330582cc71bb554fe6969c015042a", "98d97a1833a29ca61cd04a60414def8f02f406d732f9f0bcb49f769faff1b699", "b00d7bfb6603517e189d1ad76967c7e805139f63e43096e5f871d1277f50aea5", "b06c0cfd708b806ea025426aace45551f91ea7f557e0c2d4fbd9a4b346873ce0", "d14d05984581770333731690f5453efd4b82e1e5d824a1d7976b868a2e5c38e8", "da2420fe13a9452d8ae97a0e478adde1dee153b11ba832a95b223a2ba01c10f7", "da6b43a8c9ae93bc80e2739efb38cc776ba74a886e3e9318d65fe81a8b8a2c6e"] +pyasn1-modules = ["136020f884635942239b33abdb63b1e0fdfb3c4bc8693f769ff1ab0908133a5b", "1c2ce0717e099620d7d425d2bb55e68f8126d77c8ba93112f0448a212048fe76", "39da883a45dfc71314c48bba772be63a13946d0dd6abde326df163656a7b13e1", "4160b0caedf8f1675ca7b94a65900d0219c715ac745cbc0c93557a9864b19748", "50c5f454c29bc8a7b8bfffc0fd00fed1f9012160b4532807a33c27af91747337", "52c46ecb2c1e7a03fe54dc8e11d6460ec7ebdcaedba3b0fe4ba2a811521df05f", "6db7a0510e55212b42a1f3e3553559eb214c8c8495e1018b4135d2bfb5a9169a", "79580acf813e3b7d6e69783884e6e83ac94bf4617b36a135b85c599d8a818a7b", "98e80b5ae1ed0d92694927a3e34df016c3b69b7bf439b32fc0a0dc516ec3653d", "9e879981cbf4c868a2267385a56837e0d384eab2d1690e6e0c8bba28d102509e", "a52090e8c5841ebbf08ae455146792d9ef3e8445b21055d3a3b7ed9c712b7c7c", "c00dad1d69d8592bbbc978f5beb3e992d3bf996e6b97eeec1c8608f81221d922", "c226b5c17683d98498e157d6ac0098b93f9c475da5bc50072f64bf3f3f6b828f"] +python-magic = ["f2674dcfad52ae6c49d4803fa027809540b130db1dec928cfbb9240316831375", "f3765c0f582d2dfc72c15f3b5a82aecfae9498bd29ca840d72f37d7bd38bfcd5"] +pytz = ["32b0891edff07e28efe91284ed9c31e123d84bea3fd98e1f72be2508f43ef8d9", "d5f05e487007e29e03409f9398d074e158d920d36eb82eaf66fb1136b0c5374c"] +requests = ["502a824f31acdacb3a35b6690b5fbf0bc41d63a24a45c4004352b0242707598e", "7bf2a778576d825600030a110f3c0e3e8edc51dfaafe1c146e39a2027784957b"] +requests-oauthlib = ["bd6533330e8748e94bf0b214775fed487d309b8b8fe823dc45641ebcd9a32f57", "d3ed0c8f2e3bbc6b344fa63d6f933745ab394469da38db16bdddb461c7e25140", "dd5a0499abfefd087c6dd96693cbd5bfd28aa009719a7f85ab3fabe3956ef19a"] +requests-toolbelt = ["380606e1d10dc85c3bd47bf5a6095f815ec007be7a8b69c878507068df059e6f", "968089d4584ad4ad7c171454f0a5c6dac23971e9472521ea3b6d49d610aa6fc0"] +rsa = ["14ba45700ff1ec9eeb206a2ce76b32814958a98e372006c8fb76ba820211be66", "1a836406405730121ae9823e19c6e806c62bbad73f890574fff50efa4122c487"] +schema = ["d994b0dc4966000037b26898df638e3e2a694cc73636cb2050e652614a350687", "fa1a53fe5f3b6929725a4e81688c250f46838e25d8c1885a10a590c8c01a7b74"] +six = ["3350809f0555b11f552448330d0b52d5f24c91a322ea4a15ef22629740f3761c", "d16a0141ec1a18405cd4ce8b4613101da75da0e9a7aec5bdd4fa804d0e0eba73"] +tzlocal = ["4ebeb848845ac898da6519b9b31879cf13b6626f7184c496037b818e238f2c4e"] +uritemplate = ["01c69f4fe8ed503b2951bef85d996a9d22434d2431584b5b107b2981ff416fbd", "1b9c467a940ce9fb9f50df819e8ddd14696f89b9a8cc87ac77952ba416e0a8fd", "c02643cebe23fc8adb5e6becffe201185bf06c40bda5c0b4028a93f1527d011d"] +urllib3 = ["61bf29cada3fc2fbefad4fdf059ea4bd1b4a86d2b6d15e1c7c0b582b9752fe39", "de9529817c93f27c8ccbfead6985011db27bd0ddfcdb2d86f3f663385c6a9c22"] diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..90abcb3 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,30 @@ +[tool.poetry] +name = "prismedia" +version = "0.6.2" +description = "scripting your way to upload videos on peertube and youtube" +authors = [ + "LecygneNoir " + "Rigel Kent " +] +license = "AGPL-3.0-only" +readme = 'README.md' +repository = "https://git.lecygnenoir.info/LecygneNoir/prismedia" +homepage = "https://git.lecygnenoir.info/LecygneNoir/prismedia" + +[tool.poetry.dependencies] +python = "^2.7" +google-auth-oauthlib = "^0.2.0" +requests-toolbelt = "^0.9.1" +docopt = "^0.6.2" +google-auth = "^1.6" +google-auth-httplib2 = "^0.0.3" +tzlocal = "^1.5" +python-magic = "^0.4.15" +schema = "^0.6.8" +google-api-python-client = "^1.7" + +[tool.poetry.dev-dependencies] + +[build-system] +requires = ["poetry>=0.12"] +build-backend = "poetry.masonry.api" diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..dbbac32 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,93 @@ +cachetools==3.1.0 \ + --hash=sha256:219b7dc6024195b6f2bc3d3f884d1fef458745cd323b04165378622dcc823852 \ + --hash=sha256:9efcc9fab3b49ab833475702b55edd5ae07af1af7a4c627678980b45e459c460 +certifi==2018.11.29 \ + --hash=sha256:47f9c83ef4c0c621eaef743f133f09fa8a74a9b75f037e8624f83bd1b6626cb7 \ + --hash=sha256:993f830721089fef441cdfeb4b2c8c9df86f0c63239f06bd025a76a7daddb033 +chardet==3.0.4 \ + --hash=sha256:84ab92ed1c4d4f16916e05906b6b75a6c0fb5db821cc65e70cbd64a3e2a5eaae \ + --hash=sha256:fc323ffcaeaed0e0a02bf4d117757b98aed530d9ed4531e3e15460124c106691 +docopt==0.6.2 \ + --hash=sha256:49b3a825280bd66b3aa83585ef59c4a8c82f2c8a522dbe754a8bc8d08c85c491 +google-api-python-client==1.7.8 \ + --hash=sha256:06907006ed5ce831018f03af3852d739c0b2489cdacfda6971bcc2075c762858 \ + --hash=sha256:937eabdc3940977f712fa648a096a5142766b6d0a0f58bc603e2ac0687397ef0 +google-auth==1.6.2 \ + --hash=sha256:b6081ba9946828d6417c15ecdc723fdb7c007cdd74e140747d3876a7440f0be5 \ + --hash=sha256:e8d64e9bc8cb6f0fc5360c693f86dc9ee6964081ee702e3b5ddc937f99efc950 +google-auth-httplib2==0.0.3 \ + --hash=sha256:098fade613c25b4527b2c08fa42d11f3c2037dda8995d86de0745228e965d445 \ + --hash=sha256:f1c437842155680cf9918df9bc51c1182fda41feef88c34004bd1978c8157e08 +google-auth-oauthlib==0.2.0 \ + --hash=sha256:226d1d0960f86ba5d9efd426a70b291eaba96f47d071657e0254ea969025728a \ + --hash=sha256:81ba22acada4d13b1d83f9371ab19fd61f1250a542d21cf49e4dcf0637a7344a +httplib2==0.12.1 \ + --hash=sha256:4ba6b8fd77d0038769bf3c33c9a96a6f752bc4cdf739701fdcaf210121f399d4 +idna==2.8 \ + --hash=sha256:c357b3f628cf53ae2c4c05627ecc484553142ca23264e593d327bcde5e9c3407 \ + --hash=sha256:ea8b7f6188e6fa117537c3df7da9fc686d485087abf6ac197f9c46432f7e4a3c +oauthlib==3.0.1 \ + --hash=sha256:0ce32c5d989a1827e3f1148f98b9085ed2370fc939bf524c9c851d8714797298 \ + --hash=sha256:3e1e14f6cde7e5475128d30e97edc3bfb4dc857cb884d8714ec161fdbb3b358e +pyasn1==0.4.5 \ + --hash=sha256:061442c60842f6d11051d4fdae9bc197b64bd41573a12234a753a0cb80b4f30b \ + --hash=sha256:0ee2449bf4c4e535823acc25624c45a8b454f328d59d3f3eeb82d3567100b9bd \ + --hash=sha256:5f9fb05c33e53b9a6ee3b1ed1d292043f83df465852bec876e93b47fd2df7eed \ + --hash=sha256:65201d28e081f690a32401e6253cca4449ccacc8f3988e811fae66bd822910ee \ + --hash=sha256:79b336b073a52fa3c3d8728e78fa56b7d03138ef59f44084de5f39650265b5ff \ + --hash=sha256:8ec20f61483764de281e0b4aba7d12716189700debcfa9e7935780850bf527f3 \ + --hash=sha256:9458d0273f95d035de4c0d5e0643f25daba330582cc71bb554fe6969c015042a \ + --hash=sha256:98d97a1833a29ca61cd04a60414def8f02f406d732f9f0bcb49f769faff1b699 \ + --hash=sha256:b00d7bfb6603517e189d1ad76967c7e805139f63e43096e5f871d1277f50aea5 \ + --hash=sha256:b06c0cfd708b806ea025426aace45551f91ea7f557e0c2d4fbd9a4b346873ce0 \ + --hash=sha256:d14d05984581770333731690f5453efd4b82e1e5d824a1d7976b868a2e5c38e8 \ + --hash=sha256:da2420fe13a9452d8ae97a0e478adde1dee153b11ba832a95b223a2ba01c10f7 \ + --hash=sha256:da6b43a8c9ae93bc80e2739efb38cc776ba74a886e3e9318d65fe81a8b8a2c6e +pyasn1-modules==0.2.4 \ + --hash=sha256:136020f884635942239b33abdb63b1e0fdfb3c4bc8693f769ff1ab0908133a5b \ + --hash=sha256:1c2ce0717e099620d7d425d2bb55e68f8126d77c8ba93112f0448a212048fe76 \ + --hash=sha256:39da883a45dfc71314c48bba772be63a13946d0dd6abde326df163656a7b13e1 \ + --hash=sha256:4160b0caedf8f1675ca7b94a65900d0219c715ac745cbc0c93557a9864b19748 \ + --hash=sha256:50c5f454c29bc8a7b8bfffc0fd00fed1f9012160b4532807a33c27af91747337 \ + --hash=sha256:52c46ecb2c1e7a03fe54dc8e11d6460ec7ebdcaedba3b0fe4ba2a811521df05f \ + --hash=sha256:6db7a0510e55212b42a1f3e3553559eb214c8c8495e1018b4135d2bfb5a9169a \ + --hash=sha256:79580acf813e3b7d6e69783884e6e83ac94bf4617b36a135b85c599d8a818a7b \ + --hash=sha256:98e80b5ae1ed0d92694927a3e34df016c3b69b7bf439b32fc0a0dc516ec3653d \ + --hash=sha256:9e879981cbf4c868a2267385a56837e0d384eab2d1690e6e0c8bba28d102509e \ + --hash=sha256:a52090e8c5841ebbf08ae455146792d9ef3e8445b21055d3a3b7ed9c712b7c7c \ + --hash=sha256:c00dad1d69d8592bbbc978f5beb3e992d3bf996e6b97eeec1c8608f81221d922 \ + --hash=sha256:c226b5c17683d98498e157d6ac0098b93f9c475da5bc50072f64bf3f3f6b828f +python-magic==0.4.15 \ + --hash=sha256:f2674dcfad52ae6c49d4803fa027809540b130db1dec928cfbb9240316831375 \ + --hash=sha256:f3765c0f582d2dfc72c15f3b5a82aecfae9498bd29ca840d72f37d7bd38bfcd5 +pytz==2018.9 \ + --hash=sha256:32b0891edff07e28efe91284ed9c31e123d84bea3fd98e1f72be2508f43ef8d9 \ + --hash=sha256:d5f05e487007e29e03409f9398d074e158d920d36eb82eaf66fb1136b0c5374c +requests==2.21.0 \ + --hash=sha256:502a824f31acdacb3a35b6690b5fbf0bc41d63a24a45c4004352b0242707598e \ + --hash=sha256:7bf2a778576d825600030a110f3c0e3e8edc51dfaafe1c146e39a2027784957b +requests-oauthlib==1.2.0 \ + --hash=sha256:bd6533330e8748e94bf0b214775fed487d309b8b8fe823dc45641ebcd9a32f57 \ + --hash=sha256:d3ed0c8f2e3bbc6b344fa63d6f933745ab394469da38db16bdddb461c7e25140 \ + --hash=sha256:dd5a0499abfefd087c6dd96693cbd5bfd28aa009719a7f85ab3fabe3956ef19a +requests-toolbelt==0.9.1 \ + --hash=sha256:380606e1d10dc85c3bd47bf5a6095f815ec007be7a8b69c878507068df059e6f \ + --hash=sha256:968089d4584ad4ad7c171454f0a5c6dac23971e9472521ea3b6d49d610aa6fc0 +rsa==4.0 \ + --hash=sha256:14ba45700ff1ec9eeb206a2ce76b32814958a98e372006c8fb76ba820211be66 \ + --hash=sha256:1a836406405730121ae9823e19c6e806c62bbad73f890574fff50efa4122c487 +schema==0.6.8 \ + --hash=sha256:d994b0dc4966000037b26898df638e3e2a694cc73636cb2050e652614a350687 \ + --hash=sha256:fa1a53fe5f3b6929725a4e81688c250f46838e25d8c1885a10a590c8c01a7b74 +six==1.12.0 \ + --hash=sha256:3350809f0555b11f552448330d0b52d5f24c91a322ea4a15ef22629740f3761c \ + --hash=sha256:d16a0141ec1a18405cd4ce8b4613101da75da0e9a7aec5bdd4fa804d0e0eba73 +tzlocal==1.5.1 \ + --hash=sha256:4ebeb848845ac898da6519b9b31879cf13b6626f7184c496037b818e238f2c4e +uritemplate==3.0.0 \ + --hash=sha256:01c69f4fe8ed503b2951bef85d996a9d22434d2431584b5b107b2981ff416fbd \ + --hash=sha256:1b9c467a940ce9fb9f50df819e8ddd14696f89b9a8cc87ac77952ba416e0a8fd \ + --hash=sha256:c02643cebe23fc8adb5e6becffe201185bf06c40bda5c0b4028a93f1527d011d +urllib3==1.24.1 \ + --hash=sha256:61bf29cada3fc2fbefad4fdf059ea4bd1b4a86d2b6d15e1c7c0b582b9752fe39 \ + --hash=sha256:de9529817c93f27c8ccbfead6985011db27bd0ddfcdb2d86f3f663385c6a9c22 -- 2.20.1 From 4b970fed9962eb2bbe06ff5c236e3620f05ffcdd Mon Sep 17 00:00:00 2001 From: Rigel Kent Date: Mon, 18 Feb 2019 15:20:42 +0100 Subject: [PATCH 10/13] moved prismedia_upload in a module, added poetry command --- README.md | 32 ++++++++++++---------- prismedia/__init__.py | 1 + {lib => prismedia}/pt_upload.py | 0 prismedia_upload.py => prismedia/upload.py | 18 ++++++------ {lib => prismedia}/utils.py | 0 {lib => prismedia}/yt_upload.py | 0 pyproject.toml | 9 +++++- 7 files changed, 34 insertions(+), 26 deletions(-) create mode 100644 prismedia/__init__.py rename {lib => prismedia}/pt_upload.py (100%) rename prismedia_upload.py => prismedia/upload.py (97%) rename {lib => prismedia}/utils.py (100%) rename {lib => prismedia}/yt_upload.py (100%) diff --git a/README.md b/README.md index c643fad..5761e06 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # Prismedia -Scripting your way to upload videos to peertube and youtube. +Scripting your way to upload videos to peertube and youtube. Works only with Python 2 so far. ## Dependencies @@ -38,18 +38,20 @@ You can set ``OAUTHLIB_INSECURE_TRANSPORT`` to 1 if you do not use https (not re ### Youtube -Youtube uses combination of oauth and API access to identify. +Youtube uses OAuth 2.0 to restrict its API access to identified users. Registering a client is documented [here](https://developers.google.com/youtube/v3/guides/uploading_a_video). -**Credentials** -The first time you connect, prismedia will open your browser to as you to authenticate to -Youtube and allow the app to use your Youtube channel. -**It is here you choose which channel you will upload to**. -Once authenticated, the token is stored inside the file ``.youtube_credentials.json``. -Prismedia will try to use this file at each launch, and re-ask for authentication if it does not exist. +**Credentials:** the first time you connect, prismedia will open your browser +to as you to authenticate to Youtube and allow the app to use your Youtube +channel. -**Oauth**: -The default youtube_secret.json should allow you to upload some videos. -If you plan an larger usage, please consider creating your own youtube_secret file: +**It is here you choose which channel you will upload to:** once authenticated, +the token is stored inside the file `.youtube_credentials.json`. Prismedia will +try to use this file at each launch, and re-ask for authentication if it does +not exist. + +**OAuth 2.0**: the default `youtube_secret.json` should allow you to upload +some videos. If you plan a more frequent usage, please consider creating your +own `youtube_secret` file: - Go to the [Google console](https://console.developers.google.com/). - Create project. @@ -69,26 +71,26 @@ Supports only mp4 for cross compatibility between Youtube and Peertube. Simply upload a video: ``` -./prismedia_upload.py --file="yourvideo.mp4" +python -m prismedia.upload --file="yourvideo.mp4" ``` Specify description and tags: ``` -./prismedia_upload.py --file="yourvideo.mp4" -d "My supa description" -t "tag1,tag2,foo" +python -m prismedia.upload --file="yourvideo.mp4" -d "My supa description" -t "tag1,tag2,foo" ``` Provide a thumbnail: ``` -./prismedia_upload.py --file="yourvideo.mp4" -d "Video with thumbnail" --thumbnail="/path/to/your/thumbnail.jpg" +python -m prismedia.upload --file="yourvideo.mp4" -d "Video with thumbnail" --thumbnail="/path/to/your/thumbnail.jpg" ``` Use a NFO file to specify your video options: ``` -./prismedia_upload.py --file="yourvideo.mp4" --nfo /path/to/your/nfo.txt +python -m prismedia.upload --file="yourvideo.mp4" --nfo /path/to/your/nfo.txt ``` Use --help to get all available options: diff --git a/prismedia/__init__.py b/prismedia/__init__.py new file mode 100644 index 0000000..37de3b8 --- /dev/null +++ b/prismedia/__init__.py @@ -0,0 +1 @@ +from . import upload diff --git a/lib/pt_upload.py b/prismedia/pt_upload.py similarity index 100% rename from lib/pt_upload.py rename to prismedia/pt_upload.py diff --git a/prismedia_upload.py b/prismedia/upload.py similarity index 97% rename from prismedia_upload.py rename to prismedia/upload.py index 00f64ae..8d424b4 100755 --- a/prismedia_upload.py +++ b/prismedia/upload.py @@ -59,8 +59,6 @@ Languages: Japanese, Korean, Mandarin, Portuguese, Punjabi, Russian, Spanish """ -from os.path import dirname, realpath -import sys import datetime import locale import logging @@ -68,12 +66,9 @@ logging.basicConfig(format='%(asctime)s %(message)s', level=logging.INFO) from docopt import docopt -# Allows a relative import from the parent folder -sys.path.insert(0, dirname(realpath(__file__)) + "/lib") - -import yt_upload -import pt_upload -import utils +from . import yt_upload +from . import pt_upload +from . import utils try: # noinspection PyUnresolvedReferences @@ -158,8 +153,7 @@ def validateThumbnail(thumbnail): else: return False -if __name__ == '__main__': - +def main(): options = docopt(__doc__, version=VERSION) schema = Schema({ @@ -228,3 +222,7 @@ if __name__ == '__main__': yt_upload.run(options) if options.get('--platform') is None or "peertube" in options.get('--platform'): pt_upload.run(options) + +if __name__ == '__main__': + main() + diff --git a/lib/utils.py b/prismedia/utils.py similarity index 100% rename from lib/utils.py rename to prismedia/utils.py diff --git a/lib/yt_upload.py b/prismedia/yt_upload.py similarity index 100% rename from lib/yt_upload.py rename to prismedia/yt_upload.py diff --git a/pyproject.toml b/pyproject.toml index 90abcb3..7f162b0 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -3,14 +3,18 @@ name = "prismedia" version = "0.6.2" description = "scripting your way to upload videos on peertube and youtube" authors = [ - "LecygneNoir " + "LecygneNoir ", "Rigel Kent " ] + license = "AGPL-3.0-only" + readme = 'README.md' repository = "https://git.lecygnenoir.info/LecygneNoir/prismedia" homepage = "https://git.lecygnenoir.info/LecygneNoir/prismedia" +keywords = ['peertube', 'youtube'] + [tool.poetry.dependencies] python = "^2.7" google-auth-oauthlib = "^0.2.0" @@ -28,3 +32,6 @@ google-api-python-client = "^1.7" [build-system] requires = ["poetry>=0.12"] build-backend = "poetry.masonry.api" + +[tool.poetry.scripts] +prismedia = 'prismedia.upload:main' -- 2.20.1 From 80a7f071948c095f2f8ed473d1f27ce1d691086e Mon Sep 17 00:00:00 2001 From: Rigel Kent Date: Tue, 19 Feb 2019 11:24:43 +0100 Subject: [PATCH 11/13] move sample file into config submodule, genconfig command instead --- README.md | 3 ++- prismedia/__init__.py | 1 + .../config/nfo_example.txt | 0 .../config/peertube_secret.sample | 0 .../config/youtube_secret.json.sample | 0 prismedia/genconfig.py | 15 +++++++++++++++ prismedia/utils.py | 12 ++++++++++-- 7 files changed, 28 insertions(+), 3 deletions(-) rename nfo_example.txt => prismedia/config/nfo_example.txt (100%) rename peertube_secret.sample => prismedia/config/peertube_secret.sample (100%) rename youtube_secret.json.sample => prismedia/config/youtube_secret.json.sample (100%) create mode 100644 prismedia/genconfig.py diff --git a/README.md b/README.md index 5761e06..619bc51 100644 --- a/README.md +++ b/README.md @@ -28,7 +28,8 @@ poetry install # installs the dependency in a virtualenv specific to the project ## Configuration -Edit `peertube_secret` and `youtube_secret.json` with your credentials. +Generate sample files with `python -m prismedia.genconfig`. Edit +`peertube_secret` and `youtube_secret.json` with your credentials. ### Peertube diff --git a/prismedia/__init__.py b/prismedia/__init__.py index 37de3b8..4c3ebaf 100644 --- a/prismedia/__init__.py +++ b/prismedia/__init__.py @@ -1 +1,2 @@ from . import upload +from . import genconfig diff --git a/nfo_example.txt b/prismedia/config/nfo_example.txt similarity index 100% rename from nfo_example.txt rename to prismedia/config/nfo_example.txt diff --git a/peertube_secret.sample b/prismedia/config/peertube_secret.sample similarity index 100% rename from peertube_secret.sample rename to prismedia/config/peertube_secret.sample diff --git a/youtube_secret.json.sample b/prismedia/config/youtube_secret.json.sample similarity index 100% rename from youtube_secret.json.sample rename to prismedia/config/youtube_secret.json.sample diff --git a/prismedia/genconfig.py b/prismedia/genconfig.py new file mode 100644 index 0000000..f03e423 --- /dev/null +++ b/prismedia/genconfig.py @@ -0,0 +1,15 @@ +from os.path import join, abspath, isfile, dirname +from os import listdir +from shutil import copyfile + + +def genconfig(): + path = join(dirname(__file__), 'config') + files = [f for f in listdir(path) if isfile(join(path, f))] + + for f in files: + copyfile(join(path, f), f) + + +if __name__ == '__main__': + genconfig() diff --git a/prismedia/utils.py b/prismedia/utils.py index 1602ab6..f2984b7 100644 --- a/prismedia/utils.py +++ b/prismedia/utils.py @@ -107,6 +107,7 @@ def remove_empty_kwargs(**kwargs): good_kwargs[key] = value return good_kwargs + def searchThumbnail(options): video_directory = dirname(options.get('--file')) + "/" # First, check for thumbnail based on videoname @@ -124,6 +125,7 @@ def searchThumbnail(options): options['--thumbnail'] = video_directory + video_file + ".jpeg" return options + # return the nfo as a RawConfigParser object def loadNFO(options): video_directory = dirname(options.get('--file')) + "/" @@ -168,10 +170,12 @@ def loadNFO(options): logging.info("No suitable NFO found, skipping.") return False + def parseNFO(options): nfo = loadNFO(options) if nfo: - # We need to check all options and replace it with the nfo value if not defined (None or False) + # We need to check all options and replace it with the nfo value if not + # defined (None or False) for key, value in options.iteritems(): key = key.replace("-", "") try: @@ -188,9 +192,11 @@ def parseNFO(options): exit(1) return options + def upcaseFirstLetter(s): return s[0].upper() + s[1:] + def cleanString(toclean): toclean = toclean.decode('utf-8') toclean = unidecode.unidecode(toclean) @@ -198,10 +204,11 @@ def cleanString(toclean): return cleaned + def decodeArgumentStrings(options, encoding): # Python crash when decoding from UTF-8 to UTF-8, so we prevent this if "utf-8" == encoding.lower(): - return; + return if options["--name"] is not None: options["--name"] = options["--name"].decode(encoding) @@ -211,3 +218,4 @@ def decodeArgumentStrings(options, encoding): if options["--tags"] is not None: options["--tags"] = options["--tags"].decode(encoding) + -- 2.20.1 From b8e7727c0cdd909d1cd8fb67bf2dd7ea381d2f3e Mon Sep 17 00:00:00 2001 From: Rigel Kent Date: Tue, 19 Feb 2019 12:02:54 +0100 Subject: [PATCH 12/13] add compatibility with python 3 --- .python-version | 1 - README.md | 18 ++++---- poetry.lock | 75 ++++++++++++++++++++------------ prismedia/__init__.py | 3 ++ prismedia/__main__.py | 2 + prismedia/config/nfo_example.txt | 4 +- prismedia/pt_upload.py | 14 ++++-- prismedia/upload.py | 13 +++++- prismedia/utils.py | 26 ++++++----- prismedia/yt_upload.py | 19 ++++---- pyproject.toml | 8 ++-- requirements.txt | 49 +++++++++++---------- 12 files changed, 142 insertions(+), 90 deletions(-) delete mode 100644 .python-version create mode 100644 prismedia/__main__.py diff --git a/.python-version b/.python-version deleted file mode 100644 index f24054f..0000000 --- a/.python-version +++ /dev/null @@ -1 +0,0 @@ -2.7.15 diff --git a/README.md b/README.md index 619bc51..b002497 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # Prismedia -Scripting your way to upload videos to peertube and youtube. Works only with Python 2 so far. +Scripting your way to upload videos to peertube and youtube. Works with Python 2.7 and 3.3+. ## Dependencies @@ -15,15 +15,15 @@ Search in your system package manager, otherwise use ``pip install --upgrade`` f - python-magic-bin - requests-toolbelt - tzlocal + - configparser + - future Otherwise, you can use the requirements file with `pip install -r requirements.txt`. (*note:* requirements are generated via `poetry export -f requirements.txt`) -Otherwise, you can use [pyenv](https://github.com/pyenv/pyenv) and [poetry](https://poetry.eustace.io/): +Otherwise, you can use [poetry](https://poetry.eustace.io/): ``` -pyenv install # installs the python version specified in .python-version -pyenv shell # activates the python version for the session -poetry install # installs the dependency in a virtualenv specific to the project +poetry install # installs the dependency in the current virtualenv, or creates one specific to the project if no virtualenv is currently active ``` ## Configuration @@ -72,26 +72,26 @@ Supports only mp4 for cross compatibility between Youtube and Peertube. Simply upload a video: ``` -python -m prismedia.upload --file="yourvideo.mp4" +python -m prismedia --file="yourvideo.mp4" ``` Specify description and tags: ``` -python -m prismedia.upload --file="yourvideo.mp4" -d "My supa description" -t "tag1,tag2,foo" +python -m prismedia --file="yourvideo.mp4" -d "My supa description" -t "tag1,tag2,foo" ``` Provide a thumbnail: ``` -python -m prismedia.upload --file="yourvideo.mp4" -d "Video with thumbnail" --thumbnail="/path/to/your/thumbnail.jpg" +python -m prismedia --file="yourvideo.mp4" -d "Video with thumbnail" --thumbnail="/path/to/your/thumbnail.jpg" ``` Use a NFO file to specify your video options: ``` -python -m prismedia.upload --file="yourvideo.mp4" --nfo /path/to/your/nfo.txt +python -m prismedia --file="yourvideo.mp4" --nfo /path/to/your/nfo.txt ``` Use --help to get all available options: diff --git a/poetry.lock b/poetry.lock index 715710f..5e3565a 100644 --- a/poetry.lock +++ b/poetry.lock @@ -22,6 +22,14 @@ optional = false python-versions = "*" version = "3.0.4" +[[package]] +category = "main" +description = "Updated configparser from Python 3.7 for Python 2.6+." +name = "configparser" +optional = false +python-versions = ">=2.6" +version = "3.7.1" + [[package]] category = "main" description = "Pythonic argument parser, that will make you smile" @@ -30,13 +38,21 @@ optional = false python-versions = "*" version = "0.6.2" +[[package]] +category = "main" +description = "Clean single-source support for Python 3 and 2" +name = "future" +optional = false +python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*" +version = "0.17.1" + [[package]] category = "main" description = "Google API Client Library for Python" name = "google-api-python-client" optional = false -python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*" -version = "1.7.8" +python-versions = "*" +version = "1.7.6" [package.dependencies] google-auth = ">=1.4.1" @@ -50,8 +66,8 @@ category = "main" description = "Google Authentication Library" name = "google-auth" optional = false -python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*" -version = "1.6.2" +python-versions = "*" +version = "1.6.1" [package.dependencies] cachetools = ">=2.0.0" @@ -99,21 +115,22 @@ category = "main" description = "Internationalized Domain Names in Applications (IDNA)" name = "idna" optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" -version = "2.8" +python-versions = "*" +version = "2.6" [[package]] category = "main" description = "A generic, spec-compliant, thorough implementation of the OAuth request-signing logic" name = "oauthlib" optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" -version = "3.0.1" +python-versions = "*" +version = "2.1.0" [package.extras] rsa = ["cryptography"] signals = ["blinker"] signedtoken = ["cryptography", "pyjwt (>=1.0.0)"] +test = ["nose", "unittest2", "cryptography", "mock", "pyjwt (>=1.0.0)", "blinker"] [[package]] category = "main" @@ -155,17 +172,17 @@ category = "main" description = "Python HTTP for Humans." name = "requests" optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" -version = "2.21.0" +python-versions = "*" +version = "2.18.4" [package.dependencies] certifi = ">=2017.4.17" chardet = ">=3.0.2,<3.1.0" -idna = ">=2.5,<2.9" -urllib3 = ">=1.21.1,<1.25" +idna = ">=2.5,<2.7" +urllib3 = ">=1.21.1,<1.23" [package.extras] -security = ["pyOpenSSL (>=0.14)", "cryptography (>=1.3.4)", "idna (>=2.0.0)"] +security = ["cryptography (>=1.3.4)", "idna (>=2.0.0)", "pyOpenSSL (>=0.14)"] socks = ["PySocks (>=1.5.6,<1.5.7 || >1.5.7)", "win-inet-pton"] [[package]] @@ -173,15 +190,15 @@ category = "main" description = "OAuthlib authentication support for Requests." name = "requests-oauthlib" optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" -version = "1.2.0" +python-versions = "*" +version = "0.8.0" [package.dependencies] -oauthlib = ">=3.0.0" +oauthlib = ">=0.6.2" requests = ">=2.0.0" [package.extras] -rsa = ["oauthlib (>=3.0.0)"] +rsa = ["oauthlib (>=0.6.2)", "requests (>=2.0.0)"] [[package]] category = "main" @@ -245,39 +262,41 @@ category = "main" description = "HTTP library with thread-safe connection pooling, file post, and more." name = "urllib3" optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, <4" -version = "1.24.1" +python-versions = "*" +version = "1.22" [package.extras] secure = ["pyOpenSSL (>=0.14)", "cryptography (>=1.3.4)", "idna (>=2.0.0)", "certifi", "ipaddress"] socks = ["PySocks (>=1.5.6,<1.5.7 || >1.5.7,<2.0)"] [metadata] -content-hash = "9e8128dce8edb5dddbe82929fdda23e4ff9ef4f2c400f033d92aa752f4de366b" -python-versions = "^2.7" +content-hash = "6d04698286eb827ccc77b1152f758c6f4add28ea6010ea65eccf227aadc20e1e" +python-versions = "~2.7 || ^3.3" [metadata.hashes] cachetools = ["219b7dc6024195b6f2bc3d3f884d1fef458745cd323b04165378622dcc823852", "9efcc9fab3b49ab833475702b55edd5ae07af1af7a4c627678980b45e459c460"] certifi = ["47f9c83ef4c0c621eaef743f133f09fa8a74a9b75f037e8624f83bd1b6626cb7", "993f830721089fef441cdfeb4b2c8c9df86f0c63239f06bd025a76a7daddb033"] chardet = ["84ab92ed1c4d4f16916e05906b6b75a6c0fb5db821cc65e70cbd64a3e2a5eaae", "fc323ffcaeaed0e0a02bf4d117757b98aed530d9ed4531e3e15460124c106691"] +configparser = ["5bd5fa2a491dc3cfe920a3f2a107510d65eceae10e9c6e547b90261a4710df32", "c114ff90ee2e762db972fa205f02491b1f5cf3ff950decd8542c62970c9bedac", "df28e045fbff307a28795b18df6ac8662be3219435560ddb068c283afab1ea7a"] docopt = ["49b3a825280bd66b3aa83585ef59c4a8c82f2c8a522dbe754a8bc8d08c85c491"] -google-api-python-client = ["06907006ed5ce831018f03af3852d739c0b2489cdacfda6971bcc2075c762858", "937eabdc3940977f712fa648a096a5142766b6d0a0f58bc603e2ac0687397ef0"] -google-auth = ["b6081ba9946828d6417c15ecdc723fdb7c007cdd74e140747d3876a7440f0be5", "e8d64e9bc8cb6f0fc5360c693f86dc9ee6964081ee702e3b5ddc937f99efc950"] +future = ["67045236dcfd6816dc439556d009594abf643e5eb48992e36beac09c2ca659b8"] +google-api-python-client = ["51dc9139aa06fd0b1339a22b6b1c9fe74cb891b3dd803e8c464c5a18a8de23dc", "bf98b066fb6e4e6da1f2f11d6cb0bb947de156aef8562a32b0692e7073d38593"] +google-auth = ["494e747bdc2cdeb0fa6ef85118de2ea1a563f160294cce05048c6ff563fda1bb", "b08a27888e9d1c17a891b3688aacc9c6f2019d7f6c5a2e73588e6bb9a2c0fa98"] google-auth-httplib2 = ["098fade613c25b4527b2c08fa42d11f3c2037dda8995d86de0745228e965d445", "f1c437842155680cf9918df9bc51c1182fda41feef88c34004bd1978c8157e08"] google-auth-oauthlib = ["226d1d0960f86ba5d9efd426a70b291eaba96f47d071657e0254ea969025728a", "81ba22acada4d13b1d83f9371ab19fd61f1250a542d21cf49e4dcf0637a7344a"] httplib2 = ["4ba6b8fd77d0038769bf3c33c9a96a6f752bc4cdf739701fdcaf210121f399d4"] -idna = ["c357b3f628cf53ae2c4c05627ecc484553142ca23264e593d327bcde5e9c3407", "ea8b7f6188e6fa117537c3df7da9fc686d485087abf6ac197f9c46432f7e4a3c"] -oauthlib = ["0ce32c5d989a1827e3f1148f98b9085ed2370fc939bf524c9c851d8714797298", "3e1e14f6cde7e5475128d30e97edc3bfb4dc857cb884d8714ec161fdbb3b358e"] +idna = ["2c6a5de3089009e3da7c5dde64a141dbc8551d5b7f6cf4ed7c2568d0cc520a8f", "8c7309c718f94b3a625cb648ace320157ad16ff131ae0af362c9f21b80ef6ec4"] +oauthlib = ["ac35665a61c1685c56336bda97d5eefa246f1202618a1d6f34fccb1bdd404162", "d883b36b21a6ad813953803edfa563b1b579d79ca758fe950d1bc9e8b326025b"] pyasn1 = ["061442c60842f6d11051d4fdae9bc197b64bd41573a12234a753a0cb80b4f30b", "0ee2449bf4c4e535823acc25624c45a8b454f328d59d3f3eeb82d3567100b9bd", "5f9fb05c33e53b9a6ee3b1ed1d292043f83df465852bec876e93b47fd2df7eed", "65201d28e081f690a32401e6253cca4449ccacc8f3988e811fae66bd822910ee", "79b336b073a52fa3c3d8728e78fa56b7d03138ef59f44084de5f39650265b5ff", "8ec20f61483764de281e0b4aba7d12716189700debcfa9e7935780850bf527f3", "9458d0273f95d035de4c0d5e0643f25daba330582cc71bb554fe6969c015042a", "98d97a1833a29ca61cd04a60414def8f02f406d732f9f0bcb49f769faff1b699", "b00d7bfb6603517e189d1ad76967c7e805139f63e43096e5f871d1277f50aea5", "b06c0cfd708b806ea025426aace45551f91ea7f557e0c2d4fbd9a4b346873ce0", "d14d05984581770333731690f5453efd4b82e1e5d824a1d7976b868a2e5c38e8", "da2420fe13a9452d8ae97a0e478adde1dee153b11ba832a95b223a2ba01c10f7", "da6b43a8c9ae93bc80e2739efb38cc776ba74a886e3e9318d65fe81a8b8a2c6e"] pyasn1-modules = ["136020f884635942239b33abdb63b1e0fdfb3c4bc8693f769ff1ab0908133a5b", "1c2ce0717e099620d7d425d2bb55e68f8126d77c8ba93112f0448a212048fe76", "39da883a45dfc71314c48bba772be63a13946d0dd6abde326df163656a7b13e1", "4160b0caedf8f1675ca7b94a65900d0219c715ac745cbc0c93557a9864b19748", "50c5f454c29bc8a7b8bfffc0fd00fed1f9012160b4532807a33c27af91747337", "52c46ecb2c1e7a03fe54dc8e11d6460ec7ebdcaedba3b0fe4ba2a811521df05f", "6db7a0510e55212b42a1f3e3553559eb214c8c8495e1018b4135d2bfb5a9169a", "79580acf813e3b7d6e69783884e6e83ac94bf4617b36a135b85c599d8a818a7b", "98e80b5ae1ed0d92694927a3e34df016c3b69b7bf439b32fc0a0dc516ec3653d", "9e879981cbf4c868a2267385a56837e0d384eab2d1690e6e0c8bba28d102509e", "a52090e8c5841ebbf08ae455146792d9ef3e8445b21055d3a3b7ed9c712b7c7c", "c00dad1d69d8592bbbc978f5beb3e992d3bf996e6b97eeec1c8608f81221d922", "c226b5c17683d98498e157d6ac0098b93f9c475da5bc50072f64bf3f3f6b828f"] python-magic = ["f2674dcfad52ae6c49d4803fa027809540b130db1dec928cfbb9240316831375", "f3765c0f582d2dfc72c15f3b5a82aecfae9498bd29ca840d72f37d7bd38bfcd5"] pytz = ["32b0891edff07e28efe91284ed9c31e123d84bea3fd98e1f72be2508f43ef8d9", "d5f05e487007e29e03409f9398d074e158d920d36eb82eaf66fb1136b0c5374c"] -requests = ["502a824f31acdacb3a35b6690b5fbf0bc41d63a24a45c4004352b0242707598e", "7bf2a778576d825600030a110f3c0e3e8edc51dfaafe1c146e39a2027784957b"] -requests-oauthlib = ["bd6533330e8748e94bf0b214775fed487d309b8b8fe823dc45641ebcd9a32f57", "d3ed0c8f2e3bbc6b344fa63d6f933745ab394469da38db16bdddb461c7e25140", "dd5a0499abfefd087c6dd96693cbd5bfd28aa009719a7f85ab3fabe3956ef19a"] +requests = ["6a1b267aa90cac58ac3a765d067950e7dbbf75b1da07e895d1f594193a40a38b", "9c443e7324ba5b85070c4a818ade28bfabedf16ea10206da1132edaa6dda237e"] +requests-oauthlib = ["50a8ae2ce8273e384895972b56193c7409601a66d4975774c60c2aed869639ca", "883ac416757eada6d3d07054ec7092ac21c7f35cb1d2cf82faf205637081f468"] requests-toolbelt = ["380606e1d10dc85c3bd47bf5a6095f815ec007be7a8b69c878507068df059e6f", "968089d4584ad4ad7c171454f0a5c6dac23971e9472521ea3b6d49d610aa6fc0"] rsa = ["14ba45700ff1ec9eeb206a2ce76b32814958a98e372006c8fb76ba820211be66", "1a836406405730121ae9823e19c6e806c62bbad73f890574fff50efa4122c487"] schema = ["d994b0dc4966000037b26898df638e3e2a694cc73636cb2050e652614a350687", "fa1a53fe5f3b6929725a4e81688c250f46838e25d8c1885a10a590c8c01a7b74"] six = ["3350809f0555b11f552448330d0b52d5f24c91a322ea4a15ef22629740f3761c", "d16a0141ec1a18405cd4ce8b4613101da75da0e9a7aec5bdd4fa804d0e0eba73"] tzlocal = ["4ebeb848845ac898da6519b9b31879cf13b6626f7184c496037b818e238f2c4e"] uritemplate = ["01c69f4fe8ed503b2951bef85d996a9d22434d2431584b5b107b2981ff416fbd", "1b9c467a940ce9fb9f50df819e8ddd14696f89b9a8cc87ac77952ba416e0a8fd", "c02643cebe23fc8adb5e6becffe201185bf06c40bda5c0b4028a93f1527d011d"] -urllib3 = ["61bf29cada3fc2fbefad4fdf059ea4bd1b4a86d2b6d15e1c7c0b582b9752fe39", "de9529817c93f27c8ccbfead6985011db27bd0ddfcdb2d86f3f663385c6a9c22"] +urllib3 = ["06330f386d6e4b195fbfc736b297f58c5a892e4440e54d294d7004e3a9bbea1b", "cc44da8e1145637334317feebd728bd869a35285b93cbb4cca2577da7e62db4f"] diff --git a/prismedia/__init__.py b/prismedia/__init__.py index 4c3ebaf..7ec26e8 100644 --- a/prismedia/__init__.py +++ b/prismedia/__init__.py @@ -1,2 +1,5 @@ +from future import standard_library +standard_library.install_aliases() + from . import upload from . import genconfig diff --git a/prismedia/__main__.py b/prismedia/__main__.py new file mode 100644 index 0000000..858cea7 --- /dev/null +++ b/prismedia/__main__.py @@ -0,0 +1,2 @@ +from .upload import main +main() diff --git a/prismedia/config/nfo_example.txt b/prismedia/config/nfo_example.txt index 5fcfc51..edee575 100644 --- a/prismedia/config/nfo_example.txt +++ b/prismedia/config/nfo_example.txt @@ -9,7 +9,7 @@ name = videoname description = Your complete video description Multilines description - should be wrote with a blank space + should be written with a blank space at the beginning of the line :) tags = list of tags, comma separated category = Films @@ -22,4 +22,4 @@ playlistCreate = True nsfw = True platform = youtube, peertube language = French -publishAt=2034-05-07T19:00:00 \ No newline at end of file +publishAt=2034-05-07T19:00:00 diff --git a/prismedia/pt_upload.py b/prismedia/pt_upload.py index ad0a36a..e6acd92 100644 --- a/prismedia/pt_upload.py +++ b/prismedia/pt_upload.py @@ -1,4 +1,3 @@ -#!/usr/bin/env python2 # coding: utf-8 import os @@ -10,12 +9,19 @@ import pytz from os.path import splitext, basename, abspath from tzlocal import get_localzone -from ConfigParser import RawConfigParser from requests_oauthlib import OAuth2Session from oauthlib.oauth2 import LegacyApplicationClient from requests_toolbelt.multipart.encoder import MultipartEncoder -import utils +from . import utils + +from six.moves import configparser +import six + +if six.PY2: + ConfigParser = configparser.SafeConfigParser +else: + ConfigParser = configparser.ConfigParser PEERTUBE_SECRETS_FILE = 'peertube_secret' PEERTUBE_PRIVACY = { @@ -209,7 +215,7 @@ def upload_video(oauth, secret, options): def run(options): - secret = RawConfigParser() + secret = ConfigParser() try: secret.read(PEERTUBE_SECRETS_FILE) except Exception as e: diff --git a/prismedia/upload.py b/prismedia/upload.py index 8d424b4..14b0d3b 100755 --- a/prismedia/upload.py +++ b/prismedia/upload.py @@ -2,7 +2,7 @@ # coding: utf-8 """ -prismedia_upload - tool to upload videos to Peertube and Youtube +prismedia - tool to upload videos to Peertube and Youtube Usage: prismedia_upload.py --file= [options] @@ -103,6 +103,7 @@ VALID_LANGUAGES = ('arabic', 'english', 'french', 'japanese', 'korean', 'mandarin', 'portuguese', 'punjabi', 'russian', 'spanish') + def validateVideo(path): supported_types = ['video/mp4'] if magic.from_file(path, mime=True) in supported_types: @@ -110,18 +111,21 @@ def validateVideo(path): else: return False + def validateCategory(category): if category.lower() in VALID_CATEGORIES: return True else: return False + def validatePrivacy(privacy): if privacy.lower() in VALID_PRIVACY_STATUSES: return True else: return False + def validatePlatform(platform): for plfrm in platform.split(','): if plfrm.lower().replace(" ", "") not in VALID_PLATFORM: @@ -129,12 +133,14 @@ def validatePlatform(platform): return True + def validateLanguage(language): if language.lower() in VALID_LANGUAGES: return True else: return False + def validatePublish(publish): # Check date format and if date is future try: @@ -146,6 +152,7 @@ def validatePublish(publish): return False return True + def validateThumbnail(thumbnail): supported_types = ['image/jpg', 'image/jpeg'] if magic.from_file(thumbnail, mime=True) in supported_types: @@ -153,6 +160,7 @@ def validateThumbnail(thumbnail): else: return False + def main(): options = docopt(__doc__, version=VERSION) @@ -223,6 +231,9 @@ def main(): if options.get('--platform') is None or "peertube" in options.get('--platform'): pt_upload.run(options) + if __name__ == '__main__': + import warnings + warnings.warn("use 'python -m prismedia', not 'python -m prismedia.upload'", DeprecationWarning) main() diff --git a/prismedia/utils.py b/prismedia/utils.py index f2984b7..d4f84f7 100644 --- a/prismedia/utils.py +++ b/prismedia/utils.py @@ -1,4 +1,3 @@ -#!/usr/bin/python # coding: utf-8 from ConfigParser import RawConfigParser, NoOptionError, NoSectionError @@ -8,6 +7,13 @@ from os import devnull from subprocess import check_call, CalledProcessError, STDOUT import unidecode import logging +from six.moves import configparser +import six + +if six.PY2: + ConfigParser = configparser.SafeConfigParser +else: + ConfigParser = configparser.ConfigParser ### CATEGORIES ### YOUTUBE_CATEGORY = { @@ -102,7 +108,7 @@ def getLanguage(language, platform): def remove_empty_kwargs(**kwargs): good_kwargs = {} if kwargs is not None: - for key, value in kwargs.iteritems(): + for key, value in viewitems(kwargs): if value: good_kwargs[key] = value return good_kwargs @@ -126,14 +132,14 @@ def searchThumbnail(options): return options -# return the nfo as a RawConfigParser object +# return the nfo as a ConfigParser object def loadNFO(options): video_directory = dirname(options.get('--file')) + "/" if options.get('--nfo'): try: logging.info("Using " + options.get('--nfo') + " as NFO, loading...") if isfile(options.get('--nfo')): - nfo = RawConfigParser() + nfo = ConfigParser() nfo.read(options.get('--nfo')) return nfo else: @@ -148,7 +154,7 @@ def loadNFO(options): if isfile(nfo_file): try: logging.info("Using " + nfo_file + " as NFO, loading...") - nfo = RawConfigParser() + nfo = ConfigParser() nfo.read(nfo_file) return nfo except Exception as e: @@ -161,7 +167,7 @@ def loadNFO(options): if isfile(nfo_file): try: logging.info("Using " + nfo_file + " as NFO, loading...") - nfo = RawConfigParser() + nfo = ConfigParser() nfo.read(nfo_file) return nfo except Exception as e: @@ -176,7 +182,7 @@ def parseNFO(options): if nfo: # We need to check all options and replace it with the nfo value if not # defined (None or False) - for key, value in options.iteritems(): + for key, value in viewitems(options): key = key.replace("-", "") try: # get string options @@ -185,10 +191,10 @@ def parseNFO(options): # get boolean options elif value is False and nfo.getboolean('video', key): options['--' + key] = nfo.getboolean('video', key) - except NoOptionError: + except configparser.NoOptionError: continue - except NoSectionError: - logging.error("Given NFO file miss section [video], please check syntax of your NFO.") + except configparser.NoSectionError: + logging.error("Given NFO file misses section [video], please check the syntax of your NFO.") exit(1) return options diff --git a/prismedia/yt_upload.py b/prismedia/yt_upload.py index 0dfbc57..4ea30a9 100644 --- a/prismedia/yt_upload.py +++ b/prismedia/yt_upload.py @@ -1,8 +1,7 @@ -#!/usr/bin/env python2 # coding: utf-8 # From Youtube samples : https://raw.githubusercontent.com/youtube/api-samples/master/python/upload_video.py # noqa -import httplib +import http.client import httplib2 import random import time @@ -22,7 +21,7 @@ from googleapiclient.http import MediaFileUpload from google_auth_oauthlib.flow import InstalledAppFlow -import utils +from . import utils logging.basicConfig(format='%(asctime)s %(message)s', level=logging.INFO) @@ -38,13 +37,13 @@ MAX_RETRIES = 10 RETRIABLE_EXCEPTIONS = ( IOError, httplib2.HttpLib2Error, - httplib.NotConnected, - httplib.IncompleteRead, - httplib.ImproperConnectionState, - httplib.CannotSendRequest, - httplib.CannotSendHeader, - httplib.ResponseNotReady, - httplib.BadStatusLine, + http.client.NotConnected, + http.client.IncompleteRead, + http.client.ImproperConnectionState, + http.client.CannotSendRequest, + http.client.CannotSendHeader, + http.client.ResponseNotReady, + http.client.BadStatusLine, ) RETRIABLE_STATUS_CODES = [500, 502, 503, 504] diff --git a/pyproject.toml b/pyproject.toml index 7f162b0..798a789 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -16,7 +16,7 @@ homepage = "https://git.lecygnenoir.info/LecygneNoir/prismedia" keywords = ['peertube', 'youtube'] [tool.poetry.dependencies] -python = "^2.7" +python = "~2.7 || ^3.3" google-auth-oauthlib = "^0.2.0" requests-toolbelt = "^0.9.1" docopt = "^0.6.2" @@ -26,12 +26,14 @@ tzlocal = "^1.5" python-magic = "^0.4.15" schema = "^0.6.8" google-api-python-client = "^1.7" +configparser = "^3.7" +future = "^0.17.1" [tool.poetry.dev-dependencies] +[tool.poetry.scripts] +prismedia = 'prismedia.upload:main' [build-system] requires = ["poetry>=0.12"] build-backend = "poetry.masonry.api" -[tool.poetry.scripts] -prismedia = 'prismedia.upload:main' diff --git a/requirements.txt b/requirements.txt index dbbac32..43c2768 100644 --- a/requirements.txt +++ b/requirements.txt @@ -7,14 +7,20 @@ certifi==2018.11.29 \ chardet==3.0.4 \ --hash=sha256:84ab92ed1c4d4f16916e05906b6b75a6c0fb5db821cc65e70cbd64a3e2a5eaae \ --hash=sha256:fc323ffcaeaed0e0a02bf4d117757b98aed530d9ed4531e3e15460124c106691 +configparser==3.7.1 \ + --hash=sha256:5bd5fa2a491dc3cfe920a3f2a107510d65eceae10e9c6e547b90261a4710df32 \ + --hash=sha256:c114ff90ee2e762db972fa205f02491b1f5cf3ff950decd8542c62970c9bedac \ + --hash=sha256:df28e045fbff307a28795b18df6ac8662be3219435560ddb068c283afab1ea7a docopt==0.6.2 \ --hash=sha256:49b3a825280bd66b3aa83585ef59c4a8c82f2c8a522dbe754a8bc8d08c85c491 -google-api-python-client==1.7.8 \ - --hash=sha256:06907006ed5ce831018f03af3852d739c0b2489cdacfda6971bcc2075c762858 \ - --hash=sha256:937eabdc3940977f712fa648a096a5142766b6d0a0f58bc603e2ac0687397ef0 -google-auth==1.6.2 \ - --hash=sha256:b6081ba9946828d6417c15ecdc723fdb7c007cdd74e140747d3876a7440f0be5 \ - --hash=sha256:e8d64e9bc8cb6f0fc5360c693f86dc9ee6964081ee702e3b5ddc937f99efc950 +future==0.17.1 \ + --hash=sha256:67045236dcfd6816dc439556d009594abf643e5eb48992e36beac09c2ca659b8 +google-api-python-client==1.7.6 \ + --hash=sha256:51dc9139aa06fd0b1339a22b6b1c9fe74cb891b3dd803e8c464c5a18a8de23dc \ + --hash=sha256:bf98b066fb6e4e6da1f2f11d6cb0bb947de156aef8562a32b0692e7073d38593 +google-auth==1.6.1 \ + --hash=sha256:494e747bdc2cdeb0fa6ef85118de2ea1a563f160294cce05048c6ff563fda1bb \ + --hash=sha256:b08a27888e9d1c17a891b3688aacc9c6f2019d7f6c5a2e73588e6bb9a2c0fa98 google-auth-httplib2==0.0.3 \ --hash=sha256:098fade613c25b4527b2c08fa42d11f3c2037dda8995d86de0745228e965d445 \ --hash=sha256:f1c437842155680cf9918df9bc51c1182fda41feef88c34004bd1978c8157e08 @@ -23,12 +29,12 @@ google-auth-oauthlib==0.2.0 \ --hash=sha256:81ba22acada4d13b1d83f9371ab19fd61f1250a542d21cf49e4dcf0637a7344a httplib2==0.12.1 \ --hash=sha256:4ba6b8fd77d0038769bf3c33c9a96a6f752bc4cdf739701fdcaf210121f399d4 -idna==2.8 \ - --hash=sha256:c357b3f628cf53ae2c4c05627ecc484553142ca23264e593d327bcde5e9c3407 \ - --hash=sha256:ea8b7f6188e6fa117537c3df7da9fc686d485087abf6ac197f9c46432f7e4a3c -oauthlib==3.0.1 \ - --hash=sha256:0ce32c5d989a1827e3f1148f98b9085ed2370fc939bf524c9c851d8714797298 \ - --hash=sha256:3e1e14f6cde7e5475128d30e97edc3bfb4dc857cb884d8714ec161fdbb3b358e +idna==2.6 \ + --hash=sha256:2c6a5de3089009e3da7c5dde64a141dbc8551d5b7f6cf4ed7c2568d0cc520a8f \ + --hash=sha256:8c7309c718f94b3a625cb648ace320157ad16ff131ae0af362c9f21b80ef6ec4 +oauthlib==2.1.0 \ + --hash=sha256:ac35665a61c1685c56336bda97d5eefa246f1202618a1d6f34fccb1bdd404162 \ + --hash=sha256:d883b36b21a6ad813953803edfa563b1b579d79ca758fe950d1bc9e8b326025b pyasn1==0.4.5 \ --hash=sha256:061442c60842f6d11051d4fdae9bc197b64bd41573a12234a753a0cb80b4f30b \ --hash=sha256:0ee2449bf4c4e535823acc25624c45a8b454f328d59d3f3eeb82d3567100b9bd \ @@ -63,13 +69,12 @@ python-magic==0.4.15 \ pytz==2018.9 \ --hash=sha256:32b0891edff07e28efe91284ed9c31e123d84bea3fd98e1f72be2508f43ef8d9 \ --hash=sha256:d5f05e487007e29e03409f9398d074e158d920d36eb82eaf66fb1136b0c5374c -requests==2.21.0 \ - --hash=sha256:502a824f31acdacb3a35b6690b5fbf0bc41d63a24a45c4004352b0242707598e \ - --hash=sha256:7bf2a778576d825600030a110f3c0e3e8edc51dfaafe1c146e39a2027784957b -requests-oauthlib==1.2.0 \ - --hash=sha256:bd6533330e8748e94bf0b214775fed487d309b8b8fe823dc45641ebcd9a32f57 \ - --hash=sha256:d3ed0c8f2e3bbc6b344fa63d6f933745ab394469da38db16bdddb461c7e25140 \ - --hash=sha256:dd5a0499abfefd087c6dd96693cbd5bfd28aa009719a7f85ab3fabe3956ef19a +requests==2.18.4 \ + --hash=sha256:6a1b267aa90cac58ac3a765d067950e7dbbf75b1da07e895d1f594193a40a38b \ + --hash=sha256:9c443e7324ba5b85070c4a818ade28bfabedf16ea10206da1132edaa6dda237e +requests-oauthlib==0.8.0 \ + --hash=sha256:50a8ae2ce8273e384895972b56193c7409601a66d4975774c60c2aed869639ca \ + --hash=sha256:883ac416757eada6d3d07054ec7092ac21c7f35cb1d2cf82faf205637081f468 requests-toolbelt==0.9.1 \ --hash=sha256:380606e1d10dc85c3bd47bf5a6095f815ec007be7a8b69c878507068df059e6f \ --hash=sha256:968089d4584ad4ad7c171454f0a5c6dac23971e9472521ea3b6d49d610aa6fc0 @@ -88,6 +93,6 @@ uritemplate==3.0.0 \ --hash=sha256:01c69f4fe8ed503b2951bef85d996a9d22434d2431584b5b107b2981ff416fbd \ --hash=sha256:1b9c467a940ce9fb9f50df819e8ddd14696f89b9a8cc87ac77952ba416e0a8fd \ --hash=sha256:c02643cebe23fc8adb5e6becffe201185bf06c40bda5c0b4028a93f1527d011d -urllib3==1.24.1 \ - --hash=sha256:61bf29cada3fc2fbefad4fdf059ea4bd1b4a86d2b6d15e1c7c0b582b9752fe39 \ - --hash=sha256:de9529817c93f27c8ccbfead6985011db27bd0ddfcdb2d86f3f663385c6a9c22 +urllib3==1.22 \ + --hash=sha256:06330f386d6e4b195fbfc736b297f58c5a892e4440e54d294d7004e3a9bbea1b \ + --hash=sha256:cc44da8e1145637334317feebd728bd869a35285b93cbb4cca2577da7e62db4f -- 2.20.1 From 22356f31cc893df71599f52f24ec4eda33471348 Mon Sep 17 00:00:00 2001 From: Rigel Kent Date: Fri, 22 Feb 2019 18:12:43 +0100 Subject: [PATCH 13/13] rollback to RawConfigParser --- prismedia/pt_upload.py | 6 +----- prismedia/upload.py | 2 +- prismedia/utils.py | 9 +++------ 3 files changed, 5 insertions(+), 12 deletions(-) diff --git a/prismedia/pt_upload.py b/prismedia/pt_upload.py index e6acd92..ae49140 100644 --- a/prismedia/pt_upload.py +++ b/prismedia/pt_upload.py @@ -16,12 +16,8 @@ from requests_toolbelt.multipart.encoder import MultipartEncoder from . import utils from six.moves import configparser -import six -if six.PY2: - ConfigParser = configparser.SafeConfigParser -else: - ConfigParser = configparser.ConfigParser +ConfigParser = configparser.RawConfigParser PEERTUBE_SECRETS_FILE = 'peertube_secret' PEERTUBE_PRIVACY = { diff --git a/prismedia/upload.py b/prismedia/upload.py index 14b0d3b..2902519 100755 --- a/prismedia/upload.py +++ b/prismedia/upload.py @@ -87,7 +87,7 @@ except ImportError: 'see https://github.com/ahupp/python-magic\n') exit(1) -VERSION = "prismedia v0.6.1-1" +VERSION = "prismedia v0.6.2" VALID_PRIVACY_STATUSES = ('public', 'private', 'unlisted') VALID_CATEGORIES = ( diff --git a/prismedia/utils.py b/prismedia/utils.py index d4f84f7..8d0d092 100644 --- a/prismedia/utils.py +++ b/prismedia/utils.py @@ -1,3 +1,4 @@ +#!/usr/bin/python # coding: utf-8 from ConfigParser import RawConfigParser, NoOptionError, NoSectionError @@ -8,14 +9,10 @@ from subprocess import check_call, CalledProcessError, STDOUT import unidecode import logging from six.moves import configparser -import six -if six.PY2: - ConfigParser = configparser.SafeConfigParser -else: - ConfigParser = configparser.ConfigParser +ConfigParser = configparser.RawConfigParser -### CATEGORIES ### +# CATEGORIES # YOUTUBE_CATEGORY = { "music": 10, "films": 1, -- 2.20.1