@@ -355,6 +355,7 @@ my $playlists_help = <<"PLAYLISTS_HELP" . $general_help;
355355<number> : list videos from the selected playlist
356356:pp=i,i : play videos from the selected playlists
357357:s=i :save=i : save the playlist locally (see -lp)
358+ :r=i :remove=i : remove a locally saved playlist from -lp
358359PLAYLISTS_HELP
359360
360361my $channels_help = <<"CHANNELS_HELP" . $general_help ;
@@ -745,8 +746,7 @@ usage: $execname [options] ([url] | [keywords])
745746 --ps=s : add video by ID or URL to a post-selected playlist
746747 or in a given playlist ID specified with `--pid`
747748 --position=i : position in the playlist where to add the video
748- --save-playlist=s : save a playlist locally given a filename
749- playlist ID must be specified with `--pid`
749+ --save-playlist=s : save a playlist locally given a playlist ID
750750 -lp --local-playlists : display saved local playlists
751751 -lp=s : display a local playlist by name
752752
@@ -759,9 +759,11 @@ usage: $execname [options] ([url] | [keywords])
759759
760760 * Channels
761761 -sc --channels : search for YouTube channels
762+ --save-channel=s : save a channel locally given a channel ID
762763 -lc --local-channels : display the list of local channels
763764 -lc=s : display videos from a local channel by name
764765
766+
765767* Comments
766768 --comments=s : display comments for a video by ID or URL
767769 --comments-order=s : change the order of YouTube comments
@@ -1340,16 +1342,13 @@ sub apply_configuration {
13401342 }
13411343
13421344 if (defined $opt -> {save_playlist }) {
1345+ my $playlistID = get_valid_playlist_id(delete ($opt -> {save_playlist })) // return ;
1346+ save_playlist_to_file($playlistID );
1347+ }
13431348
1344- if (not defined $opt -> {playlist_id }) {
1345- warn_no_thing_selected(' playlist (--pid=ID)' );
1346- return ;
1347- }
1348-
1349- my $playlistID = get_valid_playlist_id(delete ($opt -> {playlist_id })) // return ;
1350- my $filename = catfile($local_playlists_dir , delete ($opt -> {save_playlist }) // $playlistID );
1351-
1352- save_playlist_to_file($playlistID , $filename );
1349+ if (defined $opt -> {save_channel }) {
1350+ my $channelID = delete ($opt -> {save_channel });
1351+ save_channel_to_file($channelID );
13531352 }
13541353
13551354 if (defined $opt -> {playlist_id }) {
@@ -1610,7 +1609,9 @@ sub parse_arguments {
16101609 ' lc|fc|local-channels:s' => \$opt {local_channels },
16111610 ' lp|local-playlists:s' => \$opt {local_playlist },
16121611 ' wv|watched-videos' => \$opt {watched_videos },
1613- ' save-playlist=s' => \$opt {save_playlist },
1612+
1613+ ' save-channel=s' => \$opt {save_channel },
1614+ ' save-playlist=s' => \$opt {save_playlist },
16141615
16151616 ' search-videos|search|sv!' => \$opt {search_videos },
16161617 ' search-channels|channels|sc!' => \$opt {search_channels },
@@ -2090,7 +2091,7 @@ sub get_user_input {
20902091sub logout {
20912092
20922093 unlink $authentication_file
2093- or warn " Can't unlink: `$authentication_file ' -> $! " ;
2094+ or warn " [!] Can't unlink: `$authentication_file ' -> $! " ;
20942095
20952096 $yv_obj -> set_access_token();
20962097 $yv_obj -> set_refresh_token();
@@ -2128,7 +2129,7 @@ INFO
21282129 if ($remember_me ) {
21292130 $yv_obj -> set_authentication_file($authentication_file );
21302131 $yv_obj -> save_authentication_tokens()
2131- or warn " Can't store the authentication tokens: $! " ;
2132+ or warn " [!] Can't store the authentication tokens: $! " ;
21322133 }
21332134 else {
21342135 $yv_obj -> set_authentication_file();
@@ -2832,12 +2833,7 @@ sub print_channels {
28322833 foreach my $id (@nums ) {
28332834 my $channel_id = $yv_utils -> get_channel_id($channels -> [$id ]);
28342835 my $channel_title = $yv_utils -> get_title($channels -> [$id ]);
2835- if (save_channel_to_file($channel_id , $channel_title )) {
2836- say " \n :: Saved channel <<$channel_title >> (id: $channel_id ) to file." ;
2837- }
2838- else {
2839- say " \n [!] Unable to save channel <<$channel_title >> to file..." ;
2840- }
2836+ save_channel_to_file($channel_id , $channel_title );
28412837 }
28422838 }
28432839 else {
@@ -2997,22 +2993,49 @@ sub print_comments {
29972993sub save_channel_to_file {
29982994 my ($channel_id , $channel_title ) = @_ ;
29992995
3000- $yv_utils -> is_channelID($channel_id ) || return ;
2996+ $channel_id // return ;
2997+
2998+ if ($channel_id = extract_channel_id($channel_id )) {
2999+ if (not $yv_utils -> is_channelID($channel_id )) {
3000+ $channel_id = $yv_obj -> channel_id_from_username($channel_id ) // do {
3001+ warn_invalid(" username or channel ID" , $channel_id );
3002+ undef ;
3003+ };
3004+ }
3005+
3006+ if ($channel_id eq ' mine' ) {
3007+ $channel_id = $yv_obj -> my_channel_id() // do {
3008+ warn_invalid(" username or channel ID" , $channel_id );
3009+ undef ;
3010+ };
3011+ }
3012+ }
3013+
3014+ $channel_id // return ;
3015+
3016+ if (not defined ($channel_title )) {
3017+ $channel_title = $yv_utils -> get_title($yv_obj -> channel_from_id($channel_id , ' snippet' )-> {results }{items }[0]);
3018+ }
3019+
3020+ say " \n :: Saving channel <<$channel_title >> (id: $channel_id ) to file..." ;
30013021
30023022 open (my $fh , ' >>:utf8' , $opt {youtube_users_file }) or do {
3003- warn " Can't open file <<$opt {youtube_users_file}>> for appending: $! \n " ;
3023+ warn " [!] Can't open file <<$opt {youtube_users_file}>> for appending: $! \n " ;
30043024 return ;
30053025 };
30063026
30073027 say $fh " $channel_id $channel_title " ;
30083028 close $fh ;
3029+
3030+ say " :: Done." ;
3031+ return 1;
30093032}
30103033
30113034sub update_channel_file {
30123035 my (%channels ) = @_ ;
30133036
30143037 open (my $fh , ' >:utf8' , $opt {youtube_users_file }) or do {
3015- warn " Can't open file <<$opt {youtube_users_file}>> for writing: $! \n " ;
3038+ warn " [!] Can't open file <<$opt {youtube_users_file}>> for writing: $! \n " ;
30163039 return ;
30173040 };
30183041
@@ -3027,7 +3050,7 @@ sub remove_saved_channels {
30273050 my (@channel_ids ) = @_ ;
30283051
30293052 open (my $fh , ' <:utf8' , $opt {youtube_users_file }) or do {
3030- warn " Can't open file <<$opt {youtube_users_file}>> for reading: $! \n " ;
3053+ warn " [!] Can't open file <<$opt {youtube_users_file}>> for reading: $! \n " ;
30313054 return ;
30323055 };
30333056
@@ -3041,7 +3064,7 @@ sub remove_saved_channels {
30413064 $channels {$channel_id } = $channel_title ;
30423065 }
30433066 else {
3044- warn " Invalid channel ID: $channel_id \n " ;
3067+ warn " [!] Invalid channel ID: $channel_id \n " ;
30453068 }
30463069 }
30473070 }
@@ -3134,20 +3157,35 @@ sub extract_video_ids_from_playlist {
31343157}
31353158
31363159sub save_playlist_to_file {
3137- my ($playlistID , $filename ) = @_ ;
3160+ my ($playlistID , $title ) = @_ ;
3161+
3162+ $playlistID // return ;
3163+
3164+ if (not defined ($title )) {
3165+ $title = $yv_utils -> get_title($yv_obj -> playlist_from_id($playlistID , ' snippet' )-> {results }{items }[0]);
3166+ }
3167+
3168+ my $basename = $title . ' -- ' . $playlistID . ' .txt' ;
3169+ $basename =~ s { /} { %} g ;
3170+
3171+ my $filename = catfile($local_playlists_dir , $basename );
3172+ say " :: Saving playlist <<$title >> (id: $playlistID ) to file..." ;
31383173
31393174 if (-e $filename ) {
3140- warn " :: File <<$filename >> already exists!\n " ;
3175+ warn " [!] File <<$filename >> already exists!\n " ;
31413176 return ;
31423177 }
31433178
31443179 open (my $fh , ' >' , $filename ) or do {
3145- warn " Can't open file <<$filename >> for writing: $! " ;
3180+ warn " [!] Can't open file <<$filename >> for writing: $! " ;
31463181 return ;
31473182 };
31483183
31493184 extract_video_ids_from_playlist($playlistID , sub { say $fh $_ [0] });
31503185 close $fh ;
3186+
3187+ say " :: Done." ;
3188+ return 1;
31513189}
31523190
31533191sub print_local_playlist {
@@ -3421,23 +3459,45 @@ sub print_playlists {
34213459 elsif ($opt =~ / ^(?:r|return)\z / ) {
34223460 return ;
34233461 }
3462+
3463+ # :s=i, :save=i
34243464 elsif ($opt =~ / ^(?:s|save)${digit_or_equal_re} (.*)/ ) {
34253465 if (my @ids = get_valid_numbers($# {$playlists }, $1 )) {
34263466 foreach my $id (@ids ) {
34273467 my $playlist = $playlists -> [$id ];
34283468 my $playlistID = $yv_utils -> get_playlist_id($playlist );
34293469 my $title = $yv_utils -> get_title($playlist );
3430- my $basename = $title . ' -- ' . $playlistID . ' .txt' ;
3431- $basename =~ s { /} { %} g ;
3432- my $filename = catfile($local_playlists_dir , $basename );
3433- say " :: Saving playlist <<$title >> as <<$filename >>" ;
3434- save_playlist_to_file($playlistID , $filename );
3470+ save_playlist_to_file($playlistID , $title );
3471+ }
3472+ }
3473+ else {
3474+ warn_no_thing_selected(' playlist' );
3475+ }
3476+ }
3477+
3478+ # :r=i, :rm=i, :remove=i
3479+ elsif ($opt =~ / ^(?:r|rm|remove)${digit_or_equal_re} (.*)/ ) {
3480+ if (my @nums = get_valid_numbers($# {$playlists }, $1 )) {
3481+
3482+ foreach my $i (@nums ) {
3483+ my $id = $yv_utils -> get_playlist_id($playlists -> [$i ]);
3484+ my $title = $yv_utils -> get_title($playlists -> [$i ]);
3485+
3486+ if ($id =~ m { ^/} and -f $id ) {
3487+ say " :: Removing local playlist <<$title >>" ;
3488+ say (unlink ($id ) ? " :: Done." : " :: Error: $! " );
3489+ }
3490+ else {
3491+ say " :: Playlist <<$title >> is not saved locally" ;
3492+ }
34353493 }
34363494 }
34373495 else {
34383496 warn_no_thing_selected(' playlist' );
34393497 }
34403498 }
3499+
3500+ # :i=i, :info=i
34413501 elsif ($opt =~ / ^(?:i|info)${digit_or_equal_re} (.*)/ ) {
34423502 if (my @ids = get_valid_numbers($# {$playlists }, $1 )) {
34433503 foreach my $id (@ids ) {
@@ -3449,6 +3509,8 @@ sub print_playlists {
34493509 warn_no_thing_selected(' playlist' );
34503510 }
34513511 }
3512+
3513+ # :pp=i
34523514 elsif ($opt =~ / ^pp${digit_or_equal_re} (.*)/ ) {
34533515 if (my @ids = get_valid_numbers($# {$playlists }, $1 )) {
34543516 my $arg = " --pp=" . join (q{ ,} , map { $yv_utils -> get_playlist_id($_ ) } @{$playlists }[@ids ]);
@@ -4114,9 +4176,10 @@ sub print_playlist_info {
41144176 (
41154177 map { sprintf (q{ -> } . " %-*s: %s \n " , $opt {_colors } ? 18 : 10, _bold_color($_ -> [0]), $_ -> [1]) }
41164178 grep { defined ($_ -> [1]) } (
4117- [' Title' => $yv_utils -> get_title($playlist )],
4118- [' Channel' => $yv_utils -> get_channel_title($playlist )],
4119- [' ChannelID' => $yv_utils -> get_channel_id($playlist )],
4179+ [' Title' => $yv_utils -> get_title($playlist )],
4180+ [' Author' => $yv_utils -> get_channel_title($playlist )],
4181+ [' ChannelID' => $yv_utils -> get_channel_id($playlist )],
4182+ [' PlaylistID' => ($id =~ m { ^/} ? undef : $id )],
41204183 [' Videos' => $yv_utils -> set_thousands($yv_utils -> get_playlist_item_count($playlist ))],
41214184 [' Published' => $yv_utils -> get_publication_date($playlist )],
41224185 )
@@ -4590,12 +4653,7 @@ sub print_videos {
45904653 foreach my $id (@nums ) {
45914654 my $channel_id = $yv_utils -> get_channel_id($videos -> [$id ]);
45924655 my $channel_title = $yv_utils -> get_channel_title($videos -> [$id ]);
4593- if (save_channel_to_file($channel_id , $channel_title )) {
4594- say " \n :: Saved channel <<$channel_title >> (id: $channel_id ) to file." ;
4595- }
4596- else {
4597- say " \n [!] Unable to save channel <<$channel_title >> to file..." ;
4598- }
4656+ save_channel_to_file($channel_id , $channel_title );
45994657 }
46004658 }
46014659 else {
0 commit comments