diff --git a/.local/bin/channelrefresh b/.local/bin/channelrefresh new file mode 100644 index 00000000..a5831bb4 --- /dev/null +++ b/.local/bin/channelrefresh @@ -0,0 +1,61 @@ +#!/bin/dash +while ! ping -c 1 "9.9.9.9"; do sleep "0.5"; done +dd="${XDG_CACHE_HOME}/ychannels" +chl="${XDG_DATA_HOME}/channels" +ctg="${XDG_DATA_HOME}/categories" +n() { notify-send -i "${XDG_CONFIG_HOME}/dunst/yt.png" -u "critical" "${1}"; } + +eh() { + [ ! -s "${chl}" ] && [ ! -s "${ctg}" ] && { + printf "%s\n" \ + "Luke Smith=https://www.youtube.com/@LukeSmithxyz/videos" \ + "Mental Outlaw=https://www.youtube.com/@MentalOutlaw/videos" \ + > "${chl}" + printf "%s\n" "Tech=Luke Smith|Mental Outlaw" > "${ctg}" + sudo pacman -S --needed --noconfirm mpv yt-dlp jq || n "Failed to install mpv jq yt-dlp" + } +} + +mkdir -p "${dd}" && touch "${chl}" +comd() { + chn="${1}" + df="${dd}/${chn}.tsv" + odf="${dd}/${chn}_old.tsv" + [ -f "${odf}" ] && { + ou="$(cut -f2 "${odf}")" + nu="$(cut -f2 "${df}")" + printf "%s\n" "${ou}" | sort > "t1" + printf "%s\n" "${nu}" | sort > "t2" + nv="$(comm -13 "t1" "t2" | wc -l)" + rm -f "t1" "t2" + [ "${nv}" -gt "0" ] && n "${chn} | ${nv} videos." + } +} +ud() { + chn="${1}" + cu="${2}" + df="${dd}/${chn}.tsv" + odf="${dd}/${chn}_old.tsv" + mv -f "${df}" "${odf}" 2> "/dev/null" + yt-dlp -j --flat-playlist --skip-download --extractor-args \ + "youtubetab:approximate_date" "${cu}" | + jq -r '[.title, .url, .view_count, .duration, .upload_date] | @tsv' > "${df}" +} +uac() { + while IFS="=" read -r chn cu; do + ud "${chn}" "${cu}" & + done < "${chl}" + wait + while IFS="=" read -r chn cu; do + comd "${chn}" + done < "${chl}" + + avf="${dd}/all_videos.tsv" + rm -f "${avf}" + while IFS= read -r line; do + cn="${line%%=*}" + cat "${dd}/${cn}.tsv" >> "${avf}" + done < "${chl}" +} +eh +uac diff --git a/.local/bin/ybrowser b/.local/bin/ybrowser new file mode 100644 index 00000000..4ec5124d --- /dev/null +++ b/.local/bin/ybrowser @@ -0,0 +1,186 @@ +#!/bin/sh +dd="${XDG_CACHE_HOME}/ychannels" +yd="${HOME}/ytvideos" +cl="${XDG_DATA_HOME}/categories" +chl="${XDG_DATA_HOME}/channels" +cld="${XDG_DATA_HOME}/clists" +mkdir -p "${dd}" "${yd}" "${cld}" +pr() { printf "%s\n" "${@}"; } +d() { + i="$(cat)" + l="$(pr "${i}" | wc -l)" + [ "${l}" -gt "21" ] && l="21" + [ "${i}" ] || l="0" + pr "${i}" | dmenu -i -l "${l}" -p "${1}" +} +n() { notify-send -i "${XDG_CONFIG_HOME}/dunst/yt.png" "${1}"; } +sv() { + df="${1}" + so="${2}" + case "${so}" in + "@@sv") sort -nr -t" " -k3 "${df}" ;; + "@@sd") sort -nr -t" " -k4 "${df}" ;; + *) sort -nr -t" " -k5 "${df}" ;; + esac | cut -f1 +} +gv() { + cn="${1}" + so="${2}" + df="${dd}/${cn}.tsv" + sv "${df}" "${so}" +} +vu() { + cn="${1}" + vt="${2}" + df="${dd}/${cn}.tsv" + grep -F "${vt}" "${df}" | cut -f2 +} +ma() { + pr "WATCH" "DOWNLOAD" "SEND TO A LIST" | d "Actions" +} +ca() { + lsts="$(pr "${cld}"/* | sed 's|.*/||')" + [ "${lsts}" = "*" ] && lsts="" + pr "${lsts}" "## CREATE LIST ##" "## DELETE LIST ##" | d "Lists" +} +lva() { + pr "WATCH" "DOWNLOAD" "DELETE" | d "Actions" +} +atl() { + vt="${1}" + cn="${2}" + ln="${3}" + pr "${cn}: ${vt}" >> "${cld}/${ln}" +} +clm() { + while true; do + lst="$(ca)" + case "${lst}" in + "## CREATE LIST ##") + nlst="$(pr | d "Name")" + [ "${nlst}" ] && touch "${cld}/${nlst}" + ;; + "## DELETE LIST ##") + dlst="$(find "${cld}" -mindepth "1" -exec basename {} \; | d "Delete List")" + [ "${dlst}" ] && rm -f "${cld}/${dlst}" + ;; + "") return ;; + *) cvm "${lst}" ;; + esac + done +} +cvm() { + ln="${1}" + while true; do + vi=$(d "Videos" < "${cld}/${ln}") + [ "${vi}" ] || return + cn="${vi%%: *}" + vt="${vi##*: }" + clvm "${vt}" "${cn}" "${ln}" + done +} +clvm() { + vt="${1}" + cn="${2}" + ln="${3}" + ac="$(lva)" + case "${ac}" in + "WATCH") vp "${ac}" "${vt}" "${cn}" ;; + "DOWNLOAD") vp "${ac}" "${vt}" "${cn}" && n "Download finished" ;; + "DELETE") sed -i "/${vt}/d" "${cld}/${ln}" ;; + *) return ;; + esac +} +vp() { + ac="${1}" + vt="${2}" + cn="${3}" + vu="$(vu "${cn}" "${vt}")" + case "${ac}" in + "WATCH") mpv "${vu}" ;; + "DOWNLOAD") + cdd="${yd}/${cn}" + mkdir -p "${cdd}" + yt-dlp -o "${cdd}/%(title)s.%(ext)s" "${vu}" + n "Download finished" + ;; + esac +} +gav() { + so="${1}" + avf="${dd}/all_videos.tsv" + sv "${avf}" "${so}" +} +bac() { + while vt="$(gav | d "Videos | Sort: @@s{v,d}")"; do + [ "${vt}" ] || break + [ "${vt}" = "@@sv" ] || [ "${vt}" = "@@sd" ] && { + vt=$(gav "${vt}" | d "Videos") + [ "${vt}" ] || continue + } + grep -lF "${vt}" "${dd}"/*.tsv | head -n "1" | while read -r "vf"; do + vam "${vt}" "$(basename "${vf}" .tsv)" + break + done + done +} +cm() { + while true; do + c="$(cut -d= -f1 "${cl}" | d "Categories")" + [ "${c}" ] || return + chm "${c}" + done +} +chm() { + c="${1}" + IFS="|" + ch="$(sed -n "s/^${c}=\(.*\)$/\1/p" "${cl}")" + set -- ${ch} + while true; do + cn="$(pr "${@}" | d "Channels")" + [ "${cn}" ] || return + vm "${cn}" + done +} +vm() { + cn="${1}" + while true; do + vt=$(gv "${cn}" | d "Videos") + [ "${vt}" ] || return + [ "${vt}" = "@@sv" ] || [ "${vt}" = "@@sd" ] && { + so="${vt}" + vt="$(gv "${cn}" "${so}" | d "Videos")" + } + vam "${vt}" "${cn}" + done +} +vam() { + vt="${1}" + cn="${2}" + while [ "${vt}" ] && [ "${vt}" != "@@sv" ] && [ "${vt}" != "@@sd" ]; do + ac="$(ma)" + case "${ac}" in + "WATCH") vp "${ac}" "${vt}" "${cn}" ;; + "DOWNLOAD") vp "${ac}" "${vt}" "${cn}" && n "Download finished" ;; + "SEND TO A LIST") + ln="$(find "${cld}" -mindepth "1" -exec basename {} \; | d "Lists")" + [ "${ln}" ] && atl "${vt}" "${cn}" "${ln}" && n "${vt} > list: ${ln}" + ;; + *) return ;; + esac + done +} +mm() { + pr " ## ALL CHANNELS ##" " ## CATEGORIES ##" " ## CUSTOM LISTS ##" \ + "$(cut -d= -f1 "${chl}")" | d "YouTube" +} +while true; do + mc="$(mm)" + case "${mc}" in + " ## ALL CHANNELS ##") bac ;; + " ## CATEGORIES ##") cm ;; + " ## CUSTOM LISTS ##") clm ;; + "") exit ;; + *) vm "${mc}" ;; + esac +done