diff --git a/MANIFEST b/MANIFEST index 7051c406..2dcaf3ea 100644 --- a/MANIFEST +++ b/MANIFEST @@ -6,6 +6,7 @@ lib/WWW/YoutubeViewer.pm lib/WWW/YoutubeViewer/Activities.pm lib/WWW/YoutubeViewer/Authentication.pm lib/WWW/YoutubeViewer/Channels.pm +lib/WWW/YoutubeViewer/CommentThreads.pm lib/WWW/YoutubeViewer/GetCaption.pm lib/WWW/YoutubeViewer/GuideCategories.pm lib/WWW/YoutubeViewer/Itags.pm diff --git a/META.json b/META.json index f4ff00e3..b98ffefd 100644 --- a/META.json +++ b/META.json @@ -57,7 +57,7 @@ "provides" : { "WWW::YoutubeViewer" : { "file" : "lib/WWW/YoutubeViewer.pm", - "version" : "0.05" + "version" : "0.06" }, "WWW::YoutubeViewer::Activities" : { "file" : "lib/WWW/YoutubeViewer/Activities.pm", @@ -71,6 +71,10 @@ "file" : "lib/WWW/YoutubeViewer/Channels.pm", "version" : "0.01" }, + "WWW::YoutubeViewer::CommentThreads" : { + "file" : "lib/WWW/YoutubeViewer/CommentThreads.pm", + "version" : "0.01" + }, "WWW::YoutubeViewer::GetCaption" : { "file" : "lib/WWW/YoutubeViewer/GetCaption.pm", "version" : "0.02" @@ -130,6 +134,6 @@ "http://dev.perl.org/licenses/" ] }, - "version" : "0.05", + "version" : "0.06", "x_serialization_backend" : "JSON::PP version 2.27300" } diff --git a/META.yml b/META.yml index 91d8f76b..9df175da 100644 --- a/META.yml +++ b/META.yml @@ -16,7 +16,7 @@ name: WWW-YoutubeViewer provides: WWW::YoutubeViewer: file: lib/WWW/YoutubeViewer.pm - version: '0.05' + version: '0.06' WWW::YoutubeViewer::Activities: file: lib/WWW/YoutubeViewer/Activities.pm version: '0.01' @@ -26,6 +26,9 @@ provides: WWW::YoutubeViewer::Channels: file: lib/WWW/YoutubeViewer/Channels.pm version: '0.01' + WWW::YoutubeViewer::CommentThreads: + file: lib/WWW/YoutubeViewer/CommentThreads.pm + version: '0.01' WWW::YoutubeViewer::GetCaption: file: lib/WWW/YoutubeViewer/GetCaption.pm version: '0.02' @@ -92,5 +95,5 @@ requires: URI::Escape: '0' resources: license: http://dev.perl.org/licenses/ -version: '0.05' +version: '0.06' x_serialization_backend: 'CPAN::Meta::YAML version 0.016' diff --git a/bin/gtk-youtube-viewer b/bin/gtk-youtube-viewer index 0cf3969c..d0f0fd63 100755 --- a/bin/gtk-youtube-viewer +++ b/bin/gtk-youtube-viewer @@ -18,7 +18,7 @@ #------------------------------------------------------- # GTK Youtube Viewer # Created on: 12 September 2010 -# Latest edit on: 05 August 2015 +# Latest edit on: 01 October 2015 # Website: http://github.com/trizen/youtube-viewer #------------------------------------------------------- @@ -129,11 +129,12 @@ my %symbols = ( my %CONFIG = ( # Combobox values - active_resolution_combobox => 0, - active_safeSearch_combobox => 1, - active_more_options_expander => 0, - active_panel_account_combobox => 0, - active_channel_type_combobox => 0, + active_resolution_combobox => 0, + active_safeSearch_combobox => 1, + active_more_options_expander => 0, + active_panel_account_combobox => 0, + active_channel_type_combobox => 0, + active_subscriptions_order_combobox => 0, video_players => { vlc => { @@ -290,6 +291,7 @@ my %objects = ( 'comboboxtext4' => \my $definition_combobox, 'comboboxtext5' => \my $safesearch_combobox, 'comboboxtext1' => \my $published_within_combobox, + 'comboboxtext13' => \my $subscriptions_order_combobox, 'panel_user_entry' => \my $panel_user_entry, 'comboboxtext6' => \my $panel_account_type_combobox, 'comboboxtext2' => \my $order_combobox, @@ -671,6 +673,7 @@ sub apply_configuration { $clear_search_list_checkbox->set_active($CONFIG{clear_search_list}); $panel_account_type_combobox->set_active($CONFIG{active_panel_account_combobox}); $channel_type_combobox->set_active($CONFIG{active_channel_type_combobox}); + $subscriptions_order_combobox->set_active($CONFIG{active_subscriptions_order_combobox}); $published_within_combobox->set_active(0); @@ -1130,7 +1133,7 @@ sub set_comments { return unless $videoID =~ /$valid_video_id_re/; $feeds_liststore->clear; - print_comments($yv_obj->get_video_comments($videoID)); + display_comments($yv_obj->comments_from_video_id($videoID)); } # Feeds window @@ -1142,8 +1145,7 @@ sub show_feeds_window { $feeds_window->show; $feeds_statusbar->pop(0); - ## NEEDS WORK!!! - #print_comments($yv_obj->get_video_comments($videoID)); + display_comments($yv_obj->comments_from_video_id($videoID)); return 1; } @@ -1220,6 +1222,11 @@ sub combobox_caption_changed { $yv_obj->set_videoCaption($text); } +sub combobox_subscriptions_order_changed { + $CONFIG{active_subscriptions_order_combobox} = $subscriptions_order_combobox->get_active; + $yv_obj->set_subscriptions_order($subscriptions_order_combobox->get_active_text); +} + sub combobox_panel_account_changed { my $text = $panel_account_type_combobox->get_active_text; $CONFIG{active_panel_account_combobox} = $panel_account_type_combobox->get_active; @@ -2351,7 +2358,7 @@ sub comments_row_activated { $feeds_liststore->remove($iter); my $results = $yv_obj->next_page($value, comments => 1); if ($yv_utils->has_entries($results)) { - print_comments($results); + display_comments($results); } else { die "This is the last page of comments.\n"; @@ -2395,12 +2402,11 @@ sub favorite_video { } sub subscribe_channel { - my $user = get_channel_id_for_selected_video(); - $feeds_statusbar->push( - 0, $yv_obj->subscribe_channel($user) - ? "Successfully subscribed to channel: $user." - : 'Error!' - ); + my $channel_id = get_channel_id_for_selected_video(); + $feeds_statusbar->push(0, + $yv_obj->subscribe_channel($channel_id) + ? "Successfully subscribed to channel: $channel_id." + : 'Error!'); } sub like_selected_video { @@ -2426,34 +2432,41 @@ sub send_comment_to_video { my $comment = get_text($gui->get_object('comment_textview')); $feeds_statusbar->push(0, - length($comment) && $yv_obj->send_comment_to_video($videoID, $comment) + length($comment) && $yv_obj->comment_to_video_id($comment, $videoID) ? 'Video comment has been posted!' : 'Error!'); } -sub print_comments { - my ($results, %options) = @_; +sub display_comments { + my ($results) = @_; my $url = $results->{url}; - my $comments = $results->{results}; + my $res = $results->{results} // {}; + my $comments = $res->{items} // []; - my $i = 0; foreach my $comment (@{$comments}) { + my $snippet = (($comment->{snippet} // next)->{topLevelComment} // next)->{snippet}; my $iter = $feeds_liststore->append; $feeds_liststore->set( $iter, 0, - "$comment->{name} (" - . $yv_utils->format_date($comment->{published}) + "" + . encode_entities($snippet->{authorDisplayName}) + . " (" + . $yv_utils->format_date($snippet->{publishedAt}) . ") said:\n\t" - . encode_entities($comment->{content}) + . encode_entities($snippet->{textDisplay} // 'Empty comment...') ); } - my $iter = $feeds_liststore->append; - $feeds_liststore->set($iter, 0, "\n=>> NEXT PAGE\n"); - $feeds_liststore->set($iter, 1, $url); + # + ## This needs work!!! + # + #my $iter = $feeds_liststore->append; + #$feeds_liststore->set($iter, 0, "\n=>> NEXT PAGE\n"); + #$feeds_liststore->set($iter, 1, $url); + return 1; } diff --git a/bin/youtube-viewer b/bin/youtube-viewer index 0081925a..fc808ee6 100755 --- a/bin/youtube-viewer +++ b/bin/youtube-viewer @@ -18,7 +18,7 @@ #------------------------------------------------------- # Appname: youtube-viewer # Created on: 02 June 2010 -# Latest edit on: 06 August 2015 +# Latest edit on: 01 October 2015 # Website: https://github.com/trizen/youtube-viewer #------------------------------------------------------- # @@ -247,6 +247,8 @@ my %CONFIG = ( publishedAfter => undef, order => undef, + subscriptions_order => 'relevance', + hl => 'en_US', cats_region => 'us', @@ -643,11 +645,14 @@ usage: $execname [options] ([url] | [keywords]) -R --recommended : show the recommended videos for you * -S --subscriptions:s : show the subscribed channels * -SV --subs-videos:s : show the subscription videos * + --subs-order=s : change the subscription order + valid values: alphabetical, relevance, unread -L --likes : show the videos that you liked on YouTube * --dislikes : show the videos that you disliked on YouTube * * [POST] Personal --subscribe=s : subscribe to a channel * + --user-subscribe=s : subscribe to a channel via username * --favorite=s : favorite a YouTube video by URL or ID * --like=s : send a 'like' rating to a video URL or ID * --dislike=s : send a 'dislike' rating to a video URL or ID * @@ -1024,8 +1029,8 @@ sub apply_configuration { videoEmbeddable videoLicense videoSyndicated channelId publishedAfter publishedBefore - safeSearch regionCode - debug http_proxy hl page + safeSearch regionCode debug hl + http_proxy page subscriptions_order ) ) { @@ -1096,6 +1101,10 @@ sub apply_configuration { subscribe_to_channels(split(/[,\s]+/, delete $opt->{subscribe_channel})); } + if (defined $opt->{subscribe_username}) { + subscribe_to_usernames(split(/[,\s]+/, delete $opt->{subscribe_username})); + } + if (defined $opt->{favorite_video}) { favorite_videos(split(/[,\s]+/, delete $opt->{favorite_video})); } @@ -1317,11 +1326,13 @@ sub parse_arguments { 'subscriptions|S:s' => \$opt{subscriptions}, 'subs-videos|SV:s' => \$opt{subscription_videos}, + 'subs-order=s' => \$opt{subscriptions_order}, 'favorites|fv|favorited-videos|F:s' => \$opt{favorites}, 'recommended|recommendations|R:s' => \$opt{recommendations}, 'likes|L:s' => \$opt{likes}, 'dislikes' => \$opt{dislikes}, 'subscribe=s' => \$opt{subscribe_channel}, + 'user-subscribe=s' => \$opt{subscribe_username}, 'favorite|favorite-video|fav=s' => \$opt{favorite_video}, 'channel-suggestions' => \$opt{channel_suggestions}, 'cv|channel|channel-videos=s' => \$opt{channel_id_videos}, @@ -1867,7 +1878,7 @@ sub get_and_print_related_videos { sub get_and_print_comments { foreach my $id (@_) { my $videoID = get_valid_video_id($id) // next; - my $comments = $yv_obj->get_video_comments($videoID); + my $comments = $yv_obj->comments_from_video_id($videoID); print_comments($comments, $videoID); } return 1; @@ -1976,12 +1987,14 @@ sub get_and_print_videos_from_playlist { return 1; } -sub subscribe_to_channels { +sub subscribe_to { + my ($is_channel, @ids) = @_; + return if not authenticated(); - foreach my $channel (@_) { + foreach my $channel (@ids) { if ($channel =~ /$valid_username_re/) { - if ($yv_obj->subscribe_channel($channel)) { + if ($is_channel ? $yv_obj->subscribe_channel($channel) : $yv_obj->subscribe_channel_from_username($channel)) { print "** Successfully subscribed to channel: $channel\n"; } else { @@ -1992,6 +2005,14 @@ sub subscribe_to_channels { return 1; } +sub subscribe_to_channels { + subscribe_to(1, @_); +} + +sub subscribe_to_usernames { + subscribe_to(0, @_); +} + sub _bold_color { my ($text) = @_; return colored($text, 'bold'); @@ -2538,25 +2559,26 @@ sub print_shows { sub print_comments { my ($results, $videoID) = @_; - ...; # NEEDS WORK!!! - - if (not @{$results->{results}}) { - warn colored("\n[!] No comments found...", 'bold red') . "\n"; + if (not $yv_utils->has_entries($results)) { + warn_no_results("comments"); } my $url = $results->{url}; - my $comments = $results->{results}; + my $res = $results->{results} // {}; + my $comments = $res->{items} // []; my $i = 0; foreach my $comment (@{$comments}) { + my $snippet = (($comment->{snippet} // next)->{topLevelComment} // next)->{snippet}; + printf( "\n%s on %s said:\n%s\n", - colored($comment->{name}, 'bold'), - $yv_utils->format_date($comment->{published}), + colored($snippet->{authorDisplayName}, 'bold'), + $yv_utils->format_date($snippet->{publishedAt}), wrap_text( i_tab => q{ } x 4, s_tab => q{ } x 4, - text => [$comment->{content} // 'Empty comment...'] + text => [$snippet->{textDisplay} // 'Empty comment...'] ), ); } @@ -2593,7 +2615,7 @@ sub print_comments { my $comment = do { local (@ARGV, $/) = $filename; <> }; $comment =~ s/[^\s[:^cntrl:]]+//g; # remove control characters - if (length($comment) and $yv_obj->send_comment_to_video($videoID, $comment)) { + if (length($comment) and $yv_obj->comment_to_video_id($comment, $videoID)) { print "\n** Comment posted!\n"; } else { diff --git a/lib/WWW/YoutubeViewer.pm b/lib/WWW/YoutubeViewer.pm index c76fab99..5f8945e7 100755 --- a/lib/WWW/YoutubeViewer.pm +++ b/lib/WWW/YoutubeViewer.pm @@ -14,6 +14,7 @@ use parent qw( WWW::YoutubeViewer::ParseJSON WWW::YoutubeViewer::Subscriptions WWW::YoutubeViewer::PlaylistItems + WWW::YoutubeViewer::CommentThreads WWW::YoutubeViewer::Authentication WWW::YoutubeViewer::VideoCategories ); @@ -24,11 +25,11 @@ WWW::YoutubeViewer - A very easy interface to YouTube. =head1 VERSION -Version 0.05 +Version 0.06 =cut -our $VERSION = '0.05'; +our $VERSION = '0.06'; =head1 SYNOPSIS @@ -73,6 +74,8 @@ my %valid_options = ( safeSearch => {valid => [qw(none moderate strict)], default => undef}, videoType => {valid => [qw(any episode movie)], default => undef}, + subscriptions_order => {valid => [qw(alphabetical relevance unread)], default => undef}, + # Others debug => {valid => [0 .. 2], default => 0}, lwp_timeout => {valid => [qr/^\d+\z/], default => 1}, @@ -301,11 +304,11 @@ Get and return the content for $url. =cut sub lwp_get { - my ($self, $url) = @_; + my ($self, $url, $simple) = @_; $self->{lwp} // $self->set_lwp_useragent(); - my %lwp_header = $self->_get_lwp_header(); + my %lwp_header = ($simple ? () : $self->_get_lwp_header); my $response = $self->{lwp}->get($url, %lwp_header); if ($response->is_success) { @@ -402,12 +405,12 @@ sub lwp_mirror { } sub _get_results { - my ($self, $url) = @_; + my ($self, $url, $simple) = @_; return scalar { url => $url, - results => $self->parse_json_string($self->lwp_get($url)), + results => $self->parse_json_string($self->lwp_get($url, $simple)), }; } @@ -431,7 +434,7 @@ sub _append_url_args { sub _simple_feeds_url { my ($self, $suburl, %args) = @_; - $self->get_feeds_url() . $suburl . '?' . $self->list_to_url_arguments(%args, key => $self->get_key); + $self->get_feeds_url() . $suburl . '?' . $self->list_to_url_arguments(key => $self->get_key, %args); } =head2 default_arguments(%args) @@ -644,7 +647,7 @@ sub _request { my $res = $self->{lwp}->request($req); if ($res->is_success) { - return $res->content(); + return $res->decoded_content; } else { warn 'Request error: ' . $res->status_line(); @@ -683,30 +686,6 @@ sub post_as_json { $self->_save('POST', $url, $json_str); } -=head2 send_comment_to_video($videoID, $comment) - -Send comment to a video. Returns true on success. - -=cut - -sub send_comment_to_video { - my ($self, $code, $comment) = @_; - - ... # NEEDS WORK!!! -} - -=head2 get_video_comments($videoID) - -Returns a list of comments for a videoID. - -=cut - -sub get_video_comments { - my ($self, $video_id) = @_; - - ... # NEEDS WORK!!! -} - # SOUBROUTINE FACTORY { no strict 'refs'; diff --git a/lib/WWW/YoutubeViewer/Channels.pm b/lib/WWW/YoutubeViewer/Channels.pm index 63a7a77c..0162d238 100755 --- a/lib/WWW/YoutubeViewer/Channels.pm +++ b/lib/WWW/YoutubeViewer/Channels.pm @@ -28,7 +28,7 @@ our $VERSION = '0.01'; sub _make_channels_url { my ($self, %opts) = @_; - return $self->_make_feed_url('channels', %opts,); + return $self->_make_feed_url('channels', %opts); } =head2 channels_from_categoryID($category_id) @@ -94,6 +94,17 @@ For all functions, C<$channels->{results}{items}> contains: } } +=head2 my_channel() + +Returns info about the channel of the current authenticated user. + +=cut + +sub my_channel { + my ($self) = @_; + return $self->_get_results($self->_make_channels_url(part => 'snippet', mine => 'true')); +} + =head2 channels_my_subscribers() Retrieve a list of channels that subscribed to the authenticated user's channel. diff --git a/lib/WWW/YoutubeViewer/CommentThreads.pm b/lib/WWW/YoutubeViewer/CommentThreads.pm new file mode 100755 index 00000000..e356edc4 --- /dev/null +++ b/lib/WWW/YoutubeViewer/CommentThreads.pm @@ -0,0 +1,148 @@ +package WWW::YoutubeViewer::CommentThreads; + +use utf8; +use 5.014; +use warnings; + +=head1 NAME + +WWW::YoutubeViewer::CommentThreads - Retrieve comments threads. + +=head1 VERSION + +Version 0.01 + +=cut + +our $VERSION = '0.01'; + +=head1 SYNOPSIS + + use WWW::YoutubeViewer; + my $obj = WWW::YoutubeViewer->new(%opts); + my $videos = $obj->comments_from_video_id($video_id); + +=head1 SUBROUTINES/METHODS + +=cut + +sub _make_commentThreads_url { + my ($self, %opts) = @_; + return + $self->_make_feed_url( + 'commentThreads', + pageToken => $self->page_token, + %opts + ); +} + +=head2 comments_from_videoID($videoID) + +Retrieve comments from a video ID. + +=cut + +sub comments_from_video_id { + my ($self, $video_id) = @_; + return + $self->_get_results( + $self->_make_commentThreads_url( + videoId => $video_id, + textFormat => 'plainText', + order => 'time', + part => 'snippet' + ), + 1 + ); +} + +=head2 comment_to_video_id($comment, $videoID) + +Send a comment to a video ID. + +=cut + +sub comment_to_video_id { + my ($self, $comment, $video_id) = @_; + + my $url = $self->_simple_feeds_url('commentThreads', part => 'snippet'); + + state $channel = $self->my_channel; + if (defined($channel) and defined $channel->{results}) { + ## ok + } + else { + return; + } + + my $hash = { + "snippet" => { + "topLevelComment" => { + "snippet" => { + "textOriginal" => $comment, + "channelId" => $channel->{results}{items}[0]{id} + } + }, + "videoId" => $video_id, + } + }; + + $self->post_as_json($url, $hash); +} + +=head1 AUTHOR + +Trizen, C<< >> + + +=head1 SUPPORT + +You can find documentation for this module with the perldoc command. + + perldoc WWW::YoutubeViewer::CommentThreads + + +=head1 LICENSE AND COPYRIGHT + +Copyright 2015 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 + +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::CommentThreads diff --git a/lib/WWW/YoutubeViewer/Subscriptions.pm b/lib/WWW/YoutubeViewer/Subscriptions.pm index a1a4ce95..ccd519cc 100755 --- a/lib/WWW/YoutubeViewer/Subscriptions.pm +++ b/lib/WWW/YoutubeViewer/Subscriptions.pm @@ -28,18 +28,40 @@ our $VERSION = '0.01'; sub _make_subscriptions_url { my ($self, %opts) = @_; - return $self->_make_feed_url('subscriptions', %opts,); + return $self->_make_feed_url('subscriptions', %opts); } -=head2 subscribe_channel($username) +=head2 subscribe_channel($channel_id) -Subscribe to an user's channel. +Subscribe to an YouTube channel. =cut sub subscribe_channel { - my ($self, $user) = @_; - ... # NEEDS WORK!!! + my ($self, $channel_id) = @_; + + my $resource = { + snippet => { + resourceId => { + kind => 'youtube#channel', + channelId => $channel_id, + } + } + }; + + my $url = $self->_simple_feeds_url('subscriptions', part => 'snippet'); + return $self->post_as_json($url, $resource); +} + +=head2 subscribe_channel_from_username($username) + +Subscribe to an YouTube channel via username. + +=cut + +sub subscribe_channel_from_username { + my ($self, $username) = @_; + $self->subscribe_channel($self->channel_id_from_username($username)); } =head2 subscriptions(;$channel_id) @@ -54,7 +76,7 @@ sub subscriptions { return $self->_get_results( $self->_make_subscriptions_url( - order => 'relevance', + order => $self->get_subscriptions_order, defined($channel_id) ? (channelId => $channel_id) : (mine => 'true'), @@ -81,10 +103,10 @@ Retrieve the video subscriptions for a channel ID or for the current authenticat =cut sub subscription_videos { - my ($self, $channel_id) = @_; + my ($self, $channel_id, $order) = @_; my $url = $self->_make_subscriptions_url( - order => 'relevance', + order => $self->get_subscriptions_order, maxResults => 50, part => 'snippet,contentDetails', defined($channel_id) diff --git a/share/gtk-youtube-viewer.glade b/share/gtk-youtube-viewer.glade index 11232d2f..c60bf390 100644 --- a/share/gtk-youtube-viewer.glade +++ b/share/gtk-youtube-viewer.glade @@ -914,79 +914,6 @@ True False - - - True - False - 0 - none - - - True - False - 0 - 0 - 9 - - - True - False - - - True - True - - 15 - False - False - True - True - - - True - True - 0 - - - - - True - False - 0 - - myself - username - channel ID - - - - - False - False - end - 1 - - - - - - - - - True - False - <b>Account:</b> - True - - - - - False - False - end - 0 - - True @@ -1090,11 +1017,125 @@ False - True + False 50 + 0 + + + + + True + False + 0 + none + + + True + False + 12 + + + True + False + + relevance + unread + alphabetical + + + + + + + + + True + False + <b>Subscriptions order:</b> + True + + + + + False + False + end 1 + + + True + False + 0 + none + + + True + False + 0 + 0 + 9 + + + True + False + + + True + True + + 15 + False + False + True + True + + + True + True + 0 + + + + + True + False + 0 + + myself + username + channel ID + + + + + False + False + end + 1 + + + + + + + + + True + False + <b>Account:</b> + True + + + + + False + False + end + 2 + +