Alex 'AdUser' Z
6 years ago
commit
6c812dbf45
3 changed files with 283 additions and 0 deletions
@ -0,0 +1,123 @@ |
|||||||
|
#!/usr/bin/env perl |
||||||
|
|
||||||
|
use strict; |
||||||
|
use warnings; |
||||||
|
use utf8; |
||||||
|
|
||||||
|
use Getopt::Std; |
||||||
|
use IO::File; |
||||||
|
use Date::Parse; |
||||||
|
use DBIx::Simple; |
||||||
|
use SQL::Abstract; |
||||||
|
use Term::Prompt; |
||||||
|
use YAML; |
||||||
|
|
||||||
|
my $opts = { f => undef, F => undef }; |
||||||
|
getopts('f:F:', $opts) |
||||||
|
or die "Usage: $0 [-f <qrss.db>] [-F <filter-by-url>]\n"; |
||||||
|
|
||||||
|
die "Usage: $0 [-f <qrss.db>]\n" |
||||||
|
unless $opts->{f} and -f $opts->{f}; |
||||||
|
|
||||||
|
my $dbopts = { sqlite_unicode => 1, AutoCommit => 1, RaiseError => 1 }; |
||||||
|
my $dsn = sprintf 'dbi:SQLite:dbname=%s', $opts->{f}; |
||||||
|
my $db = DBIx::Simple->new($dsn, undef, undef, $dbopts); |
||||||
|
|
||||||
|
sub list_feeds { |
||||||
|
my $filter = $opts->{F} |
||||||
|
? { xmlUrl => {-like => "%$opts->{F}%"} } |
||||||
|
: { xmlUrl => {'!=' => ''} }; |
||||||
|
my @feeds = $db->select('feeds', [qw(id title text xmlUrl)], $filter, 'title')->hashes; |
||||||
|
print " ID | Feed name (URL)\n"; |
||||||
|
print "-----+-----------------------------------------------------------\n"; |
||||||
|
foreach my $f (@feeds) { |
||||||
|
printf " %3d | %s (%s)\n", $f->{id}, $f->{title} || $f->{text}, $f->{xmlurl}; |
||||||
|
} |
||||||
|
print "\n"; |
||||||
|
} |
||||||
|
|
||||||
|
sub export_feed { |
||||||
|
my $fid = shift; |
||||||
|
my $feed = $db->select('feeds', '*', {id => $fid})->hash |
||||||
|
or return warn "no such feed: $fid\n"; |
||||||
|
my $fname = sprintf "%d - %s", $fid, substr($feed->{title} || $feed->{text}, 0, 128); |
||||||
|
$fname =~ tr[/][]d; |
||||||
|
$fname .= '.yml'; |
||||||
|
my $file = IO::File->new($fname, 'w'); |
||||||
|
my $yml = YAML::Dump({ |
||||||
|
type => 'feed', |
||||||
|
url => $feed->{xmlurl} || $feed->{htmlurl}, |
||||||
|
name => $feed->{title} || $feed->{text}, |
||||||
|
note => $feed->{description}, |
||||||
|
}); |
||||||
|
if (utf8::is_utf8($yml)) { utf8::encode($yml); } |
||||||
|
$file->print($yml); |
||||||
|
my @news = $db->select('news', '*', {feedId => $fid})->hashes; |
||||||
|
my $exported = 0; |
||||||
|
print "exporting: "; |
||||||
|
while (my $n = shift @news) { |
||||||
|
$n->{flags} = ''; |
||||||
|
$n->{flags} .= ($n->{read}) ? 'u' : 'U'; |
||||||
|
$n->{flags} .= ($n->{starred}) ? 'S' : 's'; |
||||||
|
$n->{ctime} = str2time($n->{published} || $n->{modified}); |
||||||
|
if ($n->{description} and not $n->{content}) { |
||||||
|
$n->{content} = $n->{description}; |
||||||
|
undef $n->{description}; |
||||||
|
} |
||||||
|
foreach my $attr (qw(guid link_href)) { |
||||||
|
next unless $n->{$attr} and index($n->{$attr}, '://') >= 0; |
||||||
|
$n->{url} = $n->{$attr}; |
||||||
|
last; |
||||||
|
} |
||||||
|
$yml = YAML::Dump({ |
||||||
|
type => 'entry', |
||||||
|
url => $n->{url}, |
||||||
|
ctime => $n->{ctime}, |
||||||
|
flags => $n->{flags}, |
||||||
|
author => $n->{author_name}, |
||||||
|
category => $n->{category}, |
||||||
|
title => $n->{title}, |
||||||
|
summary => $n->{description}, |
||||||
|
content => $n->{content}, |
||||||
|
}); |
||||||
|
if (utf8::is_utf8($yml)) { utf8::encode($yml); } |
||||||
|
$file->print($yml); |
||||||
|
$exported++; |
||||||
|
if ($exported % 100 == 0) { print '.'; } |
||||||
|
} # foreach @news |
||||||
|
$file->close; |
||||||
|
print "\n"; |
||||||
|
printf "exported: %s (%d entries)\n", $fname, $exported; |
||||||
|
} |
||||||
|
|
||||||
|
sub show_help { |
||||||
|
print <<"HELP"; |
||||||
|
l\tList feeds |
||||||
|
f\tSet list filter |
||||||
|
e\tExport |
||||||
|
h\tHelp |
||||||
|
q\tQuit |
||||||
|
HELP |
||||||
|
} |
||||||
|
|
||||||
|
binmode STDOUT => ':utf8'; |
||||||
|
$| = 1; |
||||||
|
|
||||||
|
while (1) { |
||||||
|
my $a = prompt('c', 'command', 'h for help', '', qw(l f e h q)); |
||||||
|
if ($a eq 'l') { |
||||||
|
list_feeds(); |
||||||
|
} elsif ($a eq 'f') { |
||||||
|
$opts->{F} = prompt('a', 'Filter by URL', '', 'example.com', ''); |
||||||
|
} elsif ($a eq 'e') { |
||||||
|
my $fid = prompt('n', 'feed id:', '', ''); |
||||||
|
export_feed($fid); |
||||||
|
} elsif ($a eq 'q') { |
||||||
|
print "exiting...\n"; |
||||||
|
exit 0; |
||||||
|
} else { |
||||||
|
show_help(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
exit 0; |
@ -0,0 +1,44 @@ |
|||||||
|
#!/usr/bin/env perl |
||||||
|
|
||||||
|
use strict; |
||||||
|
use warnings; |
||||||
|
use utf8; |
||||||
|
|
||||||
|
use Getopt::Std; |
||||||
|
use DBIx::Simple; |
||||||
|
use SQL::Abstract; |
||||||
|
|
||||||
|
my $opts = { f => undef }; |
||||||
|
getopts('f:', $opts) |
||||||
|
or die "Usage: $0 [-f <qrss.db>]\n"; |
||||||
|
|
||||||
|
die "Usage: $0 [-f <qrss.db>]\n" |
||||||
|
unless $opts->{f} and -f $opts->{f}; |
||||||
|
|
||||||
|
my $dbopts = { sqlite_unicode => 1, AutoCommit => 1, RaiseError => 1 }; |
||||||
|
my $dsn = sprintf 'dbi:SQLite:dbname=%s', $opts->{f}; |
||||||
|
my $db = DBIx::Simple->new($dsn, undef, undef, $dbopts); |
||||||
|
|
||||||
|
my $query = 'SELECT f.id, f.title, COUNT(*) AS cnt, ' |
||||||
|
. ' SUM(LENGTH(n.description)) AS len1, SUM(LENGTH(n.content)) AS len2 FROM feeds f' |
||||||
|
. ' JOIN news n ON (f.id = feedId) GROUP BY f.id ORDER BY cnt DESC'; |
||||||
|
my $stats = $db->query($query)->hashes; |
||||||
|
|
||||||
|
printf " ID | News | Summary | Content | Title \n"; |
||||||
|
print "---------------" x 4, "\n"; |
||||||
|
my $total = { cnt => 0, len1 => 0, len2 => 0 }; |
||||||
|
foreach my $s (@{ $stats }) { |
||||||
|
utf8::encode($s->{title}); |
||||||
|
$s->{len1} //= 0; |
||||||
|
$s->{len2} //= 0; |
||||||
|
printf " %4d | %6d | %8.1fK | %8.1fK | %s\n", $s->{id}, $s->{cnt}, |
||||||
|
$s->{len1} / 1024, $s->{len2} / 1024, $s->{title}; |
||||||
|
$total->{cnt} += $s->{cnt}; |
||||||
|
$total->{len1} += $s->{len1}; |
||||||
|
$total->{len2} += $s->{len2}; |
||||||
|
} |
||||||
|
print "---------------" x 4, "\n"; |
||||||
|
printf "%5s | %6d | %8.1fK | %8.1fK | %s\n", 'Total', $total->{cnt}, |
||||||
|
$total->{len1} / 1024, $total->{len2} / 1024, ''; |
||||||
|
|
||||||
|
exit 0; |
@ -0,0 +1,116 @@ |
|||||||
|
CREATE TABLE feeds ( |
||||||
|
id integer primary key, |
||||||
|
text varchar, |
||||||
|
title varchar, |
||||||
|
description varchar, |
||||||
|
xmlUrl varchar, |
||||||
|
htmlUrl varchar, |
||||||
|
language varchar, |
||||||
|
copyrights varchar, |
||||||
|
author_name varchar, |
||||||
|
author_email varchar, |
||||||
|
author_uri varchar, |
||||||
|
webMaster varchar, |
||||||
|
pubdate varchar, |
||||||
|
lastBuildDate varchar, |
||||||
|
category varchar, |
||||||
|
contributor varchar, |
||||||
|
generator varchar, |
||||||
|
docs varchar, |
||||||
|
cloud_domain varchar, |
||||||
|
cloud_port varchar, |
||||||
|
cloud_path varchar, |
||||||
|
cloud_procedure varchar, |
||||||
|
cloud_protocal varchar, |
||||||
|
ttl integer, |
||||||
|
skipHours varchar, |
||||||
|
skipDays varchar, |
||||||
|
image blob, |
||||||
|
unread integer, |
||||||
|
newCount integer, |
||||||
|
currentNews integer, |
||||||
|
label varchar, |
||||||
|
undeleteCount integer, |
||||||
|
tags varchar, |
||||||
|
hasChildren integer default 0, |
||||||
|
parentId integer default 0, |
||||||
|
rowToParent integer, |
||||||
|
updateIntervalEnable int, |
||||||
|
updateInterval int, |
||||||
|
updateIntervalType varchar, |
||||||
|
updateOnStartup int, |
||||||
|
displayOnStartup int, |
||||||
|
markReadAfterSecondsEnable int, |
||||||
|
markReadAfterSeconds int, |
||||||
|
markReadInNewspaper int, |
||||||
|
markDisplayedOnSwitchingFeed int, |
||||||
|
markDisplayedOnClosingTab int, |
||||||
|
markDisplayedOnMinimize int, |
||||||
|
layout text, |
||||||
|
filter text, |
||||||
|
groupBy int, |
||||||
|
displayNews int, |
||||||
|
displayEmbeddedImages integer default 1, |
||||||
|
loadTypes text, |
||||||
|
openLinkOnEmptyContent int, |
||||||
|
columns text, |
||||||
|
sort text, |
||||||
|
sortType int, |
||||||
|
maximumToKeep int, |
||||||
|
maximumToKeepEnable int, |
||||||
|
maximumAgeOfNews int, |
||||||
|
maximumAgoOfNewEnable int, |
||||||
|
deleteReadNews int, |
||||||
|
neverDeleteUnreadNews int, |
||||||
|
neverDeleteStarredNews int, |
||||||
|
neverDeleteLabeledNews int, |
||||||
|
status text, |
||||||
|
created text, |
||||||
|
updated text, |
||||||
|
lastDisplayed text, |
||||||
|
f_Expanded integer default 1, |
||||||
|
flags text, |
||||||
|
authentication integer default 0, |
||||||
|
duplicateNewsMode integer default 0, |
||||||
|
typeFeed integer default 0, |
||||||
|
showNotification integer default 0, |
||||||
|
disableUpdate integer default 0, |
||||||
|
javaScriptEnable integer default 1, |
||||||
|
layoutDirection integer default 0 |
||||||
|
); |
||||||
|
|
||||||
|
CREATE TABLE news ( |
||||||
|
id integer primary key, |
||||||
|
feedId integer, |
||||||
|
guid varchar, |
||||||
|
guidislink varchar default 'true', |
||||||
|
description varchar, |
||||||
|
content varchar, |
||||||
|
title varchar, |
||||||
|
published varchar, |
||||||
|
modified varchar, |
||||||
|
received varchar, |
||||||
|
author_name varchar, |
||||||
|
author_uri varchar, |
||||||
|
author_email varchar, |
||||||
|
category varchar, |
||||||
|
label varchar, |
||||||
|
new integer default 1, -- actually "seen" |
||||||
|
read integer default 0, -- read/unread |
||||||
|
starred integer default 0, |
||||||
|
deleted integer default 0, |
||||||
|
attachment varchar, |
||||||
|
comments varchar, |
||||||
|
enclosure_length, |
||||||
|
enclosure_type, |
||||||
|
enclosure_url, |
||||||
|
source varchar, |
||||||
|
link_href varchar, |
||||||
|
link_enclosure varchar, |
||||||
|
link_related varchar, |
||||||
|
link_alternate varchar, |
||||||
|
contributor varchar, |
||||||
|
rights varchar, |
||||||
|
deleteDate varchar, |
||||||
|
feedParentId integer default 0 |
||||||
|
); |
Loading…
Reference in new issue