Compare commits
10 Commits
bf5117c655
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
| 66f2f852f2 | |||
| 0c273bb02c | |||
| a2846eb4a3 | |||
| 6be68d0538 | |||
| 11c2cf9b1d | |||
| b72d79b987 | |||
|
|
89fe982535 | ||
| df1d74b2fc | |||
| 4fd4316e51 | |||
| ad67e8279f |
0
.travis.yml
Normal file → Executable file
0
.travis.yml
Normal file → Executable file
2
README.md
Normal file → Executable file
2
README.md
Normal file → Executable file
@@ -14,7 +14,7 @@ I'm a fan of command line and "doing things yourself".
|
|||||||
I also don't like having a Google account, but still want to keep track of subscriptions.
|
I also don't like having a Google account, but still want to keep track of subscriptions.
|
||||||
Thus [subs](http://github.com/mitchweaver/subs) was born.
|
Thus [subs](http://github.com/mitchweaver/subs) was born.
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
## Environment
|
## Environment
|
||||||
|
|
||||||
|
|||||||
137
subs
137
subs
@@ -1,4 +1,12 @@
|
|||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
|
# █████
|
||||||
|
# ▒▒███
|
||||||
|
# █████ █████ ████ ▒███████ █████
|
||||||
|
# ███▒▒ ▒▒███ ▒███ ▒███▒▒███ ███▒▒
|
||||||
|
# ▒▒█████ ▒███ ▒███ ▒███ ▒███▒▒█████
|
||||||
|
# ▒▒▒▒███ ▒███ ▒███ ▒███ ▒███ ▒▒▒▒███
|
||||||
|
# ██████ ▒▒████████ ████████ ██████
|
||||||
|
# ▒▒▒▒▒▒ ▒▒▒▒▒▒▒▒ ▒▒▒▒▒▒▒▒ ▒▒▒▒▒▒
|
||||||
#
|
#
|
||||||
# Watch your youtube subscriptions without a youtube account
|
# Watch your youtube subscriptions without a youtube account
|
||||||
# via curl, dmenu, mpv and basic unix commands.
|
# via curl, dmenu, mpv and basic unix commands.
|
||||||
@@ -9,16 +17,22 @@
|
|||||||
# For more information and examples, see:
|
# For more information and examples, see:
|
||||||
# http://github.com/mitchweaver/subs
|
# http://github.com/mitchweaver/subs
|
||||||
#
|
#
|
||||||
|
# >> note: this is highly experimental / janky, it can and will break <<
|
||||||
|
#
|
||||||
# -/-/-/-/- Settings -/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/
|
# -/-/-/-/- Settings -/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/
|
||||||
: "${SUBS_FILE:=~/files/subs.txt}"
|
: "${SUBS_FILE:=~/files/subs.txt}"
|
||||||
: "${SUBS_MENU_PROG:='dmenu -p Subs:'}"
|
: "${SUBS_MENU_PROG:=dmenu -l 18 -p Subs:}"
|
||||||
: "${SUBS:=${XDG_CACHE_HOME:-~/.cache}/subs}"
|
: "${SUBS:=${XDG_CACHE_HOME:-~/.cache}/subs}"
|
||||||
: "${SUBS_LINKS:=$SUBS/links}"
|
: "${SUBS_LINKS:=$SUBS/links}"
|
||||||
: "${SUBS_CACHE:=$SUBS/cache}"
|
: "${SUBS_CACHE:=$SUBS/cache}"
|
||||||
: "${SUBS_SLEEP_VALUE:=0.05}" # raise this if you experience problems
|
: "${SUBS_SLEEP_VALUE:=1}" # raise this if you experience problems
|
||||||
|
: "${SUBS_DAEMON_INTERVAL:=600}"
|
||||||
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
SEP=^^^^^ # shouldn't need to change this
|
SEP=^^^^^ # shouldn't need to change this
|
||||||
# -/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/
|
# -/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/
|
||||||
|
export LC_ALL=C # this speeds things up a bit but can cause
|
||||||
|
# issues for titles in foreign languages
|
||||||
|
# -/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/
|
||||||
|
|
||||||
die() {
|
die() {
|
||||||
>&2 printf '%s\n' "$*"
|
>&2 printf '%s\n' "$*"
|
||||||
@@ -26,7 +40,7 @@ die() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
usage() {
|
usage() {
|
||||||
die 'Usage: subs [-m no-video] [-g gen-links] [-u update-cache] [-d daemonize]'
|
die 'Usage: subs [-m no-video] [-g gen-links] [-u update-cache] [-d daemonize] [-n dont-play]'
|
||||||
}
|
}
|
||||||
|
|
||||||
# -*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
|
# -*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
|
||||||
@@ -40,6 +54,7 @@ gen_links() {
|
|||||||
|
|
||||||
count=0
|
count=0
|
||||||
total=$(sed -e '/^$/d' -e '/^#/d' <"$SUBS_FILE" | wc -l)
|
total=$(sed -e '/^$/d' -e '/^#/d' <"$SUBS_FILE" | wc -l)
|
||||||
|
total=${total##* }
|
||||||
|
|
||||||
while read -r line ; do
|
while read -r line ; do
|
||||||
|
|
||||||
@@ -55,20 +70,31 @@ gen_links() {
|
|||||||
case $line in
|
case $line in
|
||||||
UC*)
|
UC*)
|
||||||
# YT channel IDs always begin with 'UC' and are 24 chars long
|
# YT channel IDs always begin with 'UC' and are 24 chars long
|
||||||
printf "[%s/%s] using channel ID '%s' for xml link\n" "$count" "$total" "$line"
|
if [ ${#line} -eq 24 ] ; then
|
||||||
|
printf "[%s/%s] using channel ID '%s' for xml link\n" "$count" "$total" "$line"
|
||||||
|
|
||||||
[ ${#line} -eq 24 ] &&
|
|
||||||
printf 'https://youtube.com/feeds/videos.xml?%s\n' \
|
printf 'https://youtube.com/feeds/videos.xml?%s\n' \
|
||||||
"channel_id=$line" >>"$SUBS_LINKS"
|
"channel_id=$line" >>"$SUBS_LINKS"
|
||||||
|
else
|
||||||
|
>&2 printf 'Error: cannot determine channel for %s\n' "$line"
|
||||||
|
fi
|
||||||
;;
|
;;
|
||||||
*)
|
*)
|
||||||
# otherwise we are given a username, we must find out its channel ID
|
# otherwise we are given a username, we must find out its channel ID
|
||||||
printf "fetching channel ID for %s...\n" "$line"
|
printf "Fetching channel ID for %s..." "$line"
|
||||||
|
|
||||||
curl -sfL --retry 10 "https://youtube.com/user/$line/about" | \
|
data=$(curl -sL --retry 10 "https://youtube.com/user/$line/about")
|
||||||
|
if printf '%s\n' "$data" | grep '404 Not Found' >/dev/null ; then
|
||||||
|
>&2 printf '\n[ERROR]: Could not determine channel for %s... 404\n' "$line"
|
||||||
|
>&2 printf '[%s] %s\n' "$(date)" "$line" >> "$SUBS"/ERRORS.log
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
printf '%s\n' "$data" | \
|
||||||
while read -r line ; do
|
while read -r line ; do
|
||||||
case $line in
|
case $line in
|
||||||
*channel/UC??????????????????????*)
|
*channel/UC??????????????????????*)
|
||||||
|
printf ' Found!\n'
|
||||||
line=${line##*channel/}
|
line=${line##*channel/}
|
||||||
line=${line%%\"*}
|
line=${line%%\"*}
|
||||||
printf "[%s/%s] using channel ID '%s' for xml link\n" "$count" "$total" "$line"
|
printf "[%s/%s] using channel ID '%s' for xml link\n" "$count" "$total" "$line"
|
||||||
@@ -76,18 +102,10 @@ gen_links() {
|
|||||||
"$line" >>"$SUBS_LINKS"
|
"$line" >>"$SUBS_LINKS"
|
||||||
break
|
break
|
||||||
esac
|
esac
|
||||||
done &
|
done
|
||||||
sleep "${SUBS_SLEEP_VALUE:-0}"
|
|
||||||
esac
|
esac
|
||||||
|
|
||||||
done <"$SUBS_FILE"
|
done <"$SUBS_FILE"
|
||||||
|
|
||||||
count=0
|
|
||||||
while [ "$count" -ne "$total" ] ; do
|
|
||||||
count=$(wc -l < "$SUBS_LINKS")
|
|
||||||
printf "[%s/%s] waiting for jobs to complete...\n" "$count" "$total"
|
|
||||||
sleep 0.5
|
|
||||||
done
|
|
||||||
}
|
}
|
||||||
|
|
||||||
# -*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
|
# -*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
|
||||||
@@ -97,7 +115,13 @@ gen_links() {
|
|||||||
# with a line of its videos dates, titles, and urls.
|
# with a line of its videos dates, titles, and urls.
|
||||||
# -*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
|
# -*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
|
||||||
get_vids() {
|
get_vids() {
|
||||||
data=$(curl -sfL --retry 15 "$1")
|
data=$(curl -sL --retry 15 "$1")
|
||||||
|
|
||||||
|
if printf '%s\n' "$data" | grep '404 Not Found' >/dev/null ; then
|
||||||
|
>&2 printf '[ERROR]: Could not get vids for %s... 404\n' "$1"
|
||||||
|
>&2 printf '[%s] %s\n' "$(date)" "$1" >> "$SUBS"/ERRORS.log
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
# hide the first <published> tag which is the channel
|
# hide the first <published> tag which is the channel
|
||||||
# creation date
|
# creation date
|
||||||
@@ -134,6 +158,7 @@ get_vids() {
|
|||||||
|
|
||||||
# -*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
|
# -*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
|
||||||
# Updates the local cache of subscriptions. ([-u] flag)
|
# Updates the local cache of subscriptions. ([-u] flag)
|
||||||
|
# shellcheck disable=2086
|
||||||
# -*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
|
# -*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
|
||||||
update_subs() {
|
update_subs() {
|
||||||
[ -f "$SUBS_LINKS" ] || die 'Subs links have not been generated.'
|
[ -f "$SUBS_LINKS" ] || die 'Subs links have not been generated.'
|
||||||
@@ -142,6 +167,7 @@ update_subs() {
|
|||||||
mkdir -p "$SUBS_CACHE"
|
mkdir -p "$SUBS_CACHE"
|
||||||
|
|
||||||
total=$(wc -l <"$SUBS_LINKS")
|
total=$(wc -l <"$SUBS_LINKS")
|
||||||
|
total=${total##* }
|
||||||
|
|
||||||
count=0
|
count=0
|
||||||
while read -r link ; do
|
while read -r link ; do
|
||||||
@@ -152,10 +178,13 @@ update_subs() {
|
|||||||
done <"$SUBS_LINKS"
|
done <"$SUBS_LINKS"
|
||||||
|
|
||||||
count=0
|
count=0
|
||||||
while [ "$count" -ne "$total" ] ; do
|
max_retries=$total
|
||||||
|
while [ "$count" -ne "$total" ] && [ "$max_retries" -ne "$total" ] ; do
|
||||||
count=$(printf '%s\n' "$SUBS_CACHE"/* | wc -l)
|
count=$(printf '%s\n' "$SUBS_CACHE"/* | wc -l)
|
||||||
|
count=${count##* }
|
||||||
printf "[%s/%s] waiting for fetch jobs to complete...\n" "$count" "$total"
|
printf "[%s/%s] waiting for fetch jobs to complete...\n" "$count" "$total"
|
||||||
sleep 0.5
|
sleep 1
|
||||||
|
max_retries=$(( max_retries + 1 ))
|
||||||
done
|
done
|
||||||
|
|
||||||
printf '%s\n\n' 'done!'
|
printf '%s\n\n' 'done!'
|
||||||
@@ -182,25 +211,31 @@ cat_subs() {
|
|||||||
# Finally, play the result with mpv.
|
# Finally, play the result with mpv.
|
||||||
get_sel() {
|
get_sel() {
|
||||||
if [ -d "$SUBS_CACHE" ] ; then
|
if [ -d "$SUBS_CACHE" ] ; then
|
||||||
sel=$(cat_subs | $SUBS_MENU_PROG)
|
# Pipe your subs feed into your desired menu and replace HTML escape codes (" -> ")
|
||||||
|
sel=$(cat_subs | sed -e 's/"/"/g' -e 's/&/\&/g' -e 's/</</g' -e 's/>/>/g' | $SUBS_MENU_PROG)
|
||||||
else
|
else
|
||||||
die 'Subs cache has not been retrieved.'
|
die 'Subs cache has not been retrieved.'
|
||||||
fi
|
fi
|
||||||
|
|
||||||
[ "$sel" ] || die Interrupted
|
[ "$sel" ] || die Interrupted
|
||||||
|
|
||||||
chan="${sel#* }"
|
oldchan="${sel#* }"
|
||||||
chan="${chan%%] *}"
|
chan=$(printf '%s' "${oldchan%%] *}" | sed -e 's/\&/&/g' -e 's/"/\"/g' -e 's/</\</g' -e 's/>/\>/g' )
|
||||||
title=${sel#*"$chan"\] }
|
title=$(printf '%s' "${sel#*"${oldchan%%] *}"\] }" | sed -e 's/\&/&/g' -e 's/"/\"/g' -e 's/</\</g' -e 's/>/\>/g' )
|
||||||
while read -r line ; do
|
while read -r line ; do
|
||||||
case $line in
|
case $line in
|
||||||
*"$SEP$title$SEP"*)
|
*"$SEP$title$SEP"*)
|
||||||
url=${line##*$SEP}
|
url=${line##*$SEP}
|
||||||
if [ "$url" ] ; then
|
if [ "$url" ] ; then
|
||||||
printf 'playing: %s\n' "$url"
|
if [ "$DONT_PLAY" ] ; then
|
||||||
# Play the selection.
|
# just print the url
|
||||||
# shellcheck disable=2086
|
# (useful for piping to other programs)
|
||||||
exec mpv $MPV_OPTS "$url"
|
printf '%s\n' "$url"
|
||||||
|
else
|
||||||
|
printf 'playing: %s\n' "$url"
|
||||||
|
# shellcheck disable=2086
|
||||||
|
exec mpv $MPV_OPTS "$url"
|
||||||
|
fi
|
||||||
fi
|
fi
|
||||||
break
|
break
|
||||||
esac
|
esac
|
||||||
@@ -213,6 +248,7 @@ daemonize() {
|
|||||||
daemon_file=${XDG_CACHE_HOME:-~/.cache}/subs_daemon.cache
|
daemon_file=${XDG_CACHE_HOME:-~/.cache}/subs_daemon.cache
|
||||||
if [ ! -f "$daemon_file" ] ; then
|
if [ ! -f "$daemon_file" ] ; then
|
||||||
cp -f "${SUBS_FILE:=~/files/subs.txt}" "$daemon_file"
|
cp -f "${SUBS_FILE:=~/files/subs.txt}" "$daemon_file"
|
||||||
|
gen_links
|
||||||
fi
|
fi
|
||||||
|
|
||||||
while true ; do
|
while true ; do
|
||||||
@@ -221,29 +257,42 @@ daemonize() {
|
|||||||
cp -f "${SUBS_FILE:=~/files/subs.txt}" "$daemon_file"
|
cp -f "${SUBS_FILE:=~/files/subs.txt}" "$daemon_file"
|
||||||
fi
|
fi
|
||||||
update_subs
|
update_subs
|
||||||
interval=${SUBS_DAEMON_INTERVAL:-$(( 5 * 60 ))}
|
printf 'Sleeping for %s seconds...\n' "$SUBS_DAEMON_INTERVAL"
|
||||||
printf 'Sleeping for %s seconds...\n' "$interval"
|
sleep "$SUBS_DAEMON_INTERVAL"
|
||||||
sleep "$interval"
|
|
||||||
done
|
done
|
||||||
}
|
}
|
||||||
|
|
||||||
main() {
|
main() {
|
||||||
mkdir -p "$SUBS"
|
mkdir -p "$SUBS"
|
||||||
|
|
||||||
case ${1#-} in
|
if [ "$1" ] ; then
|
||||||
m)
|
case ${1#-} in
|
||||||
export MPV_OPTS="$MPV_OPTS --no-video"
|
g)
|
||||||
shift
|
gen_links
|
||||||
esac
|
;;
|
||||||
|
u)
|
||||||
case ${1#-} in
|
update_subs
|
||||||
h) usage ;;
|
;;
|
||||||
g) gen_links ;;
|
c)
|
||||||
u) update_subs ;;
|
cat_subs
|
||||||
c) cat_subs ;;
|
;;
|
||||||
d) daemonize ;;
|
d)
|
||||||
*) get_sel
|
daemonize
|
||||||
esac
|
;;
|
||||||
|
m)
|
||||||
|
MPV_OPTS="$MPV_OPTS --no-video" \
|
||||||
|
get_sel
|
||||||
|
;;
|
||||||
|
n)
|
||||||
|
DONT_PLAY=true \
|
||||||
|
get_sel
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
usage
|
||||||
|
esac
|
||||||
|
else
|
||||||
|
get_sel
|
||||||
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
main "$@"
|
main "$@"
|
||||||
|
|||||||
Reference in New Issue
Block a user