Skip to content

Commit 5b82298

Browse files
committed
- Added the -fc (--file-channels) command-line option.
It displays saved channel from file: ~/.config/youtube-viewer/youtube_users.txt Supports searching by keyword and listing either latest uploads or popular uploads (:h for help). - Added the `:s=i` (:save=i) STDIN option for saving a channel into the list of channels.
1 parent b680ed1 commit 5b82298

File tree

1 file changed

+208
-2
lines changed

1 file changed

+208
-2
lines changed

bin/youtube-viewer

Lines changed: 208 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,7 @@ else {
123123
# Configuration dir/file
124124
my $config_dir = catdir($xdg_config_home, $execname);
125125
my $config_file = catfile($config_dir, "$execname.conf");
126+
my $youtube_users_file = catfile($config_dir, 'youtube_users.txt');
126127
my $authentication_file = catfile($config_dir, 'reg.dat');
127128
my $history_file = catfile($config_dir, 'cli-history.txt');
128129
my $watched_file = catfile($config_dir, 'watched.txt');
@@ -246,6 +247,7 @@ my %CONFIG = (
246247
skip_watched => 0,
247248
remember_watched => 0,
248249
watched_file => $watched_file,
250+
youtube_users_file => $youtube_users_file,
249251
highlight_watched => 1,
250252
highlight_color => 'bold',
251253
remove_played_file => 0,
@@ -360,6 +362,7 @@ $action_options
360362
:pv=i :popular=i : display author's popular uploads
361363
:A(ctivity)=i : display author's recent activity
362364
:p(laylists)=i : display author's playlists
365+
:s=i :save=i : save author's channel ID to file (see -fc)
363366
:ps=i :s2p=i,i : save videos to a post-selected playlist
364367
:subscribe=i : subscribe to author's channel
365368
:(dis)like=i : like or dislike a video
@@ -722,7 +725,8 @@ usage: $execname [options] ([url] | [keywords])
722725
use "--region=XX" to change the region
723726
724727
* Channels
725-
-sc --channels : search for YouTube channels
728+
-sc --channels : search for YouTube channels
729+
-fc --file-channels : show saved channels from file
726730
727731
* Comments
728732
--comments=s : display comments for a video by ID or URL
@@ -1314,6 +1318,10 @@ sub apply_configuration {
13141318
print_categories($yv_obj->video_categories);
13151319
}
13161320

1321+
if (delete $opt->{channels_from_file}) {
1322+
print_channels_from_file();
1323+
}
1324+
13171325
if (defined $opt->{uploads}) {
13181326
my $str = delete $opt->{uploads};
13191327

@@ -1541,6 +1549,8 @@ sub parse_arguments {
15411549
'c|categories' => \$opt{categories},
15421550
'video-ids|videoids|id|ids=s' => \$opt{play_video_ids},
15431551

1552+
'fc|cf|file-channels' => \$opt{channels_from_file},
1553+
15441554
'search-videos|search|sv!' => \$opt{search_videos},
15451555
'search-channels|channels|sc!' => \$opt{search_channels},
15461556
'search-playlists|sp|p!' => \$opt{search_playlists},
@@ -2793,6 +2803,177 @@ sub print_comments {
27932803
__SUB__->(@_);
27942804
}
27952805

2806+
sub save_channel_to_file {
2807+
my ($channel_id, $channel_title) = @_;
2808+
2809+
$yv_utils->is_channelID($channel_id) || return;
2810+
2811+
open(my $fh, '>>', $opt{youtube_users_file}) or do {
2812+
warn "Can't open file <<$opt{youtube_users_file}>> for appending: $!\n";
2813+
return;
2814+
};
2815+
2816+
print $fh "$channel_id $channel_title\n";
2817+
2818+
close $fh;
2819+
}
2820+
2821+
sub update_channel_file {
2822+
my (%channels) = @_;
2823+
2824+
open(my $fh, '>', $opt{youtube_users_file}) or do {
2825+
warn "Can't open file <<$opt{youtube_users_file}>> for writing: $!\n";
2826+
return;
2827+
};
2828+
2829+
foreach my $key (sort { CORE::fc($channels{$a}) cmp CORE::fc($channels{$b}) } keys %channels) {
2830+
say $fh "$key $channels{$key}";
2831+
}
2832+
2833+
close $fh;
2834+
}
2835+
2836+
sub print_channels_from_file {
2837+
2838+
open(my $fh, '<', $opt{youtube_users_file}) or do {
2839+
warn "Can't open file <<$opt{youtube_users_file}>> for reading: $!\n";
2840+
return;
2841+
};
2842+
2843+
my %channels;
2844+
2845+
while (defined(my $line = <$fh>)) {
2846+
if ($line =~ /^([a-zA-Z0-9_-]+) (.+)/) {
2847+
my ($channel_id, $channel_title) = ($1, $2);
2848+
2849+
if ($yv_utils->is_channelID($channel_id)) {
2850+
$channels{$channel_id} = $channel_title;
2851+
}
2852+
else {
2853+
warn "Invalid channel ID: $channel_id\n";
2854+
}
2855+
}
2856+
}
2857+
2858+
close $fh;
2859+
2860+
my $display_channels = sub {
2861+
my (@channels) = @_;
2862+
2863+
if (not @channels) {
2864+
warn_no_results("channel");
2865+
return;
2866+
}
2867+
2868+
print "\n";
2869+
foreach my $i (0 .. $#channels) {
2870+
my $channel = $channels[$i];
2871+
printf("%s. %-40s (id: %s)\n", colored(sprintf('%2d', $i + 1), 'bold'), $channel->{title}, $channel->{id});
2872+
}
2873+
2874+
my @keywords = get_input_for_channels();
2875+
2876+
foreach my $key (@keywords) {
2877+
if ($key =~ /$valid_opt_re/) {
2878+
2879+
my $opt = $1;
2880+
2881+
if (
2882+
general_options(opt => $opt,
2883+
sub => __SUB__,)
2884+
) {
2885+
## ok
2886+
}
2887+
elsif ($opt =~ /^(?:h|help)\z/) {
2888+
print <<"EOT";
2889+
2890+
# Search for a channel
2891+
<keyword> : search for a channel
2892+
2893+
# Select a channel
2894+
<number> : latest uploads from channel
2895+
:pv=i :popular=i : popular uploads from channel
2896+
2897+
# Remove channels
2898+
:rm=i :remove=i,i : remove the selected channels from file
2899+
EOT
2900+
press_enter_to_continue();
2901+
}
2902+
elsif ($opt =~ /^(?:pv|popular)${digit_or_equal_re}(.*)/) {
2903+
if (my @nums = get_valid_numbers($#channels, $1)) {
2904+
2905+
foreach my $id (@nums) {
2906+
2907+
my $channel_id = $channels[$id]{id};
2908+
my $request = $yv_obj->popular_videos($channel_id);
2909+
2910+
if ($yv_utils->has_entries($request)) {
2911+
print_videos($request);
2912+
}
2913+
else {
2914+
warn_no_results('popular video');
2915+
}
2916+
}
2917+
}
2918+
else {
2919+
warn_no_thing_selected('channel');
2920+
}
2921+
}
2922+
elsif ($opt =~ /^(?:r|rm|remove)${digit_or_equal_re}(.*)/) {
2923+
if (my @nums = get_valid_numbers($#channels, $1)) {
2924+
2925+
my %removed;
2926+
2927+
foreach my $id (@nums) {
2928+
2929+
my $channel_id = $channels[$id]{id};
2930+
my $channel_title = $channels[$id]{title};
2931+
2932+
say ":: Removing <<$channel_title>> (id: $channel_id)";
2933+
2934+
delete $channels{$channel_id};
2935+
$removed{$channel_id} = 1;
2936+
}
2937+
2938+
@channels = grep { not exists $removed{$_->{id}} } @channels;
2939+
update_channel_file(%channels);
2940+
}
2941+
else {
2942+
warn_no_thing_selected('channel');
2943+
}
2944+
}
2945+
elsif ($opt =~ /^(?:r|return)\z/) {
2946+
return;
2947+
}
2948+
else {
2949+
warn_invalid('option', $opt);
2950+
}
2951+
}
2952+
elsif (youtube_urls($key)) {
2953+
## ok
2954+
}
2955+
elsif (valid_num($key, \@channels)) {
2956+
my $channel = $channels[$key - 1];
2957+
my $channel_id = $channel->{id};
2958+
my $videos = $yv_obj->uploads($channel_id);
2959+
print_videos($videos);
2960+
}
2961+
else {
2962+
my $re = qr/\Q$key\E/i;
2963+
__SUB__->(grep { $_->{title} =~ /$re/ } @channels);
2964+
}
2965+
}
2966+
2967+
__SUB__->(@channels);
2968+
};
2969+
2970+
my @channels =
2971+
sort { $a->{key} cmp $b->{key} }
2972+
map { {id => $_, title => $channels{$_}, key => CORE::fc($channels{$_})} } keys %channels;
2973+
2974+
$display_channels->(@channels);
2975+
}
2976+
27962977
sub print_categories {
27972978
my ($results) = @_;
27982979

@@ -3993,6 +4174,23 @@ sub print_videos {
39934174
warn_no_thing_selected('video');
39944175
}
39954176
}
4177+
elsif ($opt =~ /^(?:s|save)${digit_or_equal_re}(.*)/) {
4178+
if (my @nums = get_valid_numbers($#{$videos}, $1)) {
4179+
foreach my $id (@nums) {
4180+
my $channel_id = $yv_utils->get_channel_id($videos->[$id]);
4181+
my $channel_title = $yv_utils->get_channel_title($videos->[$id]);
4182+
if (save_channel_to_file($channel_id, $channel_title)) {
4183+
say "\n:: Saved channel <<$channel_title>> (id: $channel_id) to file.";
4184+
}
4185+
else {
4186+
say "\n[!] Unable to save channel <<$channel_title>> to file...";
4187+
}
4188+
}
4189+
}
4190+
else {
4191+
warn_no_thing_selected('video');
4192+
}
4193+
}
39964194
elsif ($opt =~ /^(?:pv|popular)${digit_or_equal_re}(.*)/) {
39974195
if (my @nums = get_valid_numbers($#{$videos}, $1)) {
39984196
foreach my $id (@nums) {
@@ -4681,9 +4879,17 @@ File where to save the video IDs of watched/downloaded videos when C<remember_wa
46814879
46824880
Command for C<wget> when C<download_with_wget> is set to a true value.
46834881
4882+
=head2 youtube_users_file
4883+
4884+
Path to a list of YouTube channels, using the following format:
4885+
4886+
ChannelID NAME
4887+
4888+
The channels can be listed with the command-line option: C<-fc>.
4889+
46844890
=head2 youtube_video_url
46854891
4686-
Sprintf format for an YouTube video URL, given the video ID.
4892+
Format for C<sprintf()> for constructing an YouTube video URL given the video ID.
46874893
46884894
=head2 ytdl
46894895

0 commit comments

Comments
 (0)