diff options
Diffstat (limited to 'youtube')
-rw-r--r-- | youtube/accounts.py | 336 | ||||
-rw-r--r-- | youtube/comments.py | 25 | ||||
-rw-r--r-- | youtube/post_comment.py | 181 | ||||
-rw-r--r-- | youtube/templates/comments.html | 24 | ||||
-rw-r--r-- | youtube/templates/comments_page.html | 3 | ||||
-rw-r--r-- | youtube/templates/delete_comment.html | 21 | ||||
-rw-r--r-- | youtube/templates/login.html | 57 | ||||
-rw-r--r-- | youtube/templates/post_comment.html | 20 |
8 files changed, 4 insertions, 663 deletions
diff --git a/youtube/accounts.py b/youtube/accounts.py deleted file mode 100644 index d2e8a41..0000000 --- a/youtube/accounts.py +++ /dev/null @@ -1,336 +0,0 @@ -# Contains functions having to do with logging in -from youtube import util -from youtube import yt_app -import settings - -import urllib -import json -import re -import http.cookiejar -import io -import os - -import flask -from flask import request - -try: - with open(os.path.join(settings.data_dir, 'accounts.txt'), 'r', encoding='utf-8') as f: - accounts = json.loads(f.read()) -except FileNotFoundError: - # global var for temporary storage of account info - accounts = {} - -def account_list_data(): - '''Returns iterable of (channel_id, account_display_name)''' - return [ (channel_id, account['display_name']) for channel_id, account in accounts.items() ] - -def save_accounts(): - to_save = {channel_id: account for channel_id, account in accounts.items() if account['save']} - with open(os.path.join(settings.data_dir, 'accounts.txt'), 'w', encoding='utf-8') as f: - f.write(json.dumps(to_save, indent=4)+'\n') - -def cookiejar_from_lwp_str(lwp_str): - lwp_str = "#LWP-Cookies-2.0\n" + lwp_str # header required by _really_load for reading from "file" - cookiejar = http.cookiejar.LWPCookieJar() - # HACK: cookiejar module insists on using filenames and reading files for you, - # so present a StringIO to this internal method which takes a filelike object - cookiejar._really_load(io.StringIO(lwp_str), "", False, False) - return cookiejar - -def account_cookiejar(channel_id): - return cookiejar_from_lwp_str('\n'.join(accounts[channel_id]['cookies'])) - -def _add_account(username, password, save, use_tor): - cookiejar = http.cookiejar.LWPCookieJar() - result = _login(username, password, cookiejar, use_tor) - if isinstance(result, dict): - accounts[result["channel_id"]] = { - "save":save, - "username": username, - "display_name": username, - "cookies":cookiejar.as_lwp_str(ignore_discard=False, ignore_expires=False).split('\n'), - } - if save: - save_accounts() - return True - return False - -@yt_app.route('/login', methods=['POST']) -def add_account(): - save_account = request.values.get('save', 'off') == 'on' - use_tor = request.values.get('use_tor', 'off') == 'on' - - if _add_account(request.values['username'], request.values['password'], save_account, use_tor ): - return 'Account successfully added' - else: - return 'Failed to add account' - - -@yt_app.route('/login', methods=['GET']) -def get_account_login_page(): - return flask.render_template('login.html') - - - -# --------------------------------- -# Code ported from youtube-dl -# --------------------------------- -from html.parser import HTMLParser as compat_HTMLParser -import http.client as compat_http_client - -class HTMLAttributeParser(compat_HTMLParser): - """Trivial HTML parser to gather the attributes for a single element""" - def __init__(self): - self.attrs = {} - compat_HTMLParser.__init__(self) - - def handle_starttag(self, tag, attrs): - self.attrs = dict(attrs) - -def extract_attributes(html_element): - """Given a string for an HTML element such as - <el - a="foo" B="bar" c="&98;az" d=boz - empty= noval entity="&" - sq='"' dq="'" - > - Decode and return a dictionary of attributes. - { - 'a': 'foo', 'b': 'bar', c: 'baz', d: 'boz', - 'empty': '', 'noval': None, 'entity': '&', - 'sq': '"', 'dq': '\'' - }. - NB HTMLParser is stricter in Python 2.6 & 3.2 than in later versions, - but the cases in the unit test will work for all of 2.6, 2.7, 3.2-3.5. - """ - parser = HTMLAttributeParser() - parser.feed(html_element) - parser.close() - - return parser.attrs - -def _hidden_inputs(html): - html = re.sub(r'<!--(?:(?!<!--).)*-->', '', html) - hidden_inputs = {} - for input in re.findall(r'(?i)(<input[^>]+>)', html): - attrs = extract_attributes(input) - if not input: - continue - if attrs.get('type') not in ('hidden', 'submit'): - continue - name = attrs.get('name') or attrs.get('id') - value = attrs.get('value') - if name and value is not None: - hidden_inputs[name] = value - return hidden_inputs - -def try_get(src, getter, expected_type=None): - if not isinstance(getter, (list, tuple)): - getter = [getter] - for get in getter: - try: - v = get(src) - except (AttributeError, KeyError, TypeError, IndexError): - pass - else: - if expected_type is None or isinstance(v, expected_type): - return v - -def remove_start(s, start): - return s[len(start):] if s is not None and s.startswith(start) else s - - -yt_dl_headers = { - 'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64; rv:59.0) Gecko/20100101 Firefox/59.0 (Chrome)', - 'Accept-Charset': 'ISO-8859-1,utf-8;q=0.7,*;q=0.7', - 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8', - 'Accept-Language': 'en-us,en;q=0.5', -} -_LOGIN_URL = 'https://accounts.google.com/ServiceLogin' -_TWOFACTOR_URL = 'https://accounts.google.com/signin/challenge' - -_LOOKUP_URL = 'https://accounts.google.com/_/signin/sl/lookup' -_CHALLENGE_URL = 'https://accounts.google.com/_/signin/sl/challenge' -_TFA_URL = 'https://accounts.google.com/_/signin/challenge?hl=en&TL={0}' -_CHANNEL_ID_RE = re.compile(r'"channelUrl"\s*:\s*"\\/channel\\/(UC[\w-]{22})"') -def _login(username, password, cookiejar, use_tor): - """ - Attempt to log in to YouTube. - True is returned if successful or skipped. - False is returned if login failed. - - Taken from youtube-dl - """ - - login_page = util.fetch_url(_LOGIN_URL, yt_dl_headers, report_text='Downloaded login page', cookiejar_receive=cookiejar, use_tor=use_tor, debug_name='login_page').decode('utf-8') - - if login_page is False: - return - - login_form = _hidden_inputs(login_page) - - def req(url, f_req, note, errnote): - data = login_form.copy() - data.update({ - 'pstMsg': 1, - 'checkConnection': 'youtube', - 'checkedDomains': 'youtube', - 'hl': 'en', - 'deviceinfo': '[null,null,null,[],null,"US",null,null,[],"GlifWebSignIn",null,[null,null,[]]]', - 'f.req': json.dumps(f_req), - 'flowName': 'GlifWebSignIn', - 'flowEntry': 'ServiceLogin', - 'bgRequest': '["identifier",""]', - }) - headers={ - 'Content-Type': 'application/x-www-form-urlencoded;charset=utf-8', - 'Google-Accounts-XSRF': 1, - } - headers.update(yt_dl_headers) - result = util.fetch_url(url, headers, report_text=note, data=data, cookiejar_send=cookiejar, cookiejar_receive=cookiejar, use_tor=use_tor, debug_name=note).decode('utf-8') - result = re.sub(r'^[^\[]*', '', result) - return json.loads(result) - - def warn(message): - print("Login: " + message) - - lookup_req = [ - username, - None, [], None, 'US', None, None, 2, False, True, - [ - None, None, - [2, 1, None, 1, - 'https://accounts.google.com/ServiceLogin?passive=true&continue=https%3A%2F%2Fwww.youtube.com%2Fsignin%3Fnext%3D%252F%26action_handle_signin%3Dtrue%26hl%3Den%26app%3Ddesktop%26feature%3Dsign_in_button&hl=en&service=youtube&uilel=3&requestPath=%2FServiceLogin&Page=PasswordSeparationSignIn', - None, [], 4], - 1, [None, None, []], None, None, None, True - ], - username, - ] - - lookup_results = req( - _LOOKUP_URL, lookup_req, - 'Looking up account info', 'Unable to look up account info') - - if lookup_results is False: - return False - - user_hash = try_get(lookup_results, lambda x: x[0][2], str) - if not user_hash: - warn('Unable to extract user hash') - return False - - challenge_req = [ - user_hash, - None, 1, None, [1, None, None, None, [password, None, True]], - [ - None, None, [2, 1, None, 1, 'https://accounts.google.com/ServiceLogin?passive=true&continue=https%3A%2F%2Fwww.youtube.com%2Fsignin%3Fnext%3D%252F%26action_handle_signin%3Dtrue%26hl%3Den%26app%3Ddesktop%26feature%3Dsign_in_button&hl=en&service=youtube&uilel=3&requestPath=%2FServiceLogin&Page=PasswordSeparationSignIn', None, [], 4], - 1, [None, None, []], None, None, None, True - ]] - - challenge_results = req( - _CHALLENGE_URL, challenge_req, - 'Logging in', 'Unable to log in') - - if challenge_results is False: - return - - login_res = try_get(challenge_results, lambda x: x[0][5], list) - if login_res: - login_msg = try_get(login_res, lambda x: x[5], str) - warn( - 'Unable to login: %s' % 'Invalid password' - if login_msg == 'INCORRECT_ANSWER_ENTERED' else login_msg) - return False - - res = try_get(challenge_results, lambda x: x[0][-1], list) - if not res: - warn('Unable to extract result entry') - return False - - login_challenge = try_get(res, lambda x: x[0][0], list) - if login_challenge: - challenge_str = try_get(login_challenge, lambda x: x[2], str) - if challenge_str == 'TWO_STEP_VERIFICATION': - # SEND_SUCCESS - TFA code has been successfully sent to phone - # QUOTA_EXCEEDED - reached the limit of TFA codes - status = try_get(login_challenge, lambda x: x[5], str) - if status == 'QUOTA_EXCEEDED': - warn('Exceeded the limit of TFA codes, try later') - return False - - tl = try_get(challenge_results, lambda x: x[1][2], str) - if not tl: - warn('Unable to extract TL') - return False - - tfa_code = self._get_tfa_info('2-step verification code') - - if not tfa_code: - warn( - 'Two-factor authentication required. Provide it either interactively or with --twofactor <code>' - '(Note that only TOTP (Google Authenticator App) codes work at this time.)') - return False - - tfa_code = remove_start(tfa_code, 'G-') - - tfa_req = [ - user_hash, None, 2, None, - [ - 9, None, None, None, None, None, None, None, - [None, tfa_code, True, 2] - ]] - - tfa_results = req( - _TFA_URL.format(tl), tfa_req, - 'Submitting TFA code', 'Unable to submit TFA code') - - if tfa_results is False: - return False - - tfa_res = try_get(tfa_results, lambda x: x[0][5], list) - if tfa_res: - tfa_msg = try_get(tfa_res, lambda x: x[5], str) - warn( - 'Unable to finish TFA: %s' % 'Invalid TFA code' - if tfa_msg == 'INCORRECT_ANSWER_ENTERED' else tfa_msg) - return False - - check_cookie_url = try_get( - tfa_results, lambda x: x[0][-1][2], str) - else: - CHALLENGES = { - 'LOGIN_CHALLENGE': "This device isn't recognized. For your security, Google wants to make sure it's really you.", - 'USERNAME_RECOVERY': 'Please provide additional information to aid in the recovery process.', - 'REAUTH': "There is something unusual about your activity. For your security, Google wants to make sure it's really you.", - } - challenge = CHALLENGES.get( - challenge_str, - '%s returned error %s.' % ('youtube', challenge_str)) - warn('%s\nGo to https://accounts.google.com/, login and solve a challenge.' % challenge) - return False - else: - check_cookie_url = try_get(res, lambda x: x[2], str) - - if not check_cookie_url: - warn('Unable to extract CheckCookie URL') - return False - - try: - check_cookie_results = util.fetch_url(check_cookie_url, headers=yt_dl_headers, report_text="Checked cookie", cookiejar_send=cookiejar, cookiejar_receive=cookiejar, use_tor=use_tor, debug_name='check_cookie_results').decode('utf-8') - except (urllib.error.URLError, compat_http_client.HTTPException, socket.error) as err: - return False - - - if 'https://myaccount.google.com/' not in check_cookie_results: - warn('Unable to log in') - return False - - select_site_page = util.fetch_url('https://m.youtube.com/select_site', headers=util.mobile_ua, report_text="Retrieved page for channel id", cookiejar_send=cookiejar, use_tor=use_tor).decode('utf-8') - match = _CHANNEL_ID_RE.search(select_site_page) - if match is None: - warn('Failed to find channel id') - return False - - channel_id = match.group(1) - - return {'channel_id': channel_id} diff --git a/youtube/comments.py b/youtube/comments.py index b3f1a90..feaa912 100644 --- a/youtube/comments.py +++ b/youtube/comments.py @@ -1,4 +1,4 @@ -from youtube import proto, util, yt_data_extract, accounts +from youtube import proto, util, yt_data_extract from youtube.util import concat_or_none from youtube import yt_app import settings @@ -97,17 +97,10 @@ def post_process_comments_info(comments_info): comment['permalink'] = concat_or_none(util.URL_ORIGIN, '/watch?v=', comments_info['video_id'], '&lc=', comment['id']) - if comment['author_id'] in accounts.accounts: - comment['delete_url'] = concat_or_none(util.URL_ORIGIN, - '/delete_comment?video_id=', comments_info['video_id'], - '&channel_id=', comment['author_id'], - '&comment_id=', comment['id']) reply_count = comment['reply_count'] if reply_count == 0: - comment['replies_url'] = concat_or_none(util.URL_ORIGIN, - '/post_comment?parent_id=', comment['id'], - '&video_id=', comments_info['video_id']) + comment['replies_url'] = None else: comment['replies_url'] = concat_or_none(util.URL_ORIGIN, '/comments?parent_id=', comment['id'], @@ -148,10 +141,9 @@ def video_comments(video_id, sort=0, offset=0, lc='', secret_key=''): comments_info = yt_data_extract.extract_comments_info(request_comments(make_comment_ctoken(video_id, sort, offset, lc, secret_key))) post_process_comments_info(comments_info) - post_comment_url = util.URL_ORIGIN + "/post_comment?video_id=" + video_id other_sort_url = util.URL_ORIGIN + '/comments?ctoken=' + make_comment_ctoken(video_id, sort=1 - sort, lc=lc) other_sort_text = 'Sort by ' + ('newest' if sort == 0 else 'top') - comments_info['comment_links'] = [('Post comment', post_comment_url), (other_sort_text, other_sort_url)] + comments_info['comment_links'] = [(other_sort_text, other_sort_url)] return comments_info @@ -178,19 +170,8 @@ def get_comments_page(): other_sort_text = 'Sort by ' + ('newest' if comments_info['sort'] == 0 else 'top') comments_info['comment_links'] = [(other_sort_text, other_sort_url)] - - comment_posting_box_info = { - 'form_action': '' if replies else util.URL_ORIGIN + '/post_comment', - 'video_id': comments_info['video_id'], - 'accounts': accounts.account_list_data(), - 'include_video_id_input': not replies, - 'replying': replies, - } - - return flask.render_template('comments_page.html', comments_info = comments_info, - comment_posting_box_info = comment_posting_box_info, slim = request.args.get('slim', False) ) diff --git a/youtube/post_comment.py b/youtube/post_comment.py deleted file mode 100644 index 0bf0cf5..0000000 --- a/youtube/post_comment.py +++ /dev/null @@ -1,181 +0,0 @@ -# Contains functions having to do with posting/editing/deleting comments -from youtube import util, proto, comments, accounts -from youtube import yt_app -import settings - -import urllib -import json -import re -import traceback -import os - -import flask -from flask import request - -def _post_comment(text, video_id, session_token, cookiejar): - headers = { - 'User-Agent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 10_3_1 like Mac OS X) AppleWebKit/603.1.30 (KHTML, like Gecko) Version/10.0 Mobile/14E304 Safari/602.1', - 'Accept': '*/*', - 'Accept-Language': 'en-US,en;q=0.5', - 'X-YouTube-Client-Name': '2', - 'X-YouTube-Client-Version': '2.20180823', - 'Content-Type': 'application/x-www-form-urlencoded', - } - - comment_params = proto.string(2, video_id) + proto.nested(5, proto.uint(1, 0)) + proto.uint(10, 1) - comment_params = proto.percent_b64encode(comment_params).decode('ascii') - - sej = json.dumps({"clickTrackingParams":"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=", "commandMetadata":{"webCommandMetadata":{"url":"/service_ajax","sendPost":True}},"createCommentEndpoint":{"createCommentParams": comment_params}}) - - data_dict = { - 'comment_text': text, - 'sej': sej, - 'session_token': session_token, - } - data = urllib.parse.urlencode(data_dict).encode() - - - content = util.fetch_url("https://m.youtube.com/service_ajax?name=createCommentEndpoint", headers=headers, data=data, cookiejar_send=cookiejar, debug_name='post_comment') - - code = json.loads(content)['code'] - print("Comment posting code: " + code) - return code - - -def _post_comment_reply(text, video_id, parent_comment_id, session_token, cookiejar): - headers = { - 'User-Agent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 10_3_1 like Mac OS X) AppleWebKit/603.1.30 (KHTML, like Gecko) Version/10.0 Mobile/14E304 Safari/602.1', - 'Accept': '*/*', - 'Accept-Language': 'en-US,en;q=0.5', - 'X-YouTube-Client-Name': '2', - 'X-YouTube-Client-Version': '2.20180823', - 'Content-Type': 'application/x-www-form-urlencoded', - } - - comment_params = proto.string(2, video_id) + proto.string(4, parent_comment_id) + proto.nested(5, proto.uint(1, 0)) + proto.uint(6,0) + proto.uint(10, 1) - comment_params = proto.percent_b64encode(comment_params).decode('ascii') - - sej = json.dumps({"clickTrackingParams":"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=", "commandMetadata":{"webCommandMetadata":{"url":"/service_ajax","sendPost":True}},"createCommentReplyEndpoint":{"createReplyParams": comment_params}}) - - data_dict = { - 'comment_text': text, - 'sej': sej, - 'session_token': session_token, - } - data = urllib.parse.urlencode(data_dict).encode() - - content = util.fetch_url("https://m.youtube.com/service_ajax?name=createCommentReplyEndpoint", headers=headers, data=data, cookiejar_send=cookiejar, debug_name='post_reply') - - code = json.loads(content)['code'] - print("Comment posting code: " + code) - return code - -def _delete_comment(video_id, comment_id, session_token, cookiejar): - headers = { - 'User-Agent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 10_3_1 like Mac OS X) AppleWebKit/603.1.30 (KHTML, like Gecko) Version/10.0 Mobile/14E304 Safari/602.1', - 'Accept': '*/*', - 'Accept-Language': 'en-US,en;q=0.5', - 'X-YouTube-Client-Name': '2', - 'X-YouTube-Client-Version': '2.20180823', - 'Content-Type': 'application/x-www-form-urlencoded', - } - action = proto.uint(1,6) + proto.string(3, comment_id) + proto.string(5, video_id) - action = proto.percent_b64encode(action).decode('ascii') - - sej = json.dumps({"clickTrackingParams":"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=","commandMetadata":{"webCommandMetadata":{"url":"/service_ajax","sendPost":True}},"performCommentActionEndpoint":{"action":action}}) - - data_dict = { - 'sej': sej, - 'session_token': session_token, - } - data = urllib.parse.urlencode(data_dict).encode() - - content = util.fetch_url("https://m.youtube.com/service_ajax?name=performCommentActionEndpoint", headers=headers, data=data, cookiejar_send=cookiejar) - code = json.loads(content)['code'] - print("Comment deletion code: " + code) - return code - -xsrf_token_regex = re.compile(r'''XSRF_TOKEN"\s*:\s*"([\w-]*(?:=|%3D){0,2})"''') -def get_session_token(video_id, cookiejar): - ''' Get session token for a video. This is required in order to post/edit/delete comments. This will modify cookiejar with cookies from youtube required for commenting''' - # youtube-dl uses disable_polymer=1 which uses a different request format which has an obfuscated javascript algorithm to generate a parameter called "bgr" - # Tokens retrieved from disable_polymer pages only work with that format. Tokens retrieved on mobile only work using mobile requests - # Additionally, tokens retrieved without sending the same cookie won't work. So this is necessary even if the bgr and stuff was reverse engineered. - headers = {'User-Agent': util.mobile_user_agent} - mobile_page = util.fetch_url('https://m.youtube.com/watch?v=' + video_id, headers, report_text="Retrieved session token for comment", cookiejar_send=cookiejar, cookiejar_receive=cookiejar).decode() - match = xsrf_token_regex.search(mobile_page) - if match: - return match.group(1).replace("%3D", "=") - else: - raise Exception("Couldn't find xsrf_token") - -@yt_app.route('/delete_comment', methods=['POST']) -def delete_comment(): - video_id = request.values['video_id'] - cookiejar = accounts.account_cookiejar(request.values['channel_id']) - token = get_session_token(video_id, cookiejar) - - code = _delete_comment(video_id, request.values['comment_id'], token, cookiejar) - - if code == "SUCCESS": - return flask.redirect(util.URL_ORIGIN + '/comment_delete_success', 303) - else: - return flask.redirect(util.URL_ORIGIN + '/comment_delete_fail', 303) - -@yt_app.route('/comment_delete_success') -def comment_delete_success(): - return flask.render_template('status.html', title='Success', message='Successfully deleted comment') - -@yt_app.route('/comment_delete_fail') -def comment_delete_fail(): - return flask.render_template('status.html', title='Error', message='Failed to delete comment') - -@yt_app.route('/post_comment', methods=['POST']) -@yt_app.route('/comments', methods=['POST']) -def post_comment(): - video_id = request.values['video_id'] - channel_id = request.values['channel_id'] - cookiejar = accounts.account_cookiejar(channel_id) - token = get_session_token(video_id, cookiejar) - - if 'parent_id' in request.values: - code = _post_comment_reply(request.values['comment_text'], request.values['video_id'], request.values['parent_id'], token, cookiejar) - return flask.redirect(util.URL_ORIGIN + '/comments?' + request.query_string.decode('utf-8'), 303) - else: - code = _post_comment(request.values['comment_text'], request.values['video_id'], token, cookiejar) - return flask.redirect(util.URL_ORIGIN + '/comments?ctoken=' + comments.make_comment_ctoken(video_id, sort=1), 303) - -@yt_app.route('/delete_comment', methods=['GET']) -def get_delete_comment_page(): - parameters = [(parameter_name, request.args[parameter_name]) for parameter_name in ('video_id', 'channel_id', 'comment_id')] - return flask.render_template('delete_comment.html', parameters = parameters) - - -@yt_app.route('/post_comment', methods=['GET']) -def get_post_comment_page(): - video_id = request.args['video_id'] - parent_id = request.args.get('parent_id', '') - - if parent_id: # comment reply - form_action = util.URL_ORIGIN + '/comments?parent_id=' + parent_id + "&video_id=" + video_id - replying = True - else: - form_action = '' - replying = False - - - comment_posting_box_info = { - 'form_action': form_action, - 'video_id': video_id, - 'accounts': accounts.account_list_data(), - 'include_video_id_input': not replying, - 'replying': replying, - } - return flask.render_template('post_comment.html', - comment_posting_box_info = comment_posting_box_info, - replying = replying, - ) - - - - diff --git a/youtube/templates/comments.html b/youtube/templates/comments.html index 32a67ad..8780e37 100644 --- a/youtube/templates/comments.html +++ b/youtube/templates/comments.html @@ -28,12 +28,9 @@ <a href="{{ comment['replies_url'] }}" class="replies-open-new-tab" target="_blank">Open in new tab</a> <div class="comment_page">loading..</div> </details> - {% else %} + {% elif comment['reply_count'] %} <a href="{{ comment['replies_url'] }}" class="replies">{{ comment['view_replies_text'] }}</a> {% endif %} - {% if 'delete_url' is in comment %} - <a href="{{ comment['delete_url'] }}" target="_blank">Delete</a> - {% endif %} </div> </div> @@ -56,25 +53,6 @@ {% endif %} {% endmacro %} -{% macro comment_posting_box(info) %} - <form action="{{ info['form_action'] }}" method="post" class="comment-form"> - <div id="comment-account-options"> - <label for="account-selection">Account:</label> - <select id="account-selection" name="channel_id"> - {% for account in info['accounts'] %} - <option value="{{ account[0] }}">{{ account[1] }}</option> - {% endfor %} - </select> - <a href="/https://youtube.com/login" target="_blank">Add account</a> - </div> - <textarea name="comment_text"></textarea> - {% if info['include_video_id_input'] %} - <input type="hidden" name="video_id" value="{{ info['video_id'] }}"> - {% endif %} - <button type="submit" class="post-comment-button">{{ 'Post reply' if info['replying'] else 'Post comment' }}</button> - </form> -{% endmacro %} - diff --git a/youtube/templates/comments_page.html b/youtube/templates/comments_page.html index 269ac83..2d914af 100644 --- a/youtube/templates/comments_page.html +++ b/youtube/templates/comments_page.html @@ -27,9 +27,6 @@ </section> {% endif %} - {% if not slim %} - {{ comments.comment_posting_box(comment_posting_box_info) }} - {% endif %} {% if not comments_info['is_replies'] %} <div class="comment-links"> diff --git a/youtube/templates/delete_comment.html b/youtube/templates/delete_comment.html deleted file mode 100644 index 28c8f2a..0000000 --- a/youtube/templates/delete_comment.html +++ /dev/null @@ -1,21 +0,0 @@ -{% set page_title = 'Delete comment?' %} -{% extends "base.html" %} - -{% block style %} - main > div, main > form{ - margin: auto; - margin-top:20px; - width: 640px; - } -{% endblock style %} - -{% block main %} - <div>Are you sure you want to delete this comment?</div> - <form action="" method="POST"> - {% for parameter_name, parameter_value in parameters %} - <input type="hidden" name="{{ parameter_name }}" value="{{ parameter_value }}"> - {% endfor %} - <input type="submit" value="Yes, delete it"> - </form> -{% endblock %} - diff --git a/youtube/templates/login.html b/youtube/templates/login.html deleted file mode 100644 index 384f1ac..0000000 --- a/youtube/templates/login.html +++ /dev/null @@ -1,57 +0,0 @@ -{% set page_title = 'Login' %} -{% extends "base.html" %} - -{% block style %} - main > * { - width: 640px; - margin: auto; - } - main form{ - background-color: var(--interface-color); - padding: 10px; - margin-top:20px; - display:grid; - justify-items: start; - align-content: start; - grid-row-gap: 10px; - } - - #username, #password{ - grid-column:2; - width: 250px; - } - #add-account-button{ - margin-top:20px; - } - #tor-note{ - background-color: var(--interface-color); - padding: 10px; - margin-top: 40px; - } -{% endblock style %} - -{% block main %} - <form action="" method="POST"> - <div class="form-field"> - <label for="username">Username:</label> - <input type="text" id="username" name="username"> - </div> - <div class="form-field"> - <label for="password">Password:</label> - <input type="password" id="password" name="password"> - </div> - <div id="save-account-checkbox"> - <input type="checkbox" id="save-account" name="save" checked> - <label for="save-account">Save account info to disk (password will not be saved, only the login cookie)</label> - </div> - <div> - <input type="checkbox" id="use-tor" name="use_tor"> - <label for="use-tor">Use Tor when logging in (WARNING: This will lock your Google account under normal circumstances, see note below)</label> - </div> - <input type="submit" value="Add account" id="add-account-button"> - </form> - <div id="tor-note"><b>Note on using Tor to log in</b><br> -Using Tor to log in should only be done if the account was created using a proxy/VPN/Tor to begin with and hasn't been logged in using your IP. Otherwise, it's pointless since Google already knows who the account belongs to. When logging into a google account, it must be logged in using an IP address geographically close to the area where the account was created or where it is logged into regularly. If the account was created using an IP address in America and is logged into from an IP in Russia, Google will block the Russian IP from logging in, assume someone knows your password, lock the account, and make you change your password. If creating an account using Tor, you must remember the IP (or geographic region) it was created in, and only log in using that geographic region for the exit node. This can be accomplished by <a href="https://tor.stackexchange.com/questions/733/can-i-exit-from-a-specific-country-or-node">putting the desired IP in the torrc file</a> to force Tor to use that exit node. Using the login cookie to post comments through Tor is perfectly safe, however. - </div> -{% endblock main %} - diff --git a/youtube/templates/post_comment.html b/youtube/templates/post_comment.html deleted file mode 100644 index ba6a22c..0000000 --- a/youtube/templates/post_comment.html +++ /dev/null @@ -1,20 +0,0 @@ -{% set page_title = 'Post reply' if replying else 'Post comment' %} -{% extends "base.html" %} -{% import "comments.html" as comments %} - -{% block style %} - .comment-form{ - width: 640px; - margin: auto; - justify-content:start; - } - textarea{ - width: 460px; - height: 85px; - } -{% endblock style %} - -{% block main %} - {{ comments.comment_posting_box(comment_posting_box_info) }} -{% endblock %} - |