# Uses variables as input:
# $media for image file path.
# $alt_text for image alt text.
+#
+# -PROFILE_NAME Either dbd or fsf. Defaults to whatever was used last.
+#
+# Note retweeting cannot be done with the gratis api level. I suggest
+# posting a message like: 'Retweet:
+# https://nitter.net/fsf/status/1726382360826958325'
tweet() {
local keys_file
keys_file=$_pdtsh_dir/twitter_keys.py
deactivate
}
-# usage: tweetrm [-PROFILE_NAME] POST_ID
-#
-# Delete twitter post. Post id is the number at end of a url like:
-# https://nitter.net/user/status/1725640623149969527
-#
-# -PROFILE_NAME Either dbd or fsf.
-#
-tweetrm() {
- local keys_file
+_pdtsh-tweet-option() {
+ local keys_file option
+ option=$1
+ shift
keys_file=$_pdtsh_dir/twitter_keys.py
if [[ $1 == -* ]]; then
rm -f $keys_file
ln -s $keys_file$1 $keys_file
shift
fi
-
# shellcheck disable=SC1090 # not relevant to this script
source ~/src/tweepy/venv/bin/activate
- $_pdtsh_tweet $1 || { deactivate; return 1; }
+ $_pdtsh_tweet $option $1 || { deactivate; return 1; }
deactivate
}
+# usage: tweetrm [-PROFILE_NAME] POST_ID
+#
+# Delete twitter post. Post id is the number at end of a url like:
+# https://nitter.net/user/status/1725640623149969527
+#
+# -PROFILE_NAME Either dbd or fsf. Defaults to whatever was used last.
+tweetrm() {
+ _pdtsh-tweet-option --delete "$@"
+}
+
+
+
+# usage: pin-tweet [-PROFILE_NAME] POST_ID
+#
+# Pin twitter post. Post id is the number at end of a url like:
+# https://nitter.net/user/status/1725640623149969527
+#
+# -PROFILE_NAME Either dbd or fsf. Defaults to whatever was used last.
+#
+pin-tweet() {
+ _pdtsh-tweet-option --pin "$@"
+}
+
+# usage: unpin-tweet [-PROFILE_NAME] POST_ID
+#
+# Unpin twitter post. Post id is the number at end of a url like:
+# https://nitter.net/user/status/1725640623149969527
+#
+# -PROFILE_NAME Either dbd or fsf. Defaults to whatever was used last.
+#
+unpin-tweet() {
+ _pdtsh-tweet-option --unpin "$@"
+}
+
+
+# usage: twitter-banner [-PROFILE_NAME] IMAGE_PATH
+#
+# IMAGE_PATH Path to jpg or png, 1500 px by 500px.
+#
+# -PROFILE_NAME Either dbd or fsf. Defaults to whatever was used last.
+#
+twitter-banner() {
+ _pdtsh-tweet-option --banner "$@"
+}
+
# usage: toot [-PROFILE_NAME] [TOOT_ARGS]
toot() {
}
-# post to mastodon + twitter.
-#
-# Gnu Social posting code exists, but we aren't using it. You would need
-# to run pdt-gnusocial-setup beforehand. Alt text does not work on
-# gnusocial.
+# post to mastodon and/org twitter.
#
# usage:
# pdt [-s mastodon|twitter|gnusocial] [--dbd] [-m IMAGE_FILE] [-a ALT_TEXT] [POST]
#
-# -s mastodon|twitter|gnusocial = post to a single social network.
-# -m IMAGE_FILE = Uploads IMAGE_FILE. if MEDIA_FILE.txt exists, the last line of that file will be used as ALT_TEXT
-# unless -a has been used.
+# -s mastodon|twitter|gnusocial Post to a single social network.
+#
+# -m IMAGE_FILE Uploads IMAGE_FILE. if MEDIA_FILE.txt exists, the last
+# line of that file will be used as ALT_TEXT unless -a
+# has been used.
#
# POST can have have some special markup for twitter to deal with the 280 character limit:
-# /tnt/ short for "twitter next tweet", The /tnt/ will be removed, and the tweet split into 2 at that point.
-# /teof/ means twitter end of file. It will be removed, and text after it won't be posted to twitter.
#
-# If you have some pdt arguments in a file, FILE, and you want to test if they are under 280 chars, you can run:
+# * /tnt/ short for "twitter next tweet". /tnt/ will be removed, and the
+# tweet will be split into 2 at that point.
+#
+# * /teof/ short for "twitter end of file." It will be removed and text
+# after it won't be posted to twitter. An example of how this is
+# useful: You write a post which is 284 characters. Instead of
+# splitting it in 2 for twitter, you could put the least important
+# hash tag and the end and omit it on twitter.
+#
+# Twitter considers all urls to be 23 characters. To measure the length
+# of arguments in a file, run this (replace FILE).
#
-# sed -r 's,/teof/.*,,;s/-(m|a|-dbd) [^ ]*//;s,https?://[^ ]*,https://xxxxxxxxxxxxxxx,g' FILE | awk '$0 !~ /\/tnt\// && length > 280 {print length, $0}'
+# sed -r 's,/teof/.*,,;s/ *-(m|a|-dbd) [^ ]*//;s,https?://[^ ]*,https://xxxxxxxxxxxxxxx,g' FILE | awk '$0 !~ /\/tnt\// && length > 280 {print length, $0}'
#
# broken usage:
# pdt [-v VIDEO_PATH] [POST]
#
+# Outdated usage:
+#
+# Gnu Social posting code exists, but we aren't using it. You would need
+# to run pdt-gnusocial-setup beforehand. Alt text does not work on
+# gnusocial.
+#
pdt() {
local video media twitter_account gs_account mastodon_account video gs_arg network
local do_mastodon do_twitter do_gnusocial
# sudo ln -s /home/iank/.local/bin/pip /usr/bin
#
python3 -m virtualenv -p python3 venv
- # shellcheck disable=SC1090 # not relevant to this script
+ # shellcheck disable=SC1091 # not relevant to this script
source venv/bin/activate
# pip freeze after a pip install, as of 2022-11-28
cat >requirements.txt <<'EOF'
(
cd ~/src/tweepy
python3 -m virtualenv -p python3 venv
- # shellcheck disable=SC1090 # not relevant to this script
+ # shellcheck disable=SC1091 # not relevant to this script
source venv/bin/activate
python3 -m pip install .
)
mkdir -p ~/src
for repo in errhandle video-tweet; do
- if [[ -e ~/src/$repo ]]; then
- (
- cd ~/src/$repo
- git fetch
- git reset --hard origin/master
- git clean -xfffd
- )
+ if [[ -e ~/src/$repo/.git ]]; then
+ if git -C ~/src/$repo remote -v | grep -E "^origin[[:space:]]+git@vcs.fsf.org:$repo.git" &>/dev/null; then
+ git -C ~/src/$repo fetch
+ git -C ~/src/$repo reset --hard origin/master
+ git -C ~/src/$repo clean -xfffd
+ else
+ rm -rf ~/src/$repo
+ git clone https://vcs.fsf.org/git/$repo.git ~/src/$repo
+ fi
else
git clone https://vcs.fsf.org/git/$repo.git ~/src/$repo
fi
done
- if [[ -e ~/src/tweepy ]]; then
- (
- cd ~/src/tweepy
- git fetch
- git reset --hard f32d12dbddbd877470446657812a10a04292d0c9
- git clean -xfffd
- )
- else
- git clone https://github.com/tweepy/tweepy.git ~/src/tweepy
- fi
-
# shellcheck disable=SC1090 # tested separately
source ~/src/errhandle/err
# Usage: see pdt.sh example.
import sys
-import tweepy
import time
+import tweepy
from twitter_keys import *
+# for debugging:
+# import logging
+# logging.basicConfig(level=logging.DEBUG)
auth = tweepy.OAuth1UserHandler(
consumer_key, consumer_secret, access_token, access_token_secret
consumer_key=consumer_key, consumer_secret=consumer_secret,
access_token=access_token, access_token_secret=access_token_secret
)
-
-if len(sys.argv) == 2:
- response = client.delete_tweet(sys.argv[1])
+verbose = False
+
+if len(sys.argv) == 2 and sys.argv[1] == "-v":
+ verbose = True
+
+if len(sys.argv) == 3:
+ if sys.argv[1] == '--delete':
+ client.delete_tweet(sys.argv[2])
+ elif sys.argv[1] == '--pin':
+ api.pin_tweet(sys.argv[2])
+ elif sys.argv[1] == '--unpin':
+ api.unpin_tweet(sys.argv[2])
+ elif sys.argv[1] == '--banner':
+ api.update_profile_banner(sys.argv[2])
+ else:
+ print("t.py: error: unexpected argument. exiting without doing anything")
+ sys.exit(1)
else:
input_text = input()
if post_count > 1:
tweet_text=tweet_text + f" 1/{post_count}"
- have_image = False
+ have_image = True
try:
image_path = input()
- have_image = True
- except:
- pass
+ except EOFError:
+ have_image = False
- have_alt = False
+ have_alt = True
try:
alt = input()
- have_alt = True
- except:
- pass
+ except EOFError:
+ have_alt = False
+
if have_image:
media = api.media_upload(image_path)
media_id = media.media_id_string
if have_image:
response = client.create_tweet(text=tweet_text, media_ids=[media_id])
else:
- #print(tweet_text)
response = client.create_tweet(text=tweet_text)
- print(f"https://nitter.net/user/status/{response.data['id']}")
+ if verbose:
+ print(f"https://nitter.net/user/status/{response.data['id']}")
if post_count > 1:
for x in range(1, post_count):
time.sleep(1)
tweet_text=posts[x].strip() + f" {x+1}/{post_count}"
response = client.create_tweet(text=tweet_text, in_reply_to_tweet_id=response.data['id'])
- print(f"{x+1}/{post_count} https://nitter.net/user/status/{response.data['id']}")
- #print(tweet_text)
+ if verbose:
+ print(f"{x+1}/{post_count} https://nitter.net/USER/status/{response.data['id']}")