Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Improved security: access_token and refresh_token are not stored insi…

…de the configuration file anymore;

The same tokens are shared between the CLI and GTK2 version; (this is true for the .cat files too)
Term::ReadKey is not used anymore.
Improved the code for the get_term_width() function;
Updated the Build.PL: "threads" and "Thread::Queue" are no longer recommended for gtk-youtube-viewer;
Removed the 'prefer_webm' option. WebM is preferd by default;
Removed the 'donate' button.
Version 3.0.9 is almost ready for release.
  • Loading branch information...
commit de4a73eeaf3c2e5a4131b29ad92fd16bf280879a 1 parent 962f2eb
@trizen authored
View
71 WWW-YoutubeViewer/Build.PL
@@ -9,44 +9,59 @@ use Module::Build;
my $gtk_youtube_viewer = 0;
my $builder = Module::Build->new(
- module_name => 'WWW::YoutubeViewer',
- license => 'perl',
- dist_author => q{Șuteu "Trizen" Daniel <trizenx@gmail.com>},
- dist_version_from => 'lib/WWW/YoutubeViewer.pm',
- build_requires => {'Test::More' => 0},
- configure_requires => {'Module::Build' => 0},
- get_options => {
+ module_name => 'WWW::YoutubeViewer',
+ license => 'perl',
+ dist_author => q{Daniel "Trizen" Șuteu <trizenx@gmail.com>},
+ dist_version_from => 'lib/WWW/YoutubeViewer.pm',
+ release_status => 'stable',
+
+ build_requires => {
+ 'Test::More' => 0,
+ },
+
+ configure_requires => {
+ 'Module::Build' => 0,
+ },
+
+ get_options => {
'gtk-youtube-viewer' => {
type => '!',
store => \$gtk_youtube_viewer,
},
},
+
auto_features => {
+
shuffle_playlists_support => {
- description => "Shuffle the playlists before playing (--shuffle, -s)",
+ description => "To shuffle the playlists (--shuffle, -s)",
requires => {
'List::Util' => 0,
},
},
+
https_support => {
description => "HTTPS protocol support and authentication support",
requires => {
+ 'MIME::Base64' => 0,
'LWP::Protocol::https' => 0,
},
},
+
post_comments_support => {
- description => "Post YouTube comments to videos",
+ description => "For posting comments to videos",
requires => {
'File::Temp' => 0,
'LWP::Protocol::https' => 0,
},
},
+
channels_support => {
description => "Search for YouTube channels",
requires => {
'HTML::Entities' => 0,
},
},
+
fixed_width_support => {
description => "Print the results in a fixed-width format (--fixed-width, -W)",
requires => {
@@ -54,28 +69,36 @@ my $builder = Module::Build->new(
},
},
- },
+ (
+ $gtk_youtube_viewer
+ ? (
+ threads_support => {
+ description => "Threads support for gtk-youtube-viewer. (with use_threads => 1)",
+ requires => {
+ 'threads' => 0,
+ 'Thread::Queue' => 0,
+ },
+ },
+ )
+ : ()
+ ),
+
+ },
+
add_to_cleanup => ['WWW-YoutubeViewer-*'],
create_makefile_pl => 'traditional',
);
$builder->recommends(
- 'Term::ReadKey' => 0, # to get the terminal width
- 'Term::ReadLine::Gnu::XS' => 0, # for a better user input support
- 'XML::Fast' => 0, # faster XML to HASH conversion.
-
- $gtk_youtube_viewer
- ? (
- 'threads' => 0, # threads support
- 'Thread::Queue' => 0, # threads support
- )
- : (),
-);
+ 'Term::ReadLine::Gnu::XS' => 0, # for a better user input support
+ 'XML::Fast' => 0, # faster XML to HASH conversion.
+ );
$builder->requires(
'perl' => '5.016',
'Data::Dump' => 0,
'File::Spec::Functions' => 0,
+ 'File::Basename' => 0,
'File::Path' => 0,
'Getopt::Long' => 0,
'HTTP::Request' => 0,
@@ -94,7 +117,7 @@ $builder->requires(
$builder->script_files(['bin/youtube-viewer', ($gtk_youtube_viewer ? 'bin/gtk-youtube-viewer' : ())]);
$builder->create_build_script();
-# Intalling files for GTK YouTube Viewer
+# Intalling the files for GTK YouTube Viewer
if ($gtk_youtube_viewer) {
use autouse 'File::Basename' => qw(dirname);
@@ -128,9 +151,7 @@ if ($gtk_youtube_viewer) {
foreach my $dest (
[catfile($main_share_dir, $desktop_file) => catfile($applications_dir, $desktop_file)],
- [catfile($main_dir, qw(bin youtube-viewer)) =>
- catfile($gtk_youtube_viewer_dir, qw(youtube-viewer))
- ],
+ [catfile($main_dir, qw(bin youtube-viewer)) => catfile($gtk_youtube_viewer_dir, qw(youtube-viewer))],
[catfile($main_share_dir, $glade_file) => catfile($gtk_youtube_viewer_dir, $glade_file)],
) {
copy($dest->[0], $dest->[1]) or die "Can't copy `$dest->[0]' to `$dest->[1]': $!";
View
1  WWW-YoutubeViewer/MANIFEST
@@ -4,6 +4,7 @@ Build.PL
Changes
ignore.txt
lib/WWW/YoutubeViewer.pm
+lib/WWW/YoutubeViewer/AuthToken.pm
lib/WWW/YoutubeViewer/GetCaption.pm
lib/WWW/YoutubeViewer/Itags.pm
lib/WWW/YoutubeViewer/ParseXML.pm
View
73 WWW-YoutubeViewer/MANIFEST.SKIP
@@ -0,0 +1,73 @@
+
+#!start included /usr/share/perl5/core_perl/ExtUtils/MANIFEST.SKIP
+# Avoid version control files.
+\bRCS\b
+\bCVS\b
+\bSCCS\b
+,v$
+\B\.svn\b
+\B\.git\b
+\B\.gitignore\b
+\b_darcs\b
+\B\.cvsignore$
+
+# Avoid VMS specific MakeMaker generated files
+\bDescrip.MMS$
+\bDESCRIP.MMS$
+\bdescrip.mms$
+
+# Avoid Makemaker generated and utility files.
+\bMANIFEST\.bak
+\bMakefile$
+\bblib/
+\bMakeMaker-\d
+\bpm_to_blib\.ts$
+\bpm_to_blib$
+\bblibdirs\.ts$ # 6.18 through 6.25 generated this
+
+# Avoid Module::Build generated and utility files.
+\bBuild$
+\b_build/
+\bBuild.bat$
+\bBuild.COM$
+\bBUILD.COM$
+\bbuild.com$
+
+# Avoid temp and backup files.
+~$
+\.old$
+\#$
+\b\.#
+\.bak$
+\.tmp$
+\.#
+\.rej$
+
+# Avoid OS-specific files/dirs
+# Mac OSX metadata
+\B\.DS_Store
+# Mac OSX SMB mount metadata files
+\B\._
+
+# Avoid Devel::Cover and Devel::CoverX::Covered files.
+\bcover_db\b
+\bcovered\b
+
+# Avoid MYMETA files
+^MYMETA\.
+#!end included /usr/share/perl5/core_perl/ExtUtils/MANIFEST.SKIP
+
+# Avoid configuration metadata file
+^MYMETA\.
+
+# Avoid Module::Build generated and utility files.
+\bBuild$
+\bBuild.bat$
+\b_build
+\bBuild.COM$
+\bBUILD.COM$
+\bbuild.com$
+^MANIFEST\.SKIP
+
+# Avoid archives of this distribution
+\bWWW-YoutubeViewer-[\d\.\_]+
View
6 WWW-YoutubeViewer/META.json
@@ -1,7 +1,7 @@
{
"abstract" : "A very easy interface to YouTube.",
"author" : [
- "Șuteu \"Trizen\" Daniel <trizenx@gmail.com>"
+ "Daniel \"Trizen\" Șuteu <trizenx@gmail.com>"
],
"dynamic_config" : 1,
"generated_by" : "Module::Build version 0.4008, CPAN::Meta::Converter version 2.132830",
@@ -26,12 +26,12 @@
},
"runtime" : {
"recommends" : {
- "Term::ReadKey" : "0",
"Term::ReadLine::Gnu::XS" : "0",
"XML::Fast" : "0"
},
"requires" : {
"Data::Dump" : "0",
+ "File::Basename" : "0",
"File::Path" : "0",
"File::Spec::Functions" : "0",
"Getopt::Long" : "0",
@@ -57,7 +57,7 @@
},
"WWW::YoutubeViewer::Itags" : {
"file" : "lib/WWW/YoutubeViewer/Itags.pm",
- "version" : "0.02"
+ "version" : "0.03"
},
"WWW::YoutubeViewer::ParseXML" : {
"file" : "lib/WWW/YoutubeViewer/ParseXML.pm",
View
6 WWW-YoutubeViewer/META.yml
@@ -1,7 +1,7 @@
---
abstract: 'A very easy interface to YouTube.'
author:
- - "Șuteu \"Trizen\" Daniel <trizenx@gmail.com>"
+ - "Daniel \"Trizen\" Șuteu <trizenx@gmail.com>"
build_requires:
Test::More: 0
configure_requires:
@@ -22,7 +22,7 @@ provides:
version: 0.01
WWW::YoutubeViewer::Itags:
file: lib/WWW/YoutubeViewer/Itags.pm
- version: 0.02
+ version: 0.03
WWW::YoutubeViewer::ParseXML:
file: lib/WWW/YoutubeViewer/ParseXML.pm
version: 0.03
@@ -33,11 +33,11 @@ provides:
file: lib/WWW/YoutubeViewer/Utils.pm
version: 0.02
recommends:
- Term::ReadKey: 0
Term::ReadLine::Gnu::XS: 0
XML::Fast: 0
requires:
Data::Dump: 0
+ File::Basename: 0
File::Path: 0
File::Spec::Functions: 0
Getopt::Long: 0
View
1  WWW-YoutubeViewer/Makefile.PL
@@ -7,6 +7,7 @@ WriteMakefile
'VERSION_FROM' => 'lib/WWW/YoutubeViewer.pm',
'PREREQ_PM' => {
'Data::Dump' => 0,
+ 'File::Basename' => 0,
'File::Path' => 0,
'File::Spec::Functions' => 0,
'Getopt::Long' => 0,
View
215 WWW-YoutubeViewer/bin/gtk-youtube-viewer
@@ -18,29 +18,31 @@
#-------------------------------------------------------
# GTK Youtube Viewer
# Created on: 12 September 2010
-# Latest edit on: 06 September 2013
+# Latest edit on: 11 November 2013
# Website: http://trizen.googlecode.com
#-------------------------------------------------------
use 5.010;
use strict;
-no if $] >= 5.018, warnings => 'experimental::smartmatch';
-
#use lib qw(../lib); # devel only
#use warnings; # debug only
+no if $] >= 5.018, warnings => 'experimental::smartmatch';
+
use Gtk2 qw(-init);
-use autouse 'File::Basename' => qw(dirname);
use File::Spec::Functions qw(
rel2abs
- catdir catfile
- curdir updir
- path tmpdir
+ catdir
+ catfile
+ curdir
+ updir
+ path
+ tmpdir
);
my $appname = 'GTK Youtube Viewer';
-my $version = '3.0.8';
+my $version = '3.0.9';
my $execname = 'gtk-youtube-viewer';
# Developer key
@@ -54,14 +56,19 @@ my $xdg_config_home = $ENV{XDG_CONFIG_HOME}
my $config_dir = catdir($xdg_config_home, $execname);
my $config_file = catfile($config_dir, "$execname.conf");
-if (not -d $config_dir) {
- require File::Path;
- File::Path::make_path($config_dir)
- or warn "[!] Can't create dir '$config_dir': $!";
+my $yv_config_dir = catdir($xdg_config_home, 'youtube-viewer');
+my $auth_tokens_file = catfile($yv_config_dir, 'reg.dat');
+
+foreach my $dir ($config_dir, $yv_config_dir) {
+ if (not -d $dir) {
+ require File::Path;
+ File::Path::make_path($dir)
+ or warn "[!] Can't create dir '$dir': $!";
+ }
}
# Unchangeable variables goes here
-my %constant = (win32 => $^O =~ /^mswin\d/i || 0,);
+my %constant = (win32 => ($^O =~ /^mswin\d/i || 0));
# CLI Youtube Viewer
my $cli_youtube_viewer = '/usr/share/gtk-youtube-viewer/youtube-viewer';
@@ -135,7 +142,6 @@ my %CONFIG = (
mainw_fullscreen => 0,
# Youtube options
- prefer_webm => 1,
prefer_https => 0,
results => 10,
resolution => 'original',
@@ -171,8 +177,6 @@ my %CONFIG = (
hpaned_position => 420,
search_channels => 0,
search_playlists => 0,
- access_token => undef,
- refresh_token => undef,
thousand_separator => q{,},
perl_bin => $^X,
default_thumb => 'default',
@@ -197,7 +201,7 @@ sub set_mplayer_arguments {
my $config_documentation = <<"EOD";
#!/usr/bin/perl
-# $appname - configuration file
+# $appname $version - configuration file
EOD
@@ -206,7 +210,7 @@ EOD
require Data::Dump;
open my $config_fh, '>', $config_file
or do { warn "[!] Can't open '${config_file}' for write: $!"; return };
- my $dumped_config = q{our $CONFIG = } . Data::Dump::dump(\%CONFIG);
+ my $dumped_config = q{our $CONFIG = } . Data::Dump::pp(\%CONFIG) . "\n";
print $config_fh $config_documentation, $dumped_config;
close $config_fh;
}
@@ -225,8 +229,9 @@ foreach my $sig (qw(HUP TERM INT KILL)) {
# Locating the .glade interface file and icons dir
my ($interface_path, $icons_path);
if (-f (my $glade_file = catfile(updir(), 'share', "$execname.glade"))) {
+ require File::Basename;
$interface_path = rel2abs($glade_file);
- $icons_path = catdir(dirname($interface_path), 'gtk-youtube-viewer-icons');
+ $icons_path = catdir(File::Basename::dirname($interface_path), 'gtk-youtube-viewer-icons');
}
else {
foreach my $usr_dir (qw(/usr /usr/local . ..)) {
@@ -244,17 +249,15 @@ $gui->connect_signals(undef);
# ------------- Get GUI objects ------------- #
my (
- $mainw, $users_list_window, $help_window, $prefernces_window,
- $login_to_youtube, $errors_window, $details_window, $about_window,
- $treeview, $liststore, $config_view, $statusbar,
- $thumbs_column, $textview_help, $sort_combobox, $sort_by_time_combobox,
- $resolution_combobox, $spin_results, $users_treeview, $users_liststore,
- $thumbs_checkbutton, $search_for_combobox, $spin_start_with_page, $fullscreen_checkbutton,
- $notebook, $search_entry, $from_author_entry, $gif_spinner,
- $hbox2, $feeds_window, $feeds_treeview, $feeds_liststore,
- $feeds_statusbar, $safesearch_combobox, $hd_combobox, $caption_combobox,
- $duration_combobox, $warnings_window, $warnings_textview, $errors_textview,
- $category_id_entry, $more_options_expander, $cat_treeview, $cats_liststore,
+ $mainw, $users_list_window, $help_window, $prefernces_window, $login_to_youtube,
+ $errors_window, $details_window, $about_window, $treeview, $liststore,
+ $config_view, $statusbar, $thumbs_column, $textview_help, $sort_combobox,
+ $sort_by_time_combobox, $resolution_combobox, $spin_results, $users_treeview, $users_liststore,
+ $thumbs_checkbutton, $search_for_combobox, $spin_start_with_page, $fullscreen_checkbutton, $notebook,
+ $search_entry, $from_author_entry, $gif_spinner, $hbox2, $feeds_window,
+ $feeds_treeview, $feeds_liststore, $feeds_statusbar, $safesearch_combobox, $hd_combobox,
+ $caption_combobox, $duration_combobox, $warnings_window, $warnings_textview, $errors_textview,
+ $category_id_entry, $more_options_expander, $cat_treeview, $cats_liststore,
);
sub get_objects {
@@ -336,7 +339,7 @@ local $SIG{__DIE__} = sub {
if ($error =~ m{^Can't locate (.+?)\.pm\b}) {
my $module = $1;
$module =~ s{[/\\]+}{::}g;
-"\nThe module $module is required!\n\nTo install the module, just type in terminal:\n\tsudo cpan $module\n";
+ "\nThe module $module is required!\n\nTo install the module, just type in terminal:\n\tsudo cpan $module\n";
}
}
. "\n=>> Previous warnings:\n" . get_text($warnings_textview)
@@ -347,12 +350,11 @@ local $SIG{__DIE__} = sub {
};
#---------------------- LOAD IMAGES ----------------------#
-my $app_icon_pixbuf = 'Gtk2::Gdk::Pixbuf'->new_from_file("$icons_path/$execname.png");
-my $user_icon_pixbuf = 'Gtk2::Gdk::Pixbuf'->new_from_file_at_size("$icons_path/user.png", 16, 16);
-my $feed_icon_pixbuf = 'Gtk2::Gdk::Pixbuf'->new_from_file_at_size("$icons_path/feed_icon.png", 16, 16);
-my $default_thumb = 'Gtk2::Gdk::Pixbuf'->new_from_file_at_size("$icons_path/default_thumb.jpg", 120, 90);
-my $donate_icon_pixbuf = 'Gtk2::Gdk::Pixbuf'->new_from_file("$icons_path/donate.png");
-my $animation = 'Gtk2::Gdk::PixbufAnimation'->new_from_file("$icons_path/spinner.gif");
+my $app_icon_pixbuf = 'Gtk2::Gdk::Pixbuf'->new_from_file("$icons_path/$execname.png");
+my $user_icon_pixbuf = 'Gtk2::Gdk::Pixbuf'->new_from_file_at_size("$icons_path/user.png", 16, 16);
+my $feed_icon_pixbuf = 'Gtk2::Gdk::Pixbuf'->new_from_file_at_size("$icons_path/feed_icon.png", 16, 16);
+my $default_thumb = 'Gtk2::Gdk::Pixbuf'->new_from_file_at_size("$icons_path/default_thumb.jpg", 120, 90);
+my $animation = 'Gtk2::Gdk::PixbufAnimation'->new_from_file("$icons_path/spinner.gif");
# Setting application title and icon
$mainw->set_title("$appname $version");
@@ -361,34 +363,62 @@ $mainw->set_icon($app_icon_pixbuf);
# Regular expressions
use WWW::YoutubeViewer::RegularExpressions;
+our $CONFIG;
+require $config_file; # Load the configuration file
+
{
my $i = length $key;
$key =~ s/(.{$i})(.)/$2$1/g while $i--;
}
-our $CONFIG;
-require $config_file; # Load the configuration file
-
if (ref $CONFIG ne 'HASH') {
$CONFIG = do($config_file) || warn "Can't load the configuration file: $!";
}
-my @valid_keys = grep exists $CONFIG{$_}, keys %{$CONFIG};
+require WWW::YoutubeViewer::AuthToken;
+my $yv_token = WWW::YoutubeViewer::AuthToken->new(key => $key);
+
+my ($access_token, $refresh_token);
+if (defined $CONFIG->{access_token} and defined $CONFIG->{refresh_token}) {
+
+ $access_token = $CONFIG->{access_token};
+ $refresh_token = $CONFIG->{refresh_token};
+
+ $yv_token->to_file($access_token, $refresh_token, $auth_tokens_file);
+}
+elsif (-e $auth_tokens_file) {
+ ($access_token, $refresh_token) = $yv_token->from_file($auth_tokens_file);
+}
+
+my @valid_keys = grep { exists $CONFIG{$_} } keys %{$CONFIG};
@CONFIG{@valid_keys} = @{$CONFIG}{@valid_keys};
-if (ref $CONFIG ne 'HASH' or not %CONFIG ~~ %{$CONFIG}) {
+if (ref $CONFIG ne 'HASH') {
+ rename($config_file, $config_file . '.bak');
+ dump_configuration();
+}
+elsif (not \%CONFIG ~~ $CONFIG) {
dump_configuration();
}
require WWW::YoutubeViewer;
my $yv_obj = WWW::YoutubeViewer->new(
- key => $key,
- app_name => $appname,
- app_version => $version,
- config_dir => $config_dir,
- escape_utf8 => 1,
+ key => $key,
+ app_name => $appname,
+ app_version => $version,
+ access_token => $access_token,
+ refresh_token => $refresh_token,
+ config_dir => $yv_config_dir,
+ escape_utf8 => 1,
);
+if (defined $yv_obj->get_access_token()) {
+ show_user_panel();
+}
+else {
+ $statusbar->push(1, 'Not logged');
+}
+
{
my $client_id = '991455593101.apps.googleusercontent.com';
my $client_secret = 'YcxxWCCbBwIr-IhUDCanrp41';
@@ -437,20 +467,6 @@ sub apply_configuration {
# Checking thumbs button
$thumbs_checkbutton->set_active($CONFIG{show_thumbs});
- # Auto-login
- if (length $CONFIG{access_token}) {
- if ($yv_obj->set_access_token($CONFIG{access_token})) {
- $yv_obj->set_refresh_token($CONFIG{refresh_token});
- show_user_panel();
- }
- else {
- warn "[!] Invalid access token!\n";
- }
- }
- else {
- $statusbar->push(1, 'Not logged');
- }
-
# Setup threads
if ($CONFIG{use_threads}) {
set_threads();
@@ -493,13 +509,13 @@ apply_configuration();
# YouTube usernames
my %users_table = map { lc($_) => $_ } (
- 'AtGoogleTalks', 'AtheistsAreSkeptics', 'Best0fScience', 'Google',
- 'GoogleChrome', 'GoogleTechTalks', 'KhanAcademy', 'NASAtelevision',
- 'NatCen4ScienceEd', 'GoogleDevelopers', 'VSauce', 'Gotbletu',
- 'ScienceChannel', 'SpaceRip', 'TEDtalksDirector', 'ThunderF00t',
- 'MIT', 'SixtySymbols', 'SpitzerScienceCenter', 'SciShow',
- 'UCBerkeley', 'UCTelevision', 'FOSDEMtalks', 'BigThink',
- 'ProfessorFink', 'StanfordUniversity', 'UCTVSeminars', '1Veritasium',
+ 'AtGoogleTalks', 'AtheistsAreSkeptics', 'Best0fScience', 'Google',
+ 'GoogleChrome', 'GoogleTechTalks', 'KhanAcademy', 'NASAtelevision',
+ 'NatCen4ScienceEd', 'GoogleDevelopers', 'VSauce', 'Gotbletu',
+ 'ScienceChannel', 'SpaceRip', 'TEDtalksDirector', 'ThunderF00t',
+ 'MIT', 'SixtySymbols', 'SpitzerScienceCenter', 'SciShow',
+ 'UCBerkeley', 'UCTelevision', 'FOSDEMtalks', 'BigThink',
+ 'ProfessorFink', 'StanfordUniversity', 'UCTVSeminars', '1Veritasium',
);
set_usernames();
@@ -593,7 +609,6 @@ sub new_image_from_pixbuf {
{
$gui->get_object('username_list')->set_image(new_image_from_pixbuf('icon_from_pixbuf', $user_icon_pixbuf));
$gui->get_object('channels_button')->set_image(new_image_from_pixbuf('icon_from_pixbuf', $user_icon_pixbuf));
- $gui->get_object('donate_button')->set_image(new_image_from_pixbuf('icon_from_pixbuf', $donate_icon_pixbuf));
$gui->get_object('button6')->set_image(new_image_from_pixbuf('icon_from_pixbuf', $feed_icon_pixbuf));
$gui->get_object('button23')->set_image(new_image_from_pixbuf('icon_from_pixbuf', $feed_icon_pixbuf));
}
@@ -783,23 +798,24 @@ sub show_user_panel {
hide_login_to_youtube_window();
if ($code ne q{}) {
-
my $json_data = $yv_obj->oauth_login($code) // return;
say $json_data if $yv_obj->get_debug;
my $info = $yv_utils->basic_json_parser($json_data);
- if ($gui->get_object('login_check_button')->get_active) {
- $CONFIG{access_token} = $info->{access_token} // return;
- $CONFIG{refresh_token} = $info->{refresh_token} // return;
- dump_configuration();
- }
+ if (defined $info->{access_token}) {
- $yv_obj->set_access_token($info->{access_token}) // return;
- $yv_obj->set_refresh_token($info->{refresh_token}) // return;
+ $yv_obj->set_access_token($info->{access_token}) // return;
+ $yv_obj->set_refresh_token($info->{refresh_token}) // return;
- show_user_panel();
- return 1;
+ if ($gui->get_object('login_check_button')->get_active) {
+ $yv_token->to_file($yv_obj->get_access_token, $yv_obj->get_refresh_token, $auth_tokens_file)
+ or warn "Can't store the authentication tokens: $!";
+ }
+
+ show_user_panel();
+ return 1;
+ }
}
return;
}
@@ -1180,15 +1196,13 @@ sub save_usernames_to_file {
sub log_out {
change_subscription_page(0);
- undef $CONFIG{access_token};
- undef $CONFIG{refresh_token};
-
- dump_configuration();
+ unlink $auth_tokens_file
+ or warn "Can't unlink: `$auth_tokens_file' -> $!";
$yv_obj->set_access_token();
$yv_obj->set_refresh_token();
- $statusbar->push(1, "Not logged.");
+ $statusbar->push(1, "Not logged.");
return 1;
}
@@ -1685,12 +1699,7 @@ sub get_streaming_url {
require WWW::YoutubeViewer::Itags;
state $yv_itags = WWW::YoutubeViewer::Itags->new();
- my $streaming = $yv_itags->find_streaming_url(\@urls, $CONFIG{prefer_webm}, $CONFIG{resolution});
-
- if (not defined $streaming) {
- $streaming = $yv_itags->find_streaming_url(\@urls, $CONFIG{prefer_webm});
- }
-
+ my $streaming = $yv_itags->find_streaming_url(\@urls, $CONFIG{resolution});
my $info = @urls && ref $urls[-1] eq 'HASH' && exists $urls[-1]{status} ? $urls[-1] : {};
return {
@@ -1816,8 +1825,7 @@ sub clear_text {
}
sub run_cli_youtube_viewer {
- execute_external_program($CONFIG{terminal}, '-e', q{'} . join(' ', $CONFIG{perl_bin}, $CONFIG{cli_youtube_viewer}),
- q{'});
+ execute_external_program($CONFIG{terminal}, '-e', q{'} . join(' ', $CONFIG{perl_bin}, $CONFIG{cli_youtube_viewer}), q{'});
}
sub find_terminal {
@@ -1930,9 +1938,7 @@ sub execute_cli_youtube_viewer {
map { chr ord eq q{'} ? $_ : quotemeta } $CONFIG{terminal},
'-e',
q{'}
- . join(q{ },
- $CONFIG{perl_bin}, $CONFIG{cli_youtube_viewer},
- get_options_as_arguments(), @arguments)
+ . join(q{ }, $CONFIG{perl_bin}, $CONFIG{cli_youtube_viewer}, get_options_as_arguments(), @arguments)
. q{'}
)
)
@@ -1941,8 +1947,7 @@ sub execute_cli_youtube_viewer {
say $command if $yv_obj->get_debug;
system $command;
- warn "youtube-viewer - code exit: $?\n" if $?;
-
+ warn "youtube-viewer - exit code: $?\n" if $?;
return 1;
}
@@ -2006,10 +2011,11 @@ sub favorite_video {
sub subscribe_channel {
my $user = get_username_for_selected_video();
- $feeds_statusbar->push(0,
- $yv_obj->subscribe_channel($user)
+ $feeds_statusbar->push(
+ 0, $yv_obj->subscribe_channel($user)
? "Successfully subscribed to channel: $user."
- : 'Error!');
+ : 'Error!'
+ );
}
sub like_selected_video {
@@ -2034,13 +2040,10 @@ sub send_comment_to_video {
my $videoID = get_selected_video_code() or return;
my $comment = get_text($gui->get_object('comment_textview'));
- $feeds_statusbar->push(
- 0,
- length($comment)
- && $yv_obj->send_comment_to_video($videoID, $comment)
+ $feeds_statusbar->push(0,
+ length($comment) && $yv_obj->send_comment_to_video($videoID, $comment)
? 'Video comment has been posted!'
- : 'Error!'
- );
+ : 'Error!');
}
sub print_comments {
View
158 WWW-YoutubeViewer/bin/youtube-viewer
@@ -18,7 +18,7 @@
#-------------------------------------------------------
# Appname: youtube-viewer
# Created on: 02 June 2010
-# Latest edit on: 07 November 2013
+# Latest edit on: 11 November 2013
# Websites: http://trizen.googlecode.com
# https://github.com/trizen/youtube-viewer
#-------------------------------------------------------
@@ -111,7 +111,7 @@ no if $] >= 5.018, warnings => 'experimental::smartmatch';
no if $] >= 5.018, warnings => 'deprecated';
my $appname = 'Youtube Viewer';
-my $version = '3.0.8';
+my $version = '3.0.9';
my $execname = 'youtube-viewer';
# A better <STDIN> support:
@@ -122,13 +122,11 @@ my $term = Term::ReadLine->new("$appname $version");
my $key = 'eTj9NtCyOsGMliTTwz-T85muGT-ARAwVREslfB_giHP3X339Jkpn5Xf71pQXY96xWtFY1oFHt530ct5uZZJk5YTghbNm2IrwZ4';
# Options (key=>value) goes here
-my %opt = ();
+my %opt = ();
+my $term_width = 80;
# Unchangeable data goes here
-my %constant = (
- dash_line => q{-} x 80,
- win32 => $^O =~ /^mswin\d/i || 0,
- );
+my %constant = (win32 => ($^O =~ /^mswin\d/i || 0));
my $xdg_config_home = $ENV{XDG_CONFIG_HOME}
|| catdir(
@@ -142,7 +140,8 @@ my $xdg_config_home = $ENV{XDG_CONFIG_HOME}
# Configuration dir/file
my $config_dir = catdir($xdg_config_home, $execname);
-my $config_file = catfile($config_dir, "$execname.conf");
+my $config_file = catfile($config_dir, "$execname.conf");
+my $auth_tokens_file = catfile($config_dir, 'reg.dat');
if (not -d $config_dir) {
require File::Path;
@@ -175,7 +174,6 @@ my %CONFIG = (
mplayer_arguments => '-prefer-ipv4 -really-quiet -cache %d -cache-min %d',
# Youtube options
- prefer_webm => 1,
prefer_https => 0,
results => 20,
resolution => 'original',
@@ -209,10 +207,8 @@ my %CONFIG = (
results_with_colors => 0,
results_fixed_width => 0,
interactive => 1,
- adj_for_term_width => $constant{win32} ^ 1,
+ get_term_width => $constant{win32} ^ 1,
download_with_wget => $constant{win32} ^ 1,
- access_token => undef,
- refresh_token => undef,
thousand_separator => q{,},
downloads_folder => curdir(),
keep_original_video => 0,
@@ -325,20 +321,22 @@ $notes_options
page, go to the next page and play the 9th video.
STDIN_HELP
-my $config_documentation = <<"EOD";
+{
+ my $config_documentation = <<"EOD";
#!/usr/bin/perl
-# $appname - configuration file
+# $appname $version - configuration file
EOD
-sub dump_configuration {
- require Data::Dump;
- open my $config_fh, '>', $config_file
- or do { warn "[!] Can't open '${config_file}' for write: $!"; return };
- my $dumped_config = q{our $CONFIG = } . Data::Dump::dump(\%CONFIG);
- print $config_fh $config_documentation, $dumped_config;
- close $config_fh;
+ sub dump_configuration {
+ require Data::Dump;
+ open my $config_fh, '>', $config_file
+ or do { warn "[!] Can't open '${config_file}' for write: $!"; return };
+ my $dumped_config = q{our $CONFIG = } . Data::Dump::pp(\%CONFIG) . "\n";
+ print $config_fh $config_documentation, $dumped_config;
+ close $config_fh;
+ }
}
if (not -e $config_file or $opt{reconfigure}) {
@@ -348,29 +346,48 @@ if (not -e $config_file or $opt{reconfigure}) {
our $CONFIG;
require $config_file; # Load the configuration file
+{
+ my $i = length $key;
+ $key =~ s/(.{$i})(.)/$2$1/g while $i--;
+}
+
if (ref $CONFIG ne 'HASH') {
$CONFIG = do($config_file) || warn "Can't load the configuration file: $!";
}
-my @valid_keys = grep exists $CONFIG{$_}, keys %{$CONFIG};
+require WWW::YoutubeViewer::AuthToken;
+my $yv_token = WWW::YoutubeViewer::AuthToken->new(key => $key);
+
+my ($access_token, $refresh_token);
+if (defined $CONFIG->{access_token} and defined $CONFIG->{refresh_token}) {
+
+ $access_token = $CONFIG->{access_token};
+ $refresh_token = $CONFIG->{refresh_token};
+
+ $yv_token->to_file($access_token, $refresh_token, $auth_tokens_file);
+}
+elsif (-e $auth_tokens_file) {
+ ($access_token, $refresh_token) = $yv_token->from_file($auth_tokens_file);
+}
+
+my @valid_keys = grep { exists $CONFIG{$_} } keys %{$CONFIG};
@CONFIG{@valid_keys} = @{$CONFIG}{@valid_keys};
-if (ref $CONFIG ne 'HASH' or not %CONFIG ~~ %{$CONFIG}) {
+if (ref $CONFIG ne 'HASH') {
+ rename($config_file, $config_file . '.bak');
+ dump_configuration();
+}
+elsif (not \%CONFIG ~~ $CONFIG) {
dump_configuration();
}
@opt{keys %CONFIG} = values(%CONFIG);
-{
- my $i = length $key;
- $key =~ s/(.{$i})(.)/$2$1/g while $i--;
-}
-
require WWW::YoutubeViewer;
my $yv_obj = WWW::YoutubeViewer->new(
key => $key,
- access_token => $CONFIG{access_token},
- refresh_token => $CONFIG{refresh_token},
+ access_token => $access_token,
+ refresh_token => $refresh_token,
app_name => $appname,
app_version => $version,
config_dir => $config_dir,
@@ -526,7 +543,6 @@ Other options:
--clobber : overwrite an existent video (with -d)
--skip-if-exists! : don't download videos which already exists (with -d)
--prefer-https! : use the HTTPS protocol instead of the HTTP protocol
- --prefer-webm! : use the WebM format when it is available
--downloads-dir=s : downloads directory (set: '$opt{downloads_folder}')
Help options:
@@ -551,7 +567,7 @@ sub wrap_text {
my (%args) = @_;
require Text::Wrap;
- ${Text::Wrap::columns} = $args{columns} || length($constant{dash_line});
+ ${Text::Wrap::columns} = $args{columns} || $term_width;
my $text = "@{$args{text}}";
$text =~ tr{\r}{}d;
@@ -854,10 +870,6 @@ sub apply_configuration {
logout();
}
- if ($opt->{adj_for_term_width}) {
- adj_for_term_width();
- }
-
# ... OTHER OPTIONS ... #
if (defined $opt->{shuffle_playlist}) {
require List::Util;
@@ -1094,7 +1106,6 @@ sub parse_arguments {
'all|A|play-all!' => \$opt{play_all},
'use-colors|colors|colored!' => \$opt{colors},
'prefer-https|prefer_https!' => \$opt{prefer_https},
- 'prefer-webm|prefer_webm!' => \$opt{prefer_webm},
'noconfig|N' => \$opt{noconfig},
'playlists|p|pl:s' => \$opt{search_playlists},
@@ -1133,7 +1144,7 @@ sub parse_arguments {
'rp|rem-played|remove_played_file!' => \$opt{remove_played_file},
'clobber!' => \$opt{clobber},
'info|i|show-info=s' => \$opt{show_video_info},
- 'get-term-width!' => \$opt{adj_for_term_width},
+ 'get-term-width!' => \$opt{get_term_width},
'page=i' => \$opt{page},
'novideo|n!' => \$opt{novideo},
'results=i' => \$opt{results},
@@ -1251,14 +1262,9 @@ sub get_mplayer {
}
# Get term width
-sub adj_for_term_width {
- eval { require Term::ReadKey };
- $constant{dash_line} = q{-} x (
- $@
- ? ((split(q{ }, `stty size`))[1] || 80)
- : (Term::ReadKey::GetTerminalSize())[0]
- );
- return 1;
+sub get_term_width {
+ return $term_width if $constant{win32};
+ $term_width = (-t STDOUT) ? ((split(q{ }, `stty size`))[1] || $term_width) : $term_width;
}
sub first_user_input {
@@ -1380,10 +1386,8 @@ sub get_user_input {
sub logout {
- undef $CONFIG{access_token};
- undef $CONFIG{refresh_token};
-
- dump_configuration();
+ unlink $auth_tokens_file
+ or warn "Can't unlink: `$auth_tokens_file' -> $!";
$yv_obj->set_access_token();
$yv_obj->set_refresh_token();
@@ -1417,10 +1421,10 @@ INFO
my $remember_me = $term->ask_yn(prompt => colored("\nRemember me", 'bold'),
default => 'y',);
+
if ($remember_me) {
- $CONFIG{access_token} = $yv_obj->get_access_token;
- $CONFIG{refresh_token} = $yv_obj->get_refresh_token;
- dump_configuration();
+ $yv_token->to_file($yv_obj->get_access_token, $yv_obj->get_refresh_token, $auth_tokens_file)
+ or warn "Can't store the authentication tokens: $!";
}
return 1;
@@ -1636,8 +1640,6 @@ sub general_options {
my $mode = $args{mode};
my $callback_args = ref $args{args} eq 'ARRAY' ? $args{args} : [];
- adj_for_term_width() if $opt{adj_for_term_width};
-
given ($option) {
when (\&quit_required) {
main_quit(0);
@@ -1738,8 +1740,7 @@ sub warn_cant_do {
sub warn_cant_get {
my ($name, $videoID) = @_;
- warn colored("\n[!] Can't get $name for video: " . sprintf($CONFIG{youtube_video_url}, $videoID), 'bold red')
- . "\n";
+ warn colored("\n[!] Can't get $name for video: " . sprintf($CONFIG{youtube_video_url}, $videoID), 'bold red') . "\n";
}
sub warn_last_page {
@@ -1948,8 +1949,7 @@ HELP
my ($fh, $filename) = File::Temp::tempfile();
system $ENV{EDITOR} // 'nano', $filename;
if ($?) {
- warn colored("\n[!] Editor exited with a non-zero code. Unable to continue!", 'bold red')
- . "\n";
+ warn colored("\n[!] Editor exited with a non-zero code. Unable to continue!", 'bold red') . "\n";
}
else {
my $comment = do { local (@ARGV, $/) = $filename; <> };
@@ -2438,12 +2438,7 @@ sub get_streaming_url {
require WWW::YoutubeViewer::Itags;
state $yv_itags = WWW::YoutubeViewer::Itags->new();
- my ($streaming, $resolution) = $yv_itags->find_streaming_url(\@urls, $opt{prefer_webm}, $opt{resolution});
-
- if (not defined $streaming) { # get the highest resolution
- ($streaming, $resolution) = $yv_itags->find_streaming_url(\@urls, $opt{prefer_webm});
- }
-
+ my ($streaming, $resolution) = $yv_itags->find_streaming_url(\@urls, $opt{resolution});
my $info = @urls && ref $urls[-1] eq 'HASH' && exists $urls[-1]{status} ? $urls[-1] : {};
return {
@@ -2523,9 +2518,8 @@ sub download_video {
$output =~ s/\.\w{2,5}$//;
my $new_file = "$output.$opt{convert_to}";
- my $ffmpeg = sprintf($opt{ffmpeg_command},
- map { q{"} . s{(["\\`\$])}{\\$1}gr . q{"} }
- map { rel2abs($_) } $title, $new_file);
+ my $ffmpeg = sprintf($opt{ffmpeg_command}, map { q{"} . s{(["\\`\$])}{\\$1}gr . q{"} }
+ map { rel2abs($_) } $title, $new_file);
say $ffmpeg if $yv_obj->get_debug;
system $ffmpeg;
@@ -2554,16 +2548,11 @@ sub download_video {
sub play_videos {
my ($videos) = @_;
- if ($opt{adj_for_term_width}) {
- adj_for_term_width();
- }
-
foreach my $video (@{$videos}) {
my $streaming = get_streaming_url($video->{videoID});
if (defined $streaming->{info}{status} and not $streaming->{info}{status} =~ /^(?:ok|success)/i) {
- warn colored("(x_x) Can't stream: " . sprintf($CONFIG{youtube_video_url}, $video->{videoID}), 'bold red')
- . "\n";
+ warn colored("(x_x) Can't stream: " . sprintf($CONFIG{youtube_video_url}, $video->{videoID}), 'bold red') . "\n";
warn colored("(x_x) Status: $streaming->{info}{status}", 'bold red') . "\n\n";
}
@@ -2640,17 +2629,19 @@ sub play_videos_matched_by_regex {
sub print_video_info {
my ($info) = @_;
+ my $hr = '-' x ($opt{get_term_width} ? get_term_width() : $term_width);
+
printf(
"\n%s %s\n%s\n%s\n%s\n%s",
_bold_color('=>>'),
'Description',
- $constant{dash_line},
+ $hr,
wrap_text(
i_tab => q{},
s_tab => q{},
text => [$info->{description} || 'No description available...']
),
- $constant{dash_line},
+ $hr,
_bold_color('* URL: ')
);
@@ -2658,9 +2649,7 @@ sub print_video_info {
my $title_length = length($info->{title});
- print "\n$constant{dash_line}\n",
- q{ } x ((length($constant{dash_line}) - $title_length) / 2 - 4) =>
- (_bold_color("=>> $info->{title} <<=") . "\n\n"),
+ print "\n$hr\n", q{ } x (($term_width - $title_length) / 2 - 4) => (_bold_color("=>> $info->{title} <<=") . "\n\n"),
map(sprintf(q{** } . "%-*s: %s\n", $opt{_colors} ? 18 : 10, _bold_color($_->[0]), $_->[1]),
(
['Author' => $info->{author}],
@@ -2673,7 +2662,7 @@ sub print_video_info {
['Views' => $yv_utils->set_thousands($info->{views})],
$info->{published} ? ['Published' => $yv_utils->format_date($info->{published})] : (),
)),
- "$constant{dash_line}\n";
+ "$hr\n";
return 1;
}
@@ -2688,10 +2677,8 @@ sub print_videos {
my $url = $results->{url};
my $videos = $results->{results};
- state $term_width = 80;
- if ($opt{adj_for_term_width} and $opt{results_fixed_width}) {
- adj_for_term_width();
- $term_width = length($constant{dash_line});
+ if ($opt{get_term_width} and $opt{results_fixed_width}) {
+ get_term_width();
}
my $num = 0;
@@ -2715,8 +2702,7 @@ sub print_videos {
}
elsif ($opt{results_with_colors}) {
print "\n" if $num == 0;
- printf(
- "%s. %s (%s) (%s)\n",
+ printf("%s. %s (%s) (%s)\n",
colored(sprintf('%2d', ++$num), 'bold'),
colored($video->{title}, 'bold green'),
colored("by $video->{author}", 'bold yellow'),
View
176 WWW-YoutubeViewer/lib/WWW/YoutubeViewer/AuthToken.pm
@@ -0,0 +1,176 @@
+package WWW::YoutubeViewer::AuthToken;
+
+use 5.010;
+use strict;
+use warnings;
+
+=head1 NAME
+
+WWW::YoutubeViewer::AuthToken - Encode/decode the authentication tokens
+
+=head1 VERSION
+
+Version 0.01
+
+=cut
+
+our $VERSION = '0.01';
+
+=head1 SYNOPSIS
+
+ use WWW::YoutubeViewer::AuthToken;
+
+ my $yv_token = WWW::YoutubeViewer::AuthToken->new(key => "SOME_KEY");
+
+ my $decoded = $yv_token->decode($token);
+ my $encoded = $yv_token->encode($token);
+
+ # Encode and store the tokens inside a file
+ $yv_token->to_file($access_token, $refresh_token, $file);
+
+ # Decode and return the tokens from a file
+ my ($access_token, $refresh_token) = $yv_token->from_file($file);
+
+=head1 SUBROUTINES/METHODS
+
+=head2 new()
+
+Return the blessed object.
+
+=cut
+
+sub new {
+ my $class = shift;
+ bless {@_, EOL => "\0" x 3}, $class;
+}
+
+=head2 encode($token)
+
+Encode the token with a given key and return it.
+
+=cut
+
+sub encode {
+ my ($self, $token) = @_;
+
+ require MIME::Base64;
+ MIME::Base64::encode_base64($token ^ substr($self->{key}, -length($token)));
+}
+
+=head2 decode($token)
+
+Decode the token with a given key and return it.
+
+=cut
+
+sub decode {
+ my ($self, $token) = @_;
+
+ require MIME::Base64;
+ my $bin = MIME::Base64::decode_base64($token);
+ $bin ^ substr($self->{key}, -length($bin));
+}
+
+=head2 to_file($acess_token, $refresh_token, $file)
+
+Encode and save the token in a file.
+
+=cut
+
+sub to_file {
+ my ($self, $access_token, $refresh_token, $file) = @_;
+
+ if (open my $fh, '>:raw', $file) {
+ foreach my $token ($access_token, $refresh_token) {
+ print {$fh} $self->encode($token) . $self->{EOL};
+ }
+ close $fh;
+ return 1;
+ }
+
+ return;
+}
+
+=head2 from_file($file)
+
+Encode and save the token in a file.
+
+=cut
+
+sub from_file {
+ my ($self, $file) = @_;
+
+ if (-f $file) {
+ local $/ = $self->{EOL};
+ open my $fh, '<:raw', $file;
+
+ my @tokens;
+ foreach my $i (0 .. 1) {
+ chomp(my $token = <$fh>);
+ $token =~ /\S/ || last;
+ push @tokens, $self->decode($token);
+ }
+
+ close $fh;
+ return @tokens;
+ }
+
+ return;
+}
+
+=head1 AUTHOR
+
+Trizen, C<< <trizenx at gmail.com> >>
+
+
+=head1 SUPPORT
+
+You can find documentation for this module with the perldoc command.
+
+ perldoc WWW::YoutubeViewer::AuthToken
+
+
+=head1 LICENSE AND COPYRIGHT
+
+Copyright 2013 Trizen.
+
+This program is free software; you can redistribute it and/or modify it
+under the terms of the the Artistic License (2.0). You may obtain a
+copy of the full license at:
+
+L<http://www.perlfoundation.org/artistic_license_2_0>
+
+Any use, modification, and distribution of the Standard or Modified
+Versions is governed by this Artistic License. By using, modifying or
+distributing the Package, you accept this license. Do not use, modify,
+or distribute the Package, if you do not accept this license.
+
+If your Modified Version has been derived from a Modified Version made
+by someone other than you, you are nevertheless required to ensure that
+your Modified Version complies with the requirements of this license.
+
+This license does not grant you the right to use any trademark, service
+mark, tradename, or logo of the Copyright Holder.
+
+This license includes the non-exclusive, worldwide, free-of-charge
+patent license to make, have made, use, offer to sell, sell, import and
+otherwise transfer the Package with respect to any patent claims
+licensable by the Copyright Holder that are necessarily infringed by the
+Package. If you institute patent litigation (including a cross-claim or
+counterclaim) against any party alleging that the Package constitutes
+direct or contributory patent infringement, then this Artistic License
+to you shall terminate on the date that such litigation is filed.
+
+Disclaimer of Warranty: THE PACKAGE IS PROVIDED BY THE COPYRIGHT HOLDER
+AND CONTRIBUTORS "AS IS' AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES.
+THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED TO THE EXTENT PERMITTED BY
+YOUR LOCAL LAW. UNLESS REQUIRED BY LAW, NO COPYRIGHT HOLDER OR
+CONTRIBUTOR WILL BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, OR
+CONSEQUENTIAL DAMAGES ARISING IN ANY WAY OUT OF THE USE OF THE PACKAGE,
+EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+=cut
+
+1; # End of WWW::YoutubeViewer::AuthToken
View
76 WWW-YoutubeViewer/lib/WWW/YoutubeViewer/Itags.pm
@@ -2,8 +2,7 @@ package WWW::YoutubeViewer::Itags;
use 5.010;
use strict;
-
-no if $] >= 5.018, warnings => 'experimental::smartmatch';
+use warnings;
=head1 NAME
@@ -11,11 +10,11 @@ WWW::YoutubeViewer::Itags - Get the YouTube itags.
=head1 VERSION
-Version 0.02
+Version 0.03
=cut
-our $VERSION = '0.02';
+our $VERSION = '0.03';
=head1 SYNOPSIS
@@ -47,16 +46,18 @@ Get a HASH ref with the YouTube itags. {resolution => {type => itag}}.
sub get_itags {
return scalar {
- 'original' => [38],
- '1080' => [37, 46], # 137 -- no audio
- '720' => [22, 45], # 136 -- no audio
- '480' => [35, 44], # 135 -- no audio
- '360' => [34, 18, 43], # 134 -- no audio
- '240' => [5], # 133 -- no audio
- '180' => [36],
- '144' => [17], # 160 -- no audio
- 'audio' => [139, 140, 141, 171, 172],
- };
+
+ # WebM formats first
+ 'original' => [38],
+ '1080' => [46, 37], # 137 -- no audio
+ '720' => [45, 22], # 136 -- no audio
+ '480' => [44, 35], # 135 -- no audio
+ '360' => [43, 34, 18], # 134 -- no audio
+ '240' => [5], # 133 -- no audio
+ '180' => [36],
+ '144' => [17], # 160 -- no audio
+ 'audio' => [139, 140, 141, 171, 172],
+ };
}
=head2 get_resolutions()
@@ -77,14 +78,14 @@ sub get_resolutions {
};
}
-=head2 find_streaming_url($urls_ref, $prefer_webm, $resolution)
+=head2 find_streaming_url($urls_ref, $resolution)
-Return the streaming URL based on $resolution and $prefer_webm.
+Return the streaming URL which corresponds with the $resolution.
=cut
sub find_streaming_url {
- my ($self, $urls_ref, $prefer_webm, $resolution) = @_;
+ my ($self, $urls_ref, $resolution) = @_;
state $itags = $self->get_itags();
state $resolutions = $self->get_resolutions($itags);
@@ -95,39 +96,32 @@ sub find_streaming_url {
my $wanted_itag = defined $resolution ? $itags->{$resolution} : undef;
- my $streaming;
- foreach my $url_ref (
- $prefer_webm
- ? ((grep { exists($_->{type}) && $_->{type} =~ m{video/webm} } @{$urls_ref}), @{$urls_ref})
- : (@{$urls_ref})
- ) {
-
- if (exists $url_ref->{itag} && exists $url_ref->{url}) {
+ my %stream;
+ foreach my $info_ref (@{$urls_ref}) {
+ if (exists $info_ref->{itag} and exists $info_ref->{url}) {
+ $stream{$info_ref->{itag}} = $info_ref;
+ }
+ }
- if (defined $wanted_itag) {
- $url_ref->{itag} ~~ $wanted_itag or next;
+ my $streaming;
+ if (defined $wanted_itag) {
+ foreach my $itag (@{$wanted_itag}) {
+ if (exists $stream{$itag}) {
+ $streaming = $stream{$itag};
+ last;
}
-
- next unless exists $resolutions->{$url_ref->{itag}};
- $streaming = $url_ref;
- last;
}
}
if (not defined $streaming) {
-
foreach my $res (qw(original 1080 720 480 360 240 180 144 audio)) {
- foreach my $url (@{$urls_ref}) {
- if (exists $url->{itag} and exists $url->{url}) {
-
- if ($url->{itag} ~~ $itags->{$res}) {
- $streaming = $url;
- last;
- }
-
+ foreach my $itag (@{$itags->{$res}}) {
+ if (exists $stream{$itag}) {
+ $streaming = $stream{$itag};
+ last;
}
}
- last if defined($streaming);
+ last if defined $streaming;
}
}
View
BIN  WWW-YoutubeViewer/share/gtk-youtube-viewer-icons/donate.png
Deleted file not rendered
View
219 WWW-YoutubeViewer/share/gtk-youtube-viewer.glade
@@ -2,55 +2,6 @@
<interface>
<requires lib="gtk+" version="2.18"/>
<!-- interface-naming-policy project-wide -->
- <object class="GtkAboutDialog" id="aboutdialog1">
- <property name="can_focus">False</property>
- <property name="border_width">5</property>
- <property name="window_position">center-on-parent</property>
- <property name="type_hint">normal</property>
- <property name="transient_for">__MAIN__</property>
- <property name="program_name">Glade</property>
- <property name="copyright" translatable="yes">Copyright © 2010-2013 by Trizen</property>
- <property name="comments" translatable="yes">Written in Perl, Gtk2 and Glade under the GPLv3.</property>
- <property name="website">http://trizen.googlecode.com</property>
- <property name="website_label" translatable="yes">Developer's website</property>
- <property name="authors">[+] Developer/Maintainer:
- =&gt; Trizen (trizenx@gmail.com)
- * Core
- * GUI
-
-[+] Contributor:
- =&gt; Ovidiu D. Nițan (nitanovidiu@gmail.com)
- * Threads
- * GUI fixes</property>
- <signal name="destroy" handler="hide_about_window" swapped="no"/>
- <signal name="delete-event" handler="hide_about_window" swapped="no"/>
- <signal name="response" handler="hide_about_window" swapped="no"/>
- <child internal-child="vbox">
- <object class="GtkVBox" id="dialog-vbox3">
- <property name="can_focus">False</property>
- <child internal-child="action_area">
- <object class="GtkHButtonBox" id="dialog-action_area3">
- <property name="can_focus">False</property>
- </object>
- <packing>
- <property name="expand">False</property>
- <property name="fill">True</property>
- <property name="pack_type">end</property>
- <property name="position">0</property>
- </packing>
- </child>
- <child>
- <placeholder/>
- </child>
- </object>
- </child>
- </object>
- <object class="GtkAdjustment" id="adjustment1">
- <property name="lower">1</property>
- <property name="upper">50</property>
- <property name="step_increment">1</property>
- <property name="page_increment">10</property>
- </object>
<object class="GtkAdjustment" id="adjustment2">
<property name="lower">1</property>
<property name="upper">4096</property>
@@ -76,7 +27,6 @@
<property name="can_focus">False</property>
<child>
<object class="GtkMenuItem" id="file">
- <property name="use_action_appearance">False</property>
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Menu</property>
@@ -87,7 +37,6 @@
<child>
<object class="GtkImageMenuItem" id="username_list">
<property name="label" translatable="yes">Users (CTRL+U)</property>
- <property name="use_action_appearance">False</property>
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="tooltip_text" translatable="yes">Youtube usernames list</property>
@@ -98,7 +47,6 @@
<child>
<object class="GtkImageMenuItem" id="cli_version">
<property name="label" translatable="yes">Youtube Viewer</property>
- <property name="use_action_appearance">False</property>
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="tooltip_text" translatable="yes">Search and play videos in command line interface (CTRL+Y)</property>
@@ -110,7 +58,6 @@
<child>
<object class="GtkImageMenuItem" id="menuitem3">
<property name="label" translatable="yes">Login to YouTube</property>
- <property name="use_action_appearance">False</property>
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="tooltip_text" translatable="yes">Login to Youtube using email and password. (CTRL+L)</property>
@@ -122,7 +69,6 @@
<child>
<object class="GtkImageMenuItem" id="warnings_console">
<property name="label" translatable="yes">Warnings console</property>
- <property name="use_action_appearance">False</property>
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="tooltip_text" translatable="yes">Show the warnings window</property>
@@ -134,7 +80,6 @@
<child>
<object class="GtkImageMenuItem" id="options">
<property name="label">gtk-preferences</property>
- <property name="use_action_appearance">False</property>
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="tooltip_text" translatable="yes">Adjust application settings. (CTRL+P)</property>
@@ -145,7 +90,6 @@
</child>
<child>
<object class="GtkSeparatorMenuItem" id="menuitem6">
- <property name="use_action_appearance">False</property>
<property name="visible">True</property>
<property name="can_focus">False</property>
</object>
@@ -153,7 +97,6 @@
<child>
<object class="GtkImageMenuItem" id="exit">
<property name="label">gtk-quit</property>
- <property name="use_action_appearance">False</property>
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="tooltip_text" translatable="yes">Quit the application. (CTRL+Q)</property>
@@ -168,7 +111,6 @@
</child>
<child>
<object class="GtkMenuItem" id="menuitem4">
- <property name="use_action_appearance">False</property>
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Help</property>
@@ -179,7 +121,6 @@
<child>
<object class="GtkImageMenuItem" id="help">
<property name="label">gtk-help</property>
- <property name="use_action_appearance">False</property>
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="tooltip_text" translatable="yes">Show a help window. (CTRL+H)</property>
@@ -189,23 +130,21 @@
</object>
</child>
<child>
- <object class="GtkImageMenuItem" id="about1">
- <property name="label">gtk-about</property>
- <property name="use_action_appearance">False</property>
+ <object class="GtkMenuItem" id="donate_menu_item">
<property name="visible">True</property>
<property name="can_focus">False</property>
- <property name="use_underline">True</property>
- <property name="use_stock">True</property>
- <signal name="activate" handler="show_about_window" swapped="no"/>
+ <property name="label" translatable="yes">Donate</property>
+ <signal name="activate" handler="donate" swapped="no"/>
</object>
</child>
<child>
- <object class="GtkMenuItem" id="donate_menu_item">
- <property name="use_action_appearance">False</property>
+ <object class="GtkImageMenuItem" id="about1">
+ <property name="label">gtk-about</property>
<property name="visible">True</property>
<property name="can_focus">False</property>
- <property name="label" translatable="yes">Donate</property>
- <signal name="activate" handler="donate" swapped="no"/>
+ <property name="use_underline">True</property>
+ <property name="use_stock">True</property>
+ <signal name="activate" handler="show_about_window" swapped="no"/>
</object>
</child>
</object>
@@ -431,7 +370,6 @@ default = standard results</property>
<child>
<object class="GtkButton" id="button6">
<property name="label">Subscriptions</property>
- <property name="use_action_appearance">False</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
@@ -447,7 +385,6 @@ default = standard results</property>
<child>
<object class="GtkButton" id="button22">
<property name="label" translatable="yes">Favorited videos</property>
- <property name="use_action_appearance">False</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
@@ -463,7 +400,6 @@ default = standard results</property>
<child>
<object class="GtkButton" id="button9">
<property name="label" translatable="yes">Recommended</property>
- <property name="use_action_appearance">False</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
@@ -479,7 +415,6 @@ default = standard results</property>
<child>
<object class="GtkButton" id="button25">
<property name="label" translatable="yes">Watch History</property>
- <property name="use_action_appearance">False</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
@@ -495,7 +430,6 @@ default = standard results</property>
<child>
<object class="GtkButton" id="channels_button">
<property name="label" translatable="yes">Channels</property>
- <property name="use_action_appearance">False</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
@@ -511,7 +445,6 @@ default = standard results</property>
<child>
<object class="GtkButton" id="button7">
<property name="label" translatable="yes">Log out</property>
- <property name="use_action_appearance">False</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
@@ -1076,7 +1009,6 @@ Unless the categoryID is valid, this field is ignored.</property>
<child>
<object class="GtkCheckButton" id="thumbs_checkbutton">
<property name="label" translatable="yes">Show thumbnails</property>
- <property name="use_action_appearance">False</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
@@ -1092,7 +1024,6 @@ Unless the categoryID is valid, this field is ignored.</property>
<child>
<object class="GtkCheckButton" id="fullscreen_checkbutton">
<property name="label" translatable="yes">Fullscreen mode</property>
- <property name="use_action_appearance">False</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
@@ -1149,7 +1080,6 @@ Unless the categoryID is valid, this field is ignored.</property>
<child>
<object class="GtkButton" id="button8">
<property name="label">gtk-find</property>
- <property name="use_action_appearance">False</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
@@ -1171,39 +1101,6 @@ Unless the categoryID is valid, this field is ignored.</property>
</packing>
</child>
<child>
- <object class="GtkHButtonBox" id="hbuttonbox8">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="layout_style">end</property>
- <child>
- <placeholder/>
- </child>
- <child>
- <object class="GtkButton" id="donate_button">
- <property name="use_action_appearance">False</property>
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="receives_default">True</property>
- <property name="image">image78</property>
- <property name="relief">none</property>
- <property name="image_position">right</property>
- <signal name="clicked" handler="donate" swapped="no"/>
- </object>
- <packing>
- <property name="expand">False</property>
- <property name="fill">False</property>
- <property name="position">1</property>
- </packing>
- </child>
- </object>
- <packing>
- <property name="expand">False</property>
- <property name="fill">False</property>
- <property name="pack_type">end</property>
- <property name="position">8</property>
- </packing>
- </child>
- <child>
<object class="GtkFrame" id="frame10">
<property name="visible">True</property>
<property name="can_focus">False</property>
@@ -1246,7 +1143,7 @@ When the specified resolution is not found, it falls down to a lower resolution.
<property name="expand">False</property>
<property name="fill">False</property>
<property name="pack_type">end</property>
- <property name="position">9</property>
+ <property name="position">8</property>
</packing>
</child>
</object>
@@ -1738,6 +1635,55 @@ When the specified resolution is not found, it falls down to a lower resolution.
</object>
</child>
</object>
+ <object class="GtkAboutDialog" id="aboutdialog1">
+ <property name="can_focus">False</property>
+ <property name="border_width">5</property>
+ <property name="window_position">center-on-parent</property>
+ <property name="type_hint">normal</property>
+ <property name="transient_for">__MAIN__</property>
+ <property name="program_name">Glade</property>
+ <property name="copyright" translatable="yes">Copyright © 2010-2013 by Trizen</property>
+ <property name="comments" translatable="yes">Written in Perl, Gtk2 and Glade under the GPLv3.</property>
+ <property name="website">http://trizen.googlecode.com</property>
+ <property name="website_label" translatable="yes">Developer's website</property>
+ <property name="authors">[+] Developer/Maintainer:
+ =&gt; Trizen (trizenx@gmail.com)
+ * Core
+ * GUI
+
+[+] Contributor:
+ =&gt; Ovidiu D. Nițan (nitanovidiu@gmail.com)
+ * Threads
+ * GUI fixes</property>
+ <signal name="destroy" handler="hide_about_window" swapped="no"/>
+ <signal name="delete-event" handler="hide_about_window" swapped="no"/>
+ <signal name="response" handler="hide_about_window" swapped="no"/>
+ <child internal-child="vbox">
+ <object class="GtkVBox" id="dialog-vbox3">
+ <property name="can_focus">False</property>
+ <child internal-child="action_area">
+ <object class="GtkHButtonBox" id="dialog-action_area3">
+ <property name="can_focus">False</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="pack_type">end</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ </object>
+ </child>
+ </object>
+ <object class="GtkAdjustment" id="adjustment1">
+ <property name="lower">1</property>
+ <property name="upper">50</property>
+ <property name="step_increment">1</property>
+ <property name="page_increment">10</property>
+ </object>
<object class="GtkWindow" id="details_window">
<property name="can_focus">False</property>
<property name="border_width">2</property>
@@ -1952,7 +1898,6 @@ When the specified resolution is not found, it falls down to a lower resolution.
<property name="layout_style">center</property>
<child>
<object class="GtkLinkButton" id="linkbutton1">
- <property name="use_action_appearance">False</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
@@ -1988,7 +1933,6 @@ When the specified resolution is not found, it falls down to a lower resolution.
<child>
<object class="GtkButton" id="play">
<property name="label">gtk-media-play</property>
- <property name="use_action_appearance">False</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="has_focus">True</property>
@@ -2005,7 +1949,6 @@ When the specified resolution is not found, it falls down to a lower resolution.
<child>
<object class="GtkButton" id="download">
<property name="label">Download</property>
- <property name="use_action_appearance">False</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
@@ -2021,7 +1964,6 @@ When the specified resolution is not found, it falls down to a lower resolution.
<child>
<object class="GtkButton" id="close">
<property name="label">gtk-close</property>
- <property name="use_action_appearance">False</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
@@ -2050,7 +1992,6 @@ When the specified resolution is not found, it falls down to a lower resolution.
<child>
<object class="GtkImageMenuItem" id="details">
<property name="label" translatable="yes">Show video details</property>
- <property name="use_action_appearance">False</property>
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="tooltip_text" translatable="yes">(CTRL+D)</property>
@@ -2062,7 +2003,6 @@ When the specified resolution is not found, it falls down to a lower resolution.
<child>
<object class="GtkImageMenuItem" id="menuitem9">
<property name="label" translatable="yes">Comments / Ratings</property>
- <property name="use_action_appearance">False</property>
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="image">image30</property>
@@ -2079,7 +2019,6 @@ When the specified resolution is not found, it falls down to a lower resolution.
<child>
<object class="GtkImageMenuItem" id="queue_playback">
<property name="label" translatable="yes">Add to playback queue</property>
- <property name="use_action_appearance">False</property>
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="image">image9</property>
@@ -2089,8 +2028,7 @@ When the specified resolution is not found, it falls down to a lower resolution.
</child>
<child>
<object class="GtkImageMenuItem" id="menuitem1">
- <property name="label" translatable="yes">Play videos from queue</property>
- <property name="use_action_appearance">False</property>
+ <property name="label" translatable="yes">Play the enqued videos</property>
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="image">image10</property>
@@ -2100,8 +2038,7 @@ When the specified resolution is not found, it falls down to a lower resolution.
</child>
<child>
<object class="GtkImageMenuItem" id="play_all_videos">
- <property name="label" translatable="yes">Play all video results</property>
- <property name="use_action_appearance">False</property>
+ <property name="label" translatable="yes">Play all the video results</property>
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="image">image16</property>
@@ -2117,8 +2054,7 @@ When the specified resolution is not found, it falls down to a lower resolution.
</child>
<child>
<object class="GtkImageMenuItem" id="play_in_new_term">
- <property name="label" translatable="yes">Play it in a new terminal</property>
- <property name="use_action_appearance">False</property>
+ <property name="label" translatable="yes">Play this video in a terminal</property>
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="image">image5</property>
@@ -2128,8 +2064,7 @@ When the specified resolution is not found, it falls down to a lower resolution.
</child>
<child>
<object class="GtkImageMenuItem" id="download_video">
- <property name="label" translatable="yes">Download Youtube video</property>
- <property name="use_action_appearance">False</property>
+ <property name="label" translatable="yes">Download the selected video</property>
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="image">image15</property>
@@ -2139,8 +2074,7 @@ When the specified resolution is not found, it falls down to a lower resolution.
</child>
<child>
<object class="GtkImageMenuItem" id="open_youtube">
- <property name="label" translatable="yes">Open the YouTube website</property>
- <property name="use_action_appearance">False</property>
+ <property name="label" translatable="yes">Open the YouTube video page</property>
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="image">image7</property>
@@ -2232,7 +2166,6 @@ When the specified resolution is not found, it falls down to a lower resolution.
<child>
<object class="GtkButton" id="button3">
<property name="label">gtk-ok</property>
- <property name="use_action_appearance">False</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="has_focus">True</property>
@@ -2356,7 +2289,6 @@ When the specified resolution is not found, it falls down to a lower resolution.
<child type="label">
<object class="GtkButton" id="button18">
<property name="label">gtk-refresh</property>
- <property name="use_action_appearance">False</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
@@ -2431,7 +2363,6 @@ When the specified resolution is not found, it falls down to a lower resolution.
<child>
<object class="GtkButton" id="button17">
<property name="label">Send</property>
- <property name="use_action_appearance">False</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
@@ -2498,7 +2429,6 @@ When the specified resolution is not found, it falls down to a lower resolution.
<child>
<object class="GtkButton" id="button10">
<property name="label" translatable="yes">Like</property>
- <property name="use_action_appearance">False</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
@@ -2514,7 +2444,6 @@ When the specified resolution is not found, it falls down to a lower resolution.
<child>
<object class="GtkButton" id="button11">
<property name="label" translatable="yes">Dislike</property>
- <property name="use_action_appearance">False</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
@@ -2570,7 +2499,6 @@ When the specified resolution is not found, it falls down to a lower resolution.
<child>
<object class="GtkButton" id="button24">
<property name="label" translatable="yes">Add video to favorites</property>
- <property name="use_action_appearance">False</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
@@ -2586,7 +2514,6 @@ When the specified resolution is not found, it falls down to a lower resolution.
<child>
<object class="GtkButton" id="button23">
<property name="label" translatable="yes">Subscribe user's channel</property>
- <property name="use_action_appearance">False</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
@@ -2613,7 +2540,6 @@ When the specified resolution is not found, it falls down to a lower resolution.
<child>
<object class="GtkButton" id="button20">
<property name="label" translatable="yes">List videos from this user</property>
- <property name="use_action_appearance">False</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
@@ -2629,7 +2555,6 @@ When the specified resolution is not found, it falls down to a lower resolution.
<child>
<object class="GtkButton" id="button13">
<property name="label" translatable="yes">List user's favorited videos</property>
- <property name="use_action_appearance">False</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
@@ -2656,7 +2581,6 @@ When the specified resolution is not found, it falls down to a lower resolution.
<child>
<object class="GtkButton" id="button15">
<property name="label" translatable="yes">Show related videos</property>
- <property name="use_action_appearance">False</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
@@ -2672,7 +2596,6 @@ When the specified resolution is not found, it falls down to a lower resolution.
<child>
<object class="GtkButton" id="button12">
<property name="label" translatable="yes">List the user's playlists</property>
- <property name="use_action_appearance">False</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
@@ -2721,7 +2644,6 @@ When the specified resolution is not found, it falls down to a lower resolution.
<child>
<object class="GtkButton" id="button16">
<property name="label">gtk-close</property>
- <property name="use_action_appearance">False</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="has_focus">True</property>
@@ -2809,7 +2731,6 @@ When the specified resolution is not found, it falls down to a lower resolution.
<child>
<object class="GtkButton" id="button19">
<property name="label">gtk-about</property>
- <property name="use_action_appearance">False</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>