Compare commits

...

11 Commits

Author SHA1 Message Date
Emre AKYÜZ
a04bcd9ebf
Merge 395a277120fbbd148bf74ec650c5574aed48e93a into 86f05abcce1fd270032975775adb40040c746cfe 2023-08-25 21:04:17 +03:00
appeasementPolitik
86f05abcce
Fix the extra space between sb-internet and the block on the right of sb-internet (#1352) 2023-08-25 07:56:50 +00:00
Alessio Artoni
798ba175d0
Fix wrong font name (#1353) 2023-08-25 07:53:59 +00:00
Luke Smith
a360fadd5f
Merge branch 'master' of github.com:LukeSmithxyz/voidrice 2023-08-23 12:28:53 +02:00
Luke Smith
8315e4c885
libertinus replaces libertine 2023-08-23 12:28:42 +02:00
appeasementPolitik
f26e5678e6
Fix arkenfox pacman hook complaining about root (#1351)
The previous pull request on LARBS turned out not to work, so make sure `arkenfox-auto-update` runs `arkenfox-update` as the user of the firefox profile. Otherwise it complains that it's running as root and stops.

The way of getting the username is safe, because it gets the username from the owner of the user.js file of that profile.
2023-08-18 12:20:05 +00:00
Simon Nikolai Varøy
ed9633da3f
added webp to image formats in linkhandler (#1347)
Co-authored-by: Simon Nikolai Varøy <simon@simonvaroy.xyz>
2023-08-16 14:39:40 +00:00
appeasementPolitik
ec8e82745e
sb-internet: replace grep/sed commands for more efficiency (#1349) 2023-08-16 14:38:10 +00:00
appeasementPolitik
44cb5f12e6
Give setbg parameter to make notifications silent (#1350) 2023-08-16 13:55:59 +00:00
Emre AKYÜZ
395a277120
Add Approximate Date as Default 2023-05-30 10:59:59 +03:00
Emre AKYÜZ
8e7c55f586
The Ultimate Way of Browsing Channels
The script works extremely fast except the first time to update the whole data. It takes about 2 minutes to update the whole database with 80 different channels. You can set a cronjob for this. It's not a heavy work for the PC. It justs fetch the text data with yt-dlp. Video example below:

This script is a sophisticated and ingenious tool designed to streamline your YouTube experience by organizing and managing your favorite YouTube channels, allowing you to browse and watch videos directly within the script without ever visiting its website. You can assign the channels inside various categories such as "Tech", "Science", "Sports", etc. The videos can be played using the 'mpv' media player. Moreover, the script allows you to sort videos based on view count or duration; download videos; and even maintain a "Watch Later" list. If you combine this script with "SponsorBlock" lua script created for "mpv", then you will have the ultimate experience. SponsorBlock removes all sponsored segments in a video including intros, outros or similar unnecessary parts. It's normally a browser extension but is also available for "mpv".

No browsers, accounts, distractions, crappy algorithm and recommendations, advertisements, sponsors, intros, outros, fillers or empty spaces. We eliminate them all.

Required Programs: dmenu | mpv | jq | yt-dlp

FEATURES
1. Browse all videos from all channels you set at the same time. You can filter titles through dmenu.
2. Browse a channel's videos.
3. Select a channel either from the main menu or inside a Category.
4. Watch, Download or Put videos in a "Watch Later List".
5. Sort videos by view or duration. The default sort is upload date. The only problem is, we can't have the exact upload date, so we can't apply much more advanced filtering. It can be done but it makes fetching the data for the first time too slow.
6. The menus have a complex loop system. It always continues where you left off. The script doesn't close itself when you make a selection. So you don't have to run the script over and over again and get to where you left off. You can also press Escape to return to a prior menu.
7. You won't see the URLs or any unnecessary things inside dmenu. Just the titles.



JUSTIFICATION
This script is incredibly beneficial for those who seek a minimalist and focused approach to consuming content on YouTube. By providing a CLI-based interface (dmenu), the script reduces distractions and clutter that are commonly encountered on the Youtube website. It allows users to personalize their content consumption and manage channels more effectively. The script is also remarkably efficient and easy to navigate, providing a user-friendly experience that saves time and promotes productivity.

The script is organized into functions that each perform a specific task, such as updating channel data, retrieving video titles, playing videos, downloading videos, adding videos to the watch later list, and browsing all channels. These functions are called by the main script to provide the user with various options for navigating and interacting with the videos.

The script makes use of various Bash features such as associative arrays, shell redirection and piping, to simplify and streamline the code. It also uses conditionals and loops to handle different user input and error cases. Overall, this script is a powerful and flexible tool for browsing, watching, organizing YouTube channels, and it provides a great example of Bash usage to automate and streamline complex tasks.

DETAILED EXPLANATION
- The script begins by defining two associative arrays, CHANNELS and CATEGORIES, which store the YouTube channel names along with their respective URLs and categories. It then sets the directories for storing data and videos, and creates them if they do not already exist.
- The 'update_data' function updates the metadata for a given channel, while the 'update_all_channels' function updates metadata for all channels. The metadata includes the video title, URL, view count, and duration, which are extracted using 'yt-dlp' and 'jq' utilities.
- The 'get_videos' function retrieves the video titles from the metadata of a given channel, sorted by the specified criteria (if any). The 'video_url' function returns the URL of a video based on its title and channel name. The 'play_video' and 'download_video' functions use 'mpv' and 'yt-dlp', respectively, to play or download a video given its title and channel name.
- The 'add_to_watch_later' function appends the video title and channel name to a watch later list, while the 'play_watch_later' and 'delete_from_watch_later' functions play a video from the list or remove it, respectively.
- The 'get_all_videos' function retrieves all video titles from the metadata of all channels, sorted by the specified criteria. The 'browse_all_channels' function lets you browse through all channels and select a video to watch, download, or add to the watch later list.
- The main part of the script first prompts the user to update the database of channels. If the user chooses to do so, the 'update_all_channels' function is called. The script then presents the user with options to browse all channels, browse channels by category, or browse the watch later list. The script loops through these options until the user decides to exit.
2023-05-02 21:49:46 +00:00
6 changed files with 320 additions and 13 deletions

View File

@ -4,7 +4,7 @@
<alias>
<family>serif</family>
<prefer>
<family>Linux Libertine</family>
<family>Libertinus Serif</family>
<family>Joy Pixels</family>
<family>Noto Color Emoji</family>
<family>FontAwesome</family>
@ -13,7 +13,7 @@
<alias>
<family>sans-serif</family>
<prefer>
<family>Linux Biolinum</family>
<family>Libertinus Sans</family>
<family>Joy Pixels</family>
<family>Noto Color Emoji</family>
<family>FontAwesome</family>
@ -22,7 +22,7 @@
<alias>
<family>sans</family>
<prefer>
<family>Linux Biolinum</family>
<family>Libertinus Sans</family>
<family>Joy Pixels</family>
<family>Noto Color Emoji</family>
<family>FontAwesome</family>
@ -32,7 +32,7 @@
<family>monospace</family>
<prefer>
<family>Noto Sans Mono</family>
<family>Liberation Mono</family>
<family>Libertinus Mono</family>
<family>FontAwesome</family>
<family>Braille</family>
</prefer>

View File

@ -16,5 +16,8 @@ IFS='
# Update each found profile.
for profile in $profiles; do
arkenfox-updater -p "${profile%%/user.js*}" -s
userjs=${profile%%/user.js*}
user=$(stat -c '%U' "$userjs") || continue
su -l "$user" -c "arkenfox-updater -c -p $userjs -s"
done

View File

@ -15,7 +15,7 @@ fi
case "$url" in
*mkv|*webm|*mp4|*youtube.com/watch*|*youtube.com/playlist*|*youtube.com/shorts*|*youtu.be*|*hooktube.com*|*bitchute.com*|*videos.lukesmith.xyz*|*odysee.com*)
setsid -f mpv -quiet "$url" >/dev/null 2>&1 ;;
*png|*jpg|*jpe|*jpeg|*gif)
*png|*jpg|*jpe|*jpeg|*gif|*webp)
curl -sL "$url" > "/tmp/$(echo "$url" | sed "s/.*\///;s/%20/ /g")" && nsxiv -a "/tmp/$(echo "$url" | sed "s/.*\///;s/%20/ /g")" >/dev/null 2>&1 & ;;
*pdf|*cbz|*cbr)
curl -sL "$url" > "/tmp/$(echo "$url" | sed "s/.*\///;s/%20/ /g")" && zathura "/tmp/$(echo "$url" | sed "s/.*\///;s/%20/ /g")" >/dev/null 2>&1 & ;;

View File

@ -13,11 +13,18 @@ bgloc="${XDG_DATA_HOME:-$HOME/.local/share}/bg"
dunstconf="${XDG_CONFIG_HOME:-$HOME/.config}/dunst/dunstrc"
zathuraconf="${XDG_CONFIG_HOME:-$HOME/.config}/zathura/zathurarc"
# Give -s as parameter to make notifications silent.
while getopts "s" o; do case "${o}" in
s) silent='1' ;;
esac done
shift $((OPTIND - 1))
trueloc="$(readlink -f "$1")" &&
case "$(file --mime-type -b "$trueloc")" in
image/* ) ln -sf "$(readlink -f "$1")" "$bgloc" && notify-send -i "$bgloc" "Changing wallpaper..." ;;
inode/directory ) ln -sf "$(find "$trueloc" -iregex '.*.\(jpg\|jpeg\|png\|gif\)' -type f | shuf -n 1)" "$bgloc" && notify-send -i "$bgloc" "Random Wallpaper chosen." ;;
*) notify-send "🖼️ Error" "Not a valid image or directory." ; exit 1;;
image/* ) ln -sf "$trueloc" "$bgloc" && [ -z "$silent" ] && notify-send -i "$bgloc" "Changing wallpaper..." ;;
inode/directory ) ln -sf "$(find "$trueloc" -iregex '.*.\(jpg\|jpeg\|png\|gif\)' -type f | shuf -n 1)" "$bgloc" && [ -z "$silent" ] && notify-send -i "$bgloc" "Random Wallpaper chosen." ;;
*) [ -z "$silent" ] && notify-send "🖼️ Error" "Not a valid image or directory." ; exit 1;;
esac
# If pywal is installed, use it.

View File

@ -17,10 +17,17 @@ case $BLOCK_BUTTON in
6) "$TERMINAL" -e "$EDITOR" "$0" ;;
esac
if grep -xq 'up' /sys/class/net/w*/operstate 2>/dev/null ; then
# Wifi
if [ "$(cat /sys/class/net/w*/operstate 2>/dev/null)" = 'up' ] ; then
wifiicon="$(awk '/^\s*w/ { print "📶", int($3 * 100 / 70) "% " }' /proc/net/wireless)"
elif grep -xq 'down' /sys/class/net/w*/operstate 2>/dev/null ; then
grep -xq '0x1003' /sys/class/net/w*/flags && wifiicon="📡 " || wifiicon="❌ "
elif [ "$(cat /sys/class/net/w*/operstate 2>/dev/null)" = 'down' ] ; then
[ "$(cat /sys/class/net/w*/flags 2>/dev/null)" = '0x1003' ] && wifiicon="📡 " || wifiicon="❌ "
fi
printf "%s%s%s\n" "$wifiicon" "$(sed "s/down/❎/;s/up/🌐/" /sys/class/net/e*/operstate 2>/dev/null)" "$(sed "s/.*/🔒/" /sys/class/net/tun*/operstate 2>/dev/null)"
# Ethernet
[ "$(cat /sys/class/net/e*/operstate 2>/dev/null)" = 'up' ] && ethericon="🌐" || ethericon="❎"
# TUN
[ -n "$(cat /sys/class/net/tun*/operstate 2>/dev/null)" ] && tunicon=" 🔒"
printf "%s%s%s\n" "$wifiicon" "$ethericon" "$tunicon"

290
.local/bin/yt-browser Normal file
View File

@ -0,0 +1,290 @@
#!/bin/bash
declare -A CHANNELS
CHANNELS=(
["Luke Smith"]="https://www.youtube.com/@LukeSmithxyz/videos"
["Mental Outlaw"]="https://www.youtube.com/@MentalOutlaw/videos"
["Sabine Hossenfelder"]="https://www.youtube.com/@SabineHossenfelder/videos"
["Veritasium"]="https://www.youtube.com/@veritasium/videos"
# Add More Channels
)
declare -A CATEGORIES
CATEGORIES=(
["Tech"]="Luke Smith|Mental Outlaw"
["Science"]="Sabine Hossenfelder|Veritasium"
# Add More Categories and Channels
)
DATA_DIR="$HOME/.cache/youtube_channels"
DOWNLOAD_DIR="$HOME/ytvideos"
WATCH_LATER_LIST="${DATA_DIR}/watch_later.list"
mkdir -p "$DATA_DIR" "$DOWNLOAD_DIR"
update_data() {
local channel_name="$1"
local channel_url="$2"
local data_file="${DATA_DIR}/${channel_name}.tsv"
yt-dlp -j --flat-playlist --skip-download --extractor-args youtubetab:approximate_date "$channel_url" | jq -r '[.title, .url, .view_count, .duration, .upload_date] | @tsv' > "$data_file" &
}
update_all_channels() {
for channel_name in "${!CHANNELS[@]}"; do
update_data "$channel_name" "${CHANNELS[$channel_name]}"
done
wait
}
get_videos() {
local channel_name="$1"
local sort_option="$2"
local data_file="${DATA_DIR}/${channel_name}.tsv"
case $sort_option in
"@@sv")
sort -nr -t$'\t' -k3 "$data_file" | cut -f1
;;
"@@sd")
sort -nr -t$'\t' -k4 "$data_file" | cut -f1
;;
*)
sort -nr -t$'\t' -k5 "$data_file" | cut -f1
;;
esac
}
video_url() {
local channel_name="$1"
local video_title="$2"
local data_file="${DATA_DIR}/${channel_name}.tsv"
grep -F "$video_title" "$data_file" | cut -f2
}
play_video() {
local video_title="$1"
local channel_name="$2"
local video_url=$(video_url "$channel_name" "$video_title")
mpv "$video_url"
}
download_video() {
local video_title="$1"
local channel_name="$2"
local video_url=$(video_url "$channel_name" "$video_title")
local channel_download_dir="${DOWNLOAD_DIR}/${channel_name}"
mkdir -p "$channel_download_dir"
yt-dlp -o "${channel_download_dir}/%(title)s.%(ext)s" "$video_url"
}
add_to_watch_later() {
local video_title="$1"
local channel_name="$2"
echo "${channel_name}: ${video_title}" >> "$WATCH_LATER_LIST"
}
play_watch_later() {
local line="$1"
local channel_name="${line%%: *}"
local video_title="${line#*: }"
play_video "$video_title" "$channel_name"
}
delete_from_watch_later() {
local video_line="$1"
local tmp_list="${DATA_DIR}/watch_later_tmp.list"
grep -vF "$video_line" "$WATCH_LATER_LIST" > "$tmp_list"
mv "$tmp_list" "$WATCH_LATER_LIST"
}
get_all_videos() {
local sort_option="$1"
local all_videos_file="${DATA_DIR}/all_videos.tsv"
# Combine all channel video data into a single file
rm -f "$all_videos_file"
for channel_name in "${!CHANNELS[@]}"; do
cat "${DATA_DIR}/${channel_name}.tsv" >> "$all_videos_file"
done
# Sort videos based on the specified criteria
case $sort_option in
"@@sv")
sort -nr -t$'\t' -k3 "$all_videos_file" | cut -f1
;;
"@@sd")
sort -nr -t$'\t' -k4 "$all_videos_file" | cut -f1
;;
*)
sort -nr -t$'\t' -k5 "$all_videos_file" | cut -f1
;;
esac
}
browse_all_channels() {
while true; do
video_title=$(get_all_videos | dmenu -i -l 20 -p "Choose a video or enter @@sv or @@sd")
if [[ -z "$video_title" ]]; then
break
elif [[ $video_title == "@@sv" ]] || [[ $video_title == "@@sd" ]]; then
sort_option="$video_title"
video_title=$(get_all_videos "$sort_option" | dmenu -i -l 20 -dmenu -i -p "Choose a video")
fi
if [[ -n "$video_title" ]] && [[ $video_title != "@@sv" ]] && [[ $video_title != "@@sd" ]]; then
for channel_name in "${!CHANNELS[@]}"; do
if grep -qF "$video_title" "${DATA_DIR}/${channel_name}.tsv"; then
break
fi
done
action=$(echo -e "Watch\nDownload\nAdd to Watch Later" | dmenu -i -l 3 -p "Choose an action for the video")
case $action in
Watch)
play_video "$video_title" "$channel_name"
;;
Download)
download_video "$video_title" "$channel_name" && notify-send "Downloading has finished."
;;
"Add to Watch Later")
add_to_watch_later "$video_title" "$channel_name"
;;
*)
continue
;;
esac
fi
done
}
# Main script
update_choice=$(echo -e "No\nYes" | dmenu -i -l 2 -p "Do you want to update the database? (Yes/No)")
case $update_choice in
Yes)
update_all_channels
;;
No)
;;
*)
echo "Invalid option"
exit 1
;;
esac
while true; do
main_choice=$(echo -e "All Channels\nCategories\nWatch Later List\n$(printf '%s\n' "${!CHANNELS[@]}")" | dmenu -i -l 20 -p "Choose an Option or a Channel")
if [[ -z "$main_choice" ]]; then
break
elif [[ $main_choice == "All Channels" ]]; then
browse_all_channels
elif [[ $main_choice == "Categories" ]]; then
while true; do
category=$(echo -e "$(printf '%s\n' "${!CATEGORIES[@]}")" | dmenu -i -l 12 -p "Choose a category")
if [[ -z "$category" ]]; then
break
fi
while true; do
IFS="|" read -ra channels <<< "${CATEGORIES[$category]}"
channel_name=$(printf '%s\n' "${channels[@]}" | dmenu -i -l 20 -p "Choose a channel")
if [[ -z "$channel_name" ]]; then
break
fi
while true; do
video_title=$(get_videos "$channel_name" | dmenu -i -l 20 -p "Choose a video")
if [[ -z "$video_title" ]]; then
break
elif [[ $video_title == "@@sv" ]] || [[ $video_title == "@@sd" ]]; then
sort_option="$video_title"
video_title=$(get_videos "$channel_name" "$sort_option" | dmenu -i -l 20 -p "Choose a video")
fi
if [[ -n "$video_title" ]] && [[ $video_title != "@@sv" ]] && [[ $video_title != "@@sd" ]]; then
action=$(echo -e "Watch\nDownload\nAdd to Watch Later" | dmenu -i -l 3 -p "Choose an action for the video")
case $action in
Watch)
play_video "$video_title" "$channel_name"
;;
Download)
download_video "$video_title" "$channel_name" && notify-send "Downloading has finished."
;;
"Add to Watch Later")
add_to_watch_later "$video_title" "$channel_name"
;;
*)
echo "Invalid action"
;;
esac
fi
done
done
done
elif [[ $main_choice == "Watch Later List" ]]; then
while true; do
video_line=$(cat "$WATCH_LATER_LIST" | dmenu -i -l 5 -p "Choose a video from Watch Later List")
if [[ -z "$video_line" ]]; then
break
fi
action=$(echo -e "Watch\nDownload\nDelete" | dmenu -i -l 3 -p "Choose an action for the video")
case $action in
Watch)
play_watch_later "$video_line"
;;
Download)
channel_name="${video_line%%: *}"
video_title="${video_line#*: }"
download_video "$video_title" "$channel_name"
;;
Delete)
delete_from_watch_later "$video_line"
;;
*)
echo "Invalid action"
;;
esac
done
else
channel_name="$main_choice"
while true; do
video_title=$(get_videos "$channel_name" | dmenu -i -l 20 -p "Choose a video or enter @@sv or @@sd to sort by view count or duration")
if [[ -z "$video_title" ]]; then
break
elif [[ $video_title == "@@sv" ]] || [[ $video_title == "@@sd" ]]; then
sort_option="$video_title"
video_title=$(get_videos "$channel_name" "$sort_option" | l 20 -dmenu -i -p "Choose a video")
fi
if [[ -n "$video_title" ]] && [[ $video_title != "@@sv" ]] && [[ $video_title != "@@sd" ]]; then
action=$(echo -e "Watch\nDownload\nAdd to Watch Later" | dmenu -i -l 3 -p "Choose an action for the video")
case $action in
Watch)
play_video "$video_title" "$channel_name"
;;
Download)
download_video "$video_title" "$channel_name" && notify-send "Downloading has finished."
;;
"Add to Watch Later")
add_to_watch_later "$video_title" "$channel_name"
;;
*)
echo "Invalid action"
;;
esac
fi
done
fi
done