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

Style and doc improvements #23

Open
wants to merge 9 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
152 changes: 152 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class

# C extensions
*.so

# Distribution / packaging
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
share/python-wheels/
*.egg-info/
.installed.cfg
*.egg
MANIFEST

# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec

# Installer logs
pip-log.txt
pip-delete-this-directory.txt

# Unit test / coverage reports
htmlcov/
.tox/
.nox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*.cover
*.py,cover
.hypothesis/
.pytest_cache/
cover/

# Translations
*.mo
*.pot

# Django stuff:
*.log
local_settings.py
db.sqlite3
db.sqlite3-journal

# Flask stuff:
instance/
.webassets-cache

# Scrapy stuff:
.scrapy

# Sphinx documentation
docs/_build/

# PyBuilder
.pybuilder/
target/

# Jupyter Notebook
.ipynb_checkpoints

# IPython
profile_default/
ipython_config.py

# pyenv
# For a library or package, you might want to ignore these files since the code is
# intended to run in multiple environments; otherwise, check them in:
# .python-version

# pipenv
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
# However, in case of collaboration, if having platform-specific dependencies or dependencies
# having no cross-platform support, pipenv may install dependencies that don't work, or not
# install all needed dependencies.
#Pipfile.lock

# poetry
# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
# This is especially recommended for binary packages to ensure reproducibility, and is more
# commonly ignored for libraries.
# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
#poetry.lock

# PEP 582; used by e.g. github.com/David-OConnor/pyflow
__pypackages__/

# Celery stuff
celerybeat-schedule
celerybeat.pid

# SageMath parsed files
*.sage.py

# Environments
.env
.venv
env/
venv/
ENV/
env.bak/
venv.bak/

# Spyder project settings
.spyderproject
.spyproject

# Rope project settings
.ropeproject

# mkdocs documentation
/site

# mypy
.mypy_cache/
.dmypy.json
dmypy.json

# Pyre type checker
.pyre/

# pytype static type analyzer
.pytype/

# Cython debug symbols
cython_debug/

# PyCharm
# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
# and can be added to the global gitignore or merged into this file. For a more nuclear
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
.idea/
22 changes: 22 additions & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v2.3.0
hooks:
- id: check-yaml
- id: end-of-file-fixer
- id: trailing-whitespace
- id: double-quote-string-fixer
- repo: https://github.com/psf/black
rev: 19.3b0
hooks:
- id: black
args: [--line-length=88, --skip-string-normalization]
- repo: https://github.com/pycqa/isort
rev: 5.5.2
hooks:
- id: isort
- repo: https://github.com/PyCQA/flake8
rev: 4.0.1
hooks:
- id: flake8
args: [--max-line-length=88]
20 changes: 13 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Youtube-First-Comment-Bot
A bot for automatically post comment when a youtube channel upload a new video.
This bot checks a specified channel every specified intervel and if a new video found this bot will post a comment that you wants to post.
This bot checks a specified channel every specified interval and if a new video found this bot will post a comment that you wants to post.

## Requirments
* python 2.7
Expand All @@ -12,17 +12,23 @@ This bot checks a specified channel every specified intervel and if a new video
1. Create an account and a api and a outh screen in google console
2. Replace the file "client_secrets.json" with the downloaded Credentials json file from google console
3. Edit these variables in bot.py
* cid="UUX6OQ3DkcsbYNE6v8uQQuVA" put uploads id of the required channel here.
* lastvid="Z9WQy9uEY8M" put last video id here
* intervel=5 put the time waiting intervel here
* playlist_id="UUX6OQ3DkcsbYNE6v8uQQuVA" put uploads id of the required channel here.
* lastvid="Z9WQy9uEY8M" put last video id here
* interval=5 put the time waiting interval here
* comment="Put your text here" edit this variable and put the required comment here.
4. Remove contents in "bot.py-oauth2.json" before usage
5. if you setup everything properly the bot will ask you to goto a link from your browser and login with your youtube account ( this is a one time only requirment)

## Help
* How to find upload it? see this video https://www.youtube.com/watch?v=RjUlmco7v2M .
* How to find upload video id? see this video https://www.youtube.com/watch?v=RjUlmco7v2M .
* To find last video go the the required channel and check the url of the latest upload an url may look like this https://www.youtube.com/watch?v=RjUlmco7v2M take the last string that is "RjUlmco7v2M" this is video id.
* To set up a good time intervel you must consider several things eg youtube api quata limit system resources etc... if you planed to run this bot 24x7 then put the inyer vell as 20 to 25 seconds, if you are running this bot only for one or two hour you can put this intervel as 1 or 2 seconds. this is to prevent youtube api limit.
* To set up a good time interval you must consider several things eg youtube api quata limit system resources etc... if you planed to run this bot 24x7 then put the inyer vell as 20 to 25 seconds, if you are running this bot only for one or two hour you can put this interval as 1 or 2 seconds. this is to prevent youtube api limit.

**Note**
## Development
* For pinning requirements run in virtualenv
```bash
pip freeze -r unpinned-requirements.txt > requirements.txt
```

**Note**
Feel free to modify i have messed up with arguments in the last few section, the code still works but there is a lot of room for improvements.
136 changes: 71 additions & 65 deletions bot.py
Original file line number Diff line number Diff line change
@@ -1,28 +1,29 @@
import httplib2
# -*- coding: utf-8 -*-
import os
import sys
import time

from apiclient.discovery import build_from_document
from apiclient.errors import HttpError
import httplib2
from googleapiclient.discovery import build_from_document
from googleapiclient.errors import HttpError
from oauth2client.client import flow_from_clientsecrets
from oauth2client.file import Storage
from oauth2client.tools import argparser, run_flow

# ======== Configure the following variables ===========
#uploads id
cid="UUX6OQ3DkcsbYNE6v8uQQuVA"
#last video id wMuYiLby3-s
lastvid="Z9WQy9uEY8M"
# waiting time intervel in seconds
intervel=5
#comment you need to post
comment="Put your text here"
# uploads id
playlist_id = 'UUX6OQ3DkcsbYNE6v8uQQuVA'
# last video id wMuYiLby3-s
lastvid = 'Z9WQy9uEY8M'
# waiting time interval in seconds
interval = 5
# comment you need to post
comment = 'Put your text here'

CLIENT_SECRETS_FILE = "./client_secrets.json"
YOUTUBE_READ_WRITE_SSL_SCOPE = "https://www.googleapis.com/auth/youtube.force-ssl"
YOUTUBE_API_SERVICE_NAME = "youtube"
YOUTUBE_API_VERSION = "v3"
CLIENT_SECRETS_FILE = './client_secrets.json'
YOUTUBE_READ_WRITE_SSL_SCOPE = 'https://www.googleapis.com/auth/youtube.force-ssl'
YOUTUBE_API_SERVICE_NAME = 'youtube'
YOUTUBE_API_VERSION = 'v3'
MISSING_CLIENT_SECRETS_MESSAGE = """
WARNING: Please configure OAuth 2.0
To make this sample run you will need to populate the client_secrets.json file
Expand All @@ -32,61 +33,66 @@
https://console.developers.google.com
For more information about the client_secrets.json file format, please visit:
https://developers.google.com/api-client-library/python/guide/aaa_client_secrets
""" % os.path.abspath(os.path.join(os.path.dirname(__file__),
CLIENT_SECRETS_FILE))
""" % os.path.abspath(
os.path.join(os.path.dirname(__file__), CLIENT_SECRETS_FILE)
)


def get_authenticated_service(args):
flow = flow_from_clientsecrets(CLIENT_SECRETS_FILE, scope=YOUTUBE_READ_WRITE_SSL_SCOPE,
message=MISSING_CLIENT_SECRETS_MESSAGE)
flow = flow_from_clientsecrets(
CLIENT_SECRETS_FILE,
scope=YOUTUBE_READ_WRITE_SSL_SCOPE,
message=MISSING_CLIENT_SECRETS_MESSAGE,
)

storage = Storage('%s-oauth2.json' % sys.argv[0])
credentials = storage.get()

if credentials is None or credentials.invalid:
credentials = run_flow(flow, storage, args)
with open('youtube-v3-discoverydocument.json', 'r') as f:
doc = f.read()
return build_from_document(doc, http=credentials.authorize(httplib2.Http()))

storage = Storage("%s-oauth2.json" % sys.argv[0])
credentials = storage.get()

if credentials is None or credentials.invalid:
credentials = run_flow(flow, storage, args)
with open("youtube-v3-discoverydocument.json", "r") as f:
doc = f.read()
return build_from_document(doc, http=credentials.authorize(httplib2.Http()))
def insert_comment(youtube, parent_id, text):
insert_result = youtube.commentThreads().insert(
part="snippet",
body={
"snippet": {
"videoId": parent_id,
"topLevelComment": {
"snippet": {
"textOriginal": text
}
}
}
}
)
response = insert_result.execute()
print ("comment added")
def lastvideo(youtube, cid):
request = youtube.playlistItems().list(
part="snippet",
playlistId=cid
insert_result = youtube.commentThreads().insert(
part='snippet',
body={
'snippet': {
'videoId': parent_id,
'topLevelComment': {'snippet': {'textOriginal': text}},
}
},
)
response = request.execute()
return(response["items"][0]["snippet"]["resourceId"]["videoId"])
argparser.add_argument("--text", help="Required; text that will be used as comment.")
insert_result.execute()
print('comment added')


def lastvideo(youtube, playlist_id):
request = youtube.playlistItems().list(part='snippet', playlistId=playlist_id)
response = request.execute()
return response['items'][0]['snippet']['resourceId']['videoId']


argparser.add_argument('--text', help='Required; text that will be used as comment.')
args = argparser.parse_args()
args.videoid=lastvid
args.text=comment
args.videoid = lastvid
args.text = comment
youtube = get_authenticated_service(args)
i=0
i = 0
while True:
last=lastvideo(youtube,cid)
i=i+1
if(last!=lastvid):
print(last)
try:
insert_comment(youtube, last, args.text)
except HttpError as e:
print ("An HTTP error %d occurred:\n%s") % (e.resp.status, e.content)
else:
print ("Comment Inserted")
break
time.sleep(intervel)
print("waiting......")
print ("Cycle:", i)
last = lastvideo(youtube, playlist_id)
i = i + 1
if last != lastvid:
print(last)
try:
insert_comment(youtube, last, args.text)
except HttpError as e:
print('An HTTP error %d occurred:\n%s') % (e.resp.status, e.content)
else:
print('Comment Inserted')
break
time.sleep(interval)
print('waiting......')
print('Cycle:', i)
Loading