Skip to content

Commit

Permalink
gtk: added the right-click "Save playlist" menu entry for playlists.
Browse files Browse the repository at this point in the history
It saves a playlist locally (the video IDs only, without downloading the videos) and adds it in the "Playlists" tab.
  • Loading branch information
trizen committed Mar 7, 2021
1 parent 602a16b commit da358f9
Show file tree
Hide file tree
Showing 3 changed files with 107 additions and 17 deletions.
82 changes: 79 additions & 3 deletions bin/gtk-youtube-viewer
Original file line number Diff line number Diff line change
Expand Up @@ -1257,9 +1257,10 @@ sub menu_popup {
}
elsif ($type eq 'playlist') {

my $playlist_id = $liststore->get($iter, 3);
my $playlist_id = $liststore->get($iter, 3);
my $playlist_name = $yv_utils->get_title($yv_obj->parse_json_string($liststore->get($iter, 8)));

# More details
# Playlist videos
{
my $item = 'Gtk3::ImageMenuItem'->new("Videos");
$item->set_property(tooltip_text => "Display the videos from this playlist");
Expand All @@ -1269,6 +1270,21 @@ sub menu_popup {
$menu->append($item);
}

# Save as a local playlist
{
my $item = 'Gtk3::ImageMenuItem'->new("Save playlist");
$item->set_property(tooltip_text => "Save the playlist as a local playlist");
$item->signal_connect(
activate => sub {
my $filename = save_playlist_to_file($playlist_id, $playlist_name);
add_local_playlist_row($playlist_name, $filename) if defined($filename);
}
);
$item->set_image('Gtk3::Image'->new_from_icon_name("document-save", q{menu}));
$item->show;
$menu->append($item);
}

# Separator
{
my $item = 'Gtk3::SeparatorMenuItem'->new;
Expand Down Expand Up @@ -3109,7 +3125,6 @@ $symbols{published}\t %s",
$yv_utils->get_definition($video),
$yv_utils->set_thousands($yv_utils->get_views($video)),
$yv_utils->get_publication_date($video),

)
);

Expand Down Expand Up @@ -3231,13 +3246,74 @@ $symbols{published}\t %s",
4 => encode_entities($description),
6 => $channel_id,
7 => 'playlist',
8 => $yv_obj->make_json_string($playlist),
);

if ($CONFIG{show_thumbs}) {
set_thumbnail($playlist, $liststore, $iter);
}
}

sub extract_video_ids_from_playlist {
my ($playlistID, $callback) = @_;

local $yv_obj->{maxResults} = 50;
my $results = $yv_obj->videos_from_playlist_id($playlistID);

while (1) {
$yv_utils->has_entries($results) || last;

my $url = $results->{url};
my $info = $results->{results} // {};
my $videos = $info->{items} // [];

foreach my $video (@$videos) {
my $video_id = $yv_utils->get_video_id($video);
$callback->($video_id) if defined($video_id);
}

$results = $yv_obj->from_page_token($url, $info->{nextPageToken} || last);
}

return 1;
}

sub save_playlist_to_file {
my ($playlistID, $title) = @_;

$playlistID // return;

if (not defined($title)) {
$title = $yv_utils->get_title($yv_obj->playlist_from_id($playlistID, 'snippet')->{results}{items}[0]);
}

if (not defined($title)) {
warn "[!] Unable to determine the title of the playlist...\n";
return;
}

my $basename = $yv_utils->make_local_playlist_filename($title, $playlistID);
my $filename = catfile($local_playlists_dir, $basename);

say ":: Saving playlist <<$title>> (id: $playlistID) to file...";

if (-e $filename) {
warn "[!] File <<$filename>> already exists!\n";
return;
}

open(my $fh, '>', $filename) or do {
warn "[!] Can't open file <<$filename>> for writing: $!";
return;
};

extract_video_ids_from_playlist($playlistID, sub { say $fh $_[0] });
close $fh;

say ":: Done.";
return $filename;
}

sub list_playlist {
my ($playlist_id) = @_;

Expand Down
19 changes: 9 additions & 10 deletions bin/youtube-viewer
Original file line number Diff line number Diff line change
Expand Up @@ -3176,6 +3176,8 @@ sub extract_video_ids_from_playlist {
my ($playlistID, $callback) = @_;

$playlistID = get_valid_playlist_id($playlistID) // return;

local $yv_obj->{maxResults} = 50;
my $results = $yv_obj->videos_from_playlist_id($playlistID);

while (1) {
Expand Down Expand Up @@ -3249,10 +3251,14 @@ sub save_playlist_to_file {
$title = $yv_utils->get_title($yv_obj->playlist_from_id($playlistID, 'snippet')->{results}{items}[0]);
}

my $basename = $title . ' -- ' . $playlistID . '.txt';
$basename =~ s{/}{%}g;
if (not defined($title)) {
warn "[!] Unable to determine the title of the playlist...\n";
return;
}

my $basename = $yv_utils->make_local_playlist_filename($title, $playlistID);
my $filename = catfile($local_playlists_dir, $basename);

say ":: Saving playlist <<$title>> (id: $playlistID) to file...";

if (-e $filename) {
Expand Down Expand Up @@ -3866,19 +3872,12 @@ sub download_from_url {
sub download_video {
my ($streaming, $info) = @_;

my $fat32safe = $opt{fat32safe};
state $unix_like = $^O =~ /^(?:linux|freebsd|openbsd)\z/i;

if (not $fat32safe and not $unix_like) {
$fat32safe = 1;
}

my $video_filename = $yv_utils->format_text(
streaming => $streaming,
info => $info,
text => $opt{video_filename_format},
escape => 0,
fat32safe => $fat32safe,
fat32safe => $opt{fat32safe},
);

my $naked_filename = $video_filename =~ s/\.\w+\z//r;
Expand Down
23 changes: 19 additions & 4 deletions lib/WWW/YoutubeViewer/Utils.pm
Original file line number Diff line number Diff line change
Expand Up @@ -261,15 +261,21 @@ sub has_entries {
($result->{pageInfo}{totalResults} // 0) > 0;
}

=head2 normalize_video_title($title, $fat32safe)
=head2 normalize_filename($title, $fat32safe)
Replace file-unsafe characters and trim spaces.
=cut

sub normalize_video_title {
sub normalize_filename {
my ($self, $title, $fat32safe) = @_;

state $unix_like = $^O =~ /^(?:linux|freebsd|openbsd)\z/i;

if (not $fat32safe and not $unix_like) {
$fat32safe = 1;
}

if ($fat32safe) {
$title =~ s/: / - /g;
$title =~ tr{:"*/?\\|}{;'+%!%%}; # "
Expand All @@ -279,7 +285,9 @@ sub normalize_video_title {
$title =~ tr{/}{%};
}
join(q{ }, split(q{ }, $title));
my $basename = join(q{ }, split(q{ }, $title));
$basename = substr($basename, 0, 255); # make sure the filename is not too long
return $basename;
}
=head2 format_text(%opt)
Expand Down Expand Up @@ -333,7 +341,7 @@ sub format_text {
DURATION => sub { $self->get_duration($info) },
TIME => sub { $self->get_time($info) },
TITLE => sub { $self->get_title($info) },
FTITLE => sub { $self->normalize_video_title($self->get_title($info), $fat32safe) },
FTITLE => sub { $self->normalize_filename($self->get_title($info), $fat32safe) },
CAPTION => sub { $self->get_caption($info) },
PUBLISHED => sub { $self->get_publication_date($info) },
AGE => sub { $self->get_publication_age($info) },
Expand Down Expand Up @@ -521,6 +529,13 @@ sub get_local_playlist_filenames {
grep { -T $_ } sort { CORE::fc($a) cmp CORE::fc($b) } map { Encode::decode_utf8($_) } glob("$dir/*");
}

sub make_local_playlist_filename {
my ($self, $title, $playlistID) = @_;
my $basename = $title . ' -- ' . $playlistID . '.txt';
$basename = $self->normalize_filename($basename);
return $basename;
}

sub local_playlist_snippet {
my ($self, $id) = @_;

Expand Down

0 comments on commit da358f9

Please sign in to comment.