Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Safer install instructions using virtualenv, more convinient client_secrets.json location, Python3 support #294

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ __pycache__/
# Distribution / packaging
.Python
env/
.venv/
build/
develop-eggs/
dist/
Expand Down Expand Up @@ -56,4 +57,7 @@ coverage.xml
docs/_build/

# PyBuilder
target/
target/

# Client Secrets
client_secrets.json
45 changes: 22 additions & 23 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,29 +11,28 @@ Dependencies
* [Python 2.6/2.7/3.x](http://www.python.org).
* Packages: [google-api-python-client](https://developers.google.com/api-client-library/python), [progressbar2](https://pypi.python.org/pypi/progressbar2) (optional).

Check if your operating system provides those packages (check also those [deb/rpm/mac files](https://github.com/qiuwei/youtube-upload/releases)), otherwise install them with `pip`:

```
$ sudo pip install --upgrade google-api-python-client oauth2client progressbar2
```
Check if your operating system provides those packages (check also those [deb/rpm/mac files](https://github.com/qiuwei/youtube-upload/releases)), otherwise install them with `pip` in a virtualenv as explained below.

Install
=======

```
$ wget https://github.com/tokland/youtube-upload/archive/master.zip
$ unzip master.zip
$ cd youtube-upload-master
$ sudo python setup.py install
```
## Installing with Virtualenv

Or run directly from sources:
Using a virtualenv is optional but highly recommended if you will be installing youtube-upload's dependencies through pip.

```
$ cd youtube-upload-master
$ PYTHONPATH=. python bin/youtube-upload ...
$ git clone https://github.com/tokland/youtube-upload.git
$ cd youtube-upload
$ python -m venv .venv
$ source .venv/bin/activate
$ pip install --upgrade -r requirements.txt
$ deactivate
$ # Make the script executable and symbolic link it to your user's bin directory
$ chmod +x bin/youtube-upload && mkdir -p $HOME/.local/bin && ln -s $PWD/bin/youtube-upload $HOME/.local/bin/
```

Be sure that `$HOME/.local/bin` is in your `PATH` environmental variable. Bash users can do so by adding the line `export PATH=$PATH:$HOME/.local/bin` in their `~/.bashrc` file. Zsh users can add the same line to `~/.zshrc`. Fish users can run the command `set -U fish_user_paths $HOME/.local/bin/ $fish_user_paths`.

Setup
=====

Expand All @@ -47,15 +46,15 @@ The package used to include a default ```client_secrets.json``` file. It does no
* Top menu: _Enabled API(s)_: Enable all Youtube APIs.
* Side menu: _APIs & auth_ -> _Credentials_.
* _Create a Client ID_: Add credentials -> OAuth 2.0 Client ID -> Other -> Name: youtube-upload -> Create -> OK
* _Download JSON_: Under the section "OAuth 2.0 client IDs". Save the file to your local system.
* Use this JSON as your credentials file: `--client-secrets=CLIENT_SECRETS` or copy it to `~/client_secrets.json`.
* _Download JSON_: Under the section "OAuth 2.0 client IDs". Save the file to your local system.
* Use this JSON as your credentials file: `--client-secrets=CLIENT_SECRETS`. You may also copy it to `[YOUR YOUTUBE-UPLOAD INSTALL DIR]/client_secrets.json` or `~/.client_secrets.json`.

*Note: ```client_secrets.json``` is a file you can download from the developer console, the credentials file is something auto generated after the first time the script is run and the google account sign in is followed, the file is stored at ```~/.youtube-upload-credentials.json```.*

Examples
========

* Upload a video (a valid `~/.client_secrets.json` should exist, check the Setup section):
* Upload a video (a valid `[YOUR YOUTUBE-UPLOAD INSTALL DIR]/client_secrets.json` or `~/.client_secrets.json` should exist, check the Setup section):

```
$ youtube-upload --title="A.S. Mutter" anne_sophie_mutter.flv
Expand All @@ -80,12 +79,12 @@ $ youtube-upload \
anne_sophie_mutter.flv
tx2Zb-145Yz
```
*Other extra medata available :*
*Other extra medata available :*
```
--privacy (public | unlisted | private)
--publish-at (YYYY-MM-DDThh:mm:ss.sZ)
--location (latitude=VAL,longitude=VAL[,altitude=VAL])
--thumbnail (string)
--privacy (public | unlisted | private)
--publish-at (YYYY-MM-DDThh:mm:ss.sZ)
--location (latitude=VAL,longitude=VAL[,altitude=VAL])
--thumbnail (string)
```

* Upload a video using a browser GUI to authenticate:
Expand Down Expand Up @@ -130,7 +129,7 @@ Using [shoogle](https://github.com/tokland/shoogle):

```
$ shoogle execute --client-secret-file client_secret.json \
youtube:v3.videoCategories.list <(echo '{"part": "id,snippet", "regionCode": "es"}') |
youtube:v3.videoCategories.list <(echo '{"part": "id,snippet", "regionCode": "es"}') |
jq ".items[] | select(.snippet.assignable) | {id: .id, title: .snippet.title}"
```

Expand Down
23 changes: 14 additions & 9 deletions bin/youtube-upload
Original file line number Diff line number Diff line change
@@ -1,10 +1,15 @@
#!/usr/bin/env python
#!/usr/bin/env bash

if __name__ == '__main__':

#Allows you to a relative import from the parent folder
import os.path, sys
sys.path.insert(0, os.path.join(os.path.dirname(os.path.realpath(__file__)), os.pardir))

from youtube_upload import main
main.run()
# Get the script dir https://stackoverflow.com/a/246128
SOURCE="${BASH_SOURCE[0]}"
while [ -h "$SOURCE" ]; do # resolve $SOURCE until the file is no longer a symlink
DIR="$( cd -P "$( dirname "$SOURCE" )" >/dev/null 2>&1 && pwd )"
SOURCE="$(readlink "$SOURCE")"
[[ $SOURCE != /* ]] && SOURCE="$DIR/$SOURCE" # if $SOURCE was a relative symlink, we need to resolve it relative to the path where the symlink file was located
done
SCRIPT_DIR="$( cd -P "$( dirname "$SOURCE" )" >/dev/null 2>&1 && pwd )"

# If virtual environment exists, activate it.
[ -d "$SCRIPT_DIR/../.venv" ] && source $SCRIPT_DIR/../.venv/bin/activate

python $SCRIPT_DIR/youtube-upload.py "$@"
4 changes: 4 additions & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
wheel
google-api-python-client
oauth2client
progressbar2
15 changes: 13 additions & 2 deletions youtube_upload/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@

import googleapiclient.errors
import oauth2client
from oauth2client import file

from . import auth
from . import upload_video
Expand Down Expand Up @@ -152,7 +153,17 @@ def get_youtube_handler(options):
"""Return the API Youtube object."""
home = os.path.expanduser("~")
default_credentials = os.path.join(home, ".youtube-upload-credentials.json")
client_secrets = options.client_secrets or os.path.join(home, ".client_secrets.json")
client_secrets = options.client_secrets
if not client_secrets:
possible_secrets_locations = [
os.path.join(os.path.dirname(__file__), '..', 'client_secrets.json'),
os.path.join(home, ".client_secrets.json")
]
for f in possible_secrets_locations:
if os.path.exists(f):
client_secrets = f
break

credentials = options.credentials_file or default_credentials
debug("Using client secrets: {0}".format(client_secrets))
debug("Using credentials file: {0}".format(credentials))
Expand Down Expand Up @@ -194,7 +205,7 @@ def run_main(parser, options, args, output=sys.stdout):

def main(arguments):
"""Upload videos to Youtube."""
usage = """Usage: %prog [OPTIONS] VIDEO [VIDEO2 ...]
usage = """Usage: youtube-upload [OPTIONS] VIDEO [VIDEO2 ...]

Upload videos to Youtube."""
parser = optparse.OptionParser(usage)
Expand Down
6 changes: 3 additions & 3 deletions youtube_upload/upload_video.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,13 +31,13 @@ def _upload_to_request(request, progress_callback):
else:
raise KeyError("Expected field 'id' not found in response")

def upload(resource, path, body, chunksize=4*1024*1024,
def upload(resource, path, body, chunksize=4*1024*1024,
progress_callback=None, max_retries=10):
"""Upload video to Youtube. Return video ID."""
body_keys = ",".join(body.keys())
media = apiclient.http.MediaFileUpload(path, chunksize=chunksize,
media = apiclient.http.MediaFileUpload(path, chunksize=chunksize,
resumable=True, mimetype="application/octet-stream")
request = resource.videos().insert(part=body_keys, body=body, media_body=media)
upload_fun = lambda: _upload_to_request(request, progress_callback)
return lib.retriable_exceptions(upload_fun,
return lib.retriable_exceptions(upload_fun,
RETRIABLE_EXCEPTIONS, max_retries=max_retries)