Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Misc improvements #61

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 13 additions & 1 deletion castget.1.ronn
Original file line number Diff line number Diff line change
Expand Up @@ -44,14 +44,26 @@ options as arguments.
configuration file will not be considered as 'new' if it is added to the
configuration again at a later time.

* `-s` <count>, `--stop-after`=<count>:
Stop after <count> items are processed. This is implemented per-channel.

* `-x`, `--count-disregards-eligibility`:
By default, `--stop-after` only counts items that castget considers eligible for processing (e.g. matches filters and has not been previously downloaded (or marked as downloaded with `--catchup`)). This option modifies `--stop-after` so that the count applies to all items seen, regardless of whether the item was eligible for processing.

* `-1`, `--first-only`:
Restrict operation to the most recent item in each channel only.
Restrict operation to the most recent item in each channel only. Equivalent to `--stop-after=1`.

* `-o`, `--first-only-disregards-eligibility`:
Stop processing when one item has been seen regardless of item's eligibility for processing. Equivalent to `--stop-after=1 --count-disregards-eligibility`.

* `-f` <pattern>, `--filter`=<pattern>:
Restrict operation to enclosures whose download URLs match the regular expression `pattern`. Note that this will override any regular expression filters given in the configuration file.

### Global options

* `-R`, `--reverse`:
Reverse the order in which items in feeds are processed.

* `-r`, `--resume`:
Resume aborted downloads. Make sure not to use this option if the RSS feed uses the same filename for multiple enclosures as this will corrupt existing downloads.

Expand Down
9 changes: 7 additions & 2 deletions configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,13 @@ else
AC_SUBST(CURL_LIBS)
fi

#AC_ARG_WITH(taglib, [ --without-taglib disable taglib support])
AC_ARG_WITH(taglib, AC_HELP_STRING([--without-taglib], [disable taglib support])])
AC_PATH_PROG(RONN, ronn, no)
if test "$RONN" = "no" ; then
AC_MSG_ERROR(Required tool ronn not found)
fi

#AC_ARG_WITH(taglib, [ --without-taglib disable taglib support)
AC_ARG_WITH(taglib, AC_HELP_STRING([--without-taglib], [disable taglib support]))
if test "x$with_taglib" != "xno"; then
PKG_CHECK_MODULES(TAGLIB, [taglib_c])
AC_SUBST(TAGLIB_CFLAGS)
Expand Down
90 changes: 72 additions & 18 deletions src/castget.c
Original file line number Diff line number Diff line change
Expand Up @@ -53,16 +53,8 @@ static int playlist_add(const gchar *playlist_file, const gchar *media_file);

static gboolean verbose = FALSE;
static gboolean quiet = FALSE;
static gboolean first_only = FALSE;
static gboolean resume = FALSE;
static gboolean debug = FALSE;
static gboolean show_progress_bar = FALSE;
static gboolean show_version = FALSE;
static gboolean new_only = FALSE;
static gboolean list = FALSE;
static gboolean catchup = FALSE;
static gchar *rcfile = NULL;
static gchar *filter_regex = NULL;
static option_info *opts = NULL;

int main(int argc, char **argv)
{
Expand All @@ -76,6 +68,19 @@ int main(int argc, char **argv)
enclosure_filter *filter = NULL;
GError *error = NULL;
GOptionContext *context;
static gboolean first_only = FALSE;
static gboolean first_only_disregard_eligibility = FALSE;
static gint stop_after_count = 0;
static gboolean count_disregards_eligibility = FALSE;
static gboolean resume = FALSE;
static gboolean debug = FALSE;
static gboolean reverse = FALSE;
static gboolean show_progress_bar = FALSE;
static gchar *rcfile = NULL;
static gchar *filter_regex = NULL;
static gboolean list = FALSE;
static gboolean catchup = FALSE;
static gboolean show_version = FALSE;

static GOptionEntry options[] = {
{ "catchup", 'c', 0, G_OPTION_ARG_NONE, &catchup,
Expand All @@ -100,8 +105,16 @@ int main(int argc, char **argv)
{ "new-only", 'n', 0, G_OPTION_ARG_NONE, &new_only,
"only process new channels" },
{ "quiet", 'q', 0, G_OPTION_ARG_NONE, &quiet, "only print error messages" },
{ "stop-after", 's', 0, G_OPTION_ARG_INT, &stop_after_count,
"stop after processing ARGUMENT items from each channel" },
{ "count-disregards-eligibility", 'x', 0, G_OPTION_ARG_NONE, &count_disregards_eligibility,
"when processing --stop-after, count considers all items, not just those eligible" },
{ "first-only", '1', 0, G_OPTION_ARG_NONE, &first_only,
"only process the most recent item from each channel" },
{ "first-only-disregard-eligibility", 'c', 0, G_OPTION_ARG_NONE, &first_only_disregard_eligibility,
"only process the most recent item from each channel" },
{ "reverse", 'R', 0, G_OPTION_ARG_NONE, &reverse,
"process the channel in reverse order" },
{ "filter", 'f', 0, G_OPTION_ARG_STRING, &filter_regex,
"only process items whose enclosure names match a regular expression" },

Expand Down Expand Up @@ -130,20 +143,62 @@ int main(int argc, char **argv)
exit(1);
}

if (stop_after_count < 0) {
g_print("--stop-after must be greater than 0\n");
exit(1);
}
if (first_only && stop_after_count) {
g_print("--stop-after and --first-only are incompatible\n");
exit(1);
}
if (first_only_disregard_eligibility && stop_after_count) {
g_print("--stop-after and --first-only-disregard-eligibility are incompatible\n");
exit(1);
}
if (first_only_disregard_eligibility && first_only) {
g_print("--first-only and --first-only-disregard-eligibility are incompatible\n");
exit(1);
}

if (first_only)
stop_after_count = 1;
if (first_only_disregard_eligibility) {
stop_after_count = 1;
count_disregards_eligibility = TRUE;
}

/* Decide on the action to take */
if (show_version) {
version();
exit(0);
}

if (catchup)
opts = option_info_new();
opts->no_download = 0;
opts->no_mark_read = 0;
opts->stop_after_count = stop_after_count;
opts->count_disregards_eligibility = count_disregards_eligibility;
opts->resume = resume;
opts->debug = debug;
opts->reverse = reverse;
opts->show_progress_bar = show_progress_bar;

if (catchup) {
op = OP_CATCHUP;
opts->no_download = 1;
opts->no_mark_read = 0;
}

if (list)
if (list) {
op = OP_LIST;
opts->no_download = 1;
opts->no_mark_read = 1;
}

opts->filter = NULL;
if (filter_regex) {
filter = enclosure_filter_new(filter_regex, FALSE);
opts->filter = filter;
g_free(filter_regex);
}

Expand Down Expand Up @@ -206,6 +261,8 @@ int main(int argc, char **argv)
if (filter)
enclosure_filter_free(filter);

option_info_free(opts);

g_free(rcfile);

if (kf)
Expand Down Expand Up @@ -394,7 +451,7 @@ static int _process_channel(const gchar *channel_directory, GKeyFile *kf,

c = channel_new(channel_configuration->url, channel_file,
channel_configuration->spool_directory,
channel_configuration->filename_pattern, resume);
channel_configuration->filename_pattern, opts->resume);
g_free(channel_file);

if (!c) {
Expand All @@ -415,18 +472,15 @@ static int _process_channel(const gchar *channel_directory, GKeyFile *kf,

switch (op) {
case OP_UPDATE:
channel_update(c, channel_configuration, update_callback, 0, 0, first_only,
resume, filter, debug, show_progress_bar);
channel_update(c, channel_configuration, update_callback, opts);
break;

case OP_CATCHUP:
channel_update(c, channel_configuration, catchup_callback, 1, 0, first_only,
0, filter, debug, show_progress_bar);
channel_update(c, channel_configuration, catchup_callback, opts);
break;

case OP_LIST:
channel_update(c, channel_configuration, list_callback, 1, 1, first_only, 0,
filter, debug, show_progress_bar);
channel_update(c, channel_configuration, list_callback, opts);
break;
}

Expand Down
96 changes: 77 additions & 19 deletions src/channel.c
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,9 @@
#include <sys/stat.h>
#include <sys/types.h>

void _initialize_index(channel_index *index, int num_items, int reverse);
int _next_index(channel_index *index);

static int _enclosure_pattern_match(enclosure_filter *filter,
const enclosure *enclosure);

Expand Down Expand Up @@ -293,21 +296,23 @@ static int _do_catchup(channel *c, channel_info *channel_info, rss_item *item,
}

int channel_update(channel *c, void *user_data, channel_callback cb,
int no_download, int no_mark_read, int first_only,
int resume, enclosure_filter *filter, int debug,
int show_progress_bar)
option_info *opts)
{
int i, download_failed;
int i, download_failed, eligible_items_seen = 0;
rss_file *f;

/* Retrieve the RSS file. */
f = _get_rss(c, user_data, cb, debug);
f = _get_rss(c, user_data, cb, opts->debug);

if (!f)
return 1;

channel_index index;
_initialize_index(&index, f->num_items, opts->reverse);

/* Check enclosures in RSS file. */
for (i = 0; i < f->num_items; i++)
while (_next_index(&index)) {
i = index.current;
if (f->items[i]->enclosure) {
if (!g_hash_table_lookup_extended(c->downloaded_enclosures,
f->items[i]->enclosure->url, NULL,
Expand All @@ -316,52 +321,95 @@ int channel_update(channel *c, void *user_data, channel_callback cb,

item = f->items[i];

if (!filter || _enclosure_pattern_match(filter, item->enclosure)) {
if (no_download)
if (!opts->filter || _enclosure_pattern_match(opts->filter, item->enclosure)) {
eligible_items_seen++;
if (opts->no_download)
download_failed =
_do_catchup(c, &(f->channel_info), item, user_data, cb);
else
download_failed =
_do_download(c, &(f->channel_info), item, user_data, cb, resume,
debug, show_progress_bar);
_do_download(c, &(f->channel_info), item, user_data, cb, opts->resume,
opts->debug, opts->show_progress_bar);

if (download_failed)
break;

if (!no_mark_read) {
if (!opts->no_mark_read) {
/* Mark enclosure as downloaded and immediately save channel
file to ensure that it reflects the change. */
g_hash_table_insert(c->downloaded_enclosures,
f->items[i]->enclosure->url,
(gpointer)get_rfc822_time());

_cast_channel_save(c, debug);
_cast_channel_save(c, opts->debug);
}

/* If we have been instructed to deal only with the first
available enclosure, it is time to break out of the loop. */
if (first_only)
break;
}
}

/* If we have been instructed to only process a certain number of items
and we have seen that number, exit the loop */
if (opts->stop_after_count) {
int check_index = (opts->count_disregards_eligibility) ? index.iteration : eligible_items_seen;
if (check_index >= opts->stop_after_count) {
break;
}
}
}
}

if (!no_mark_read) {
if (!opts->no_mark_read) {
/* Update the RSS last fetched time and save the channel file again. */

if (c->rss_last_fetched)
g_free(c->rss_last_fetched);

c->rss_last_fetched = g_strdup(f->fetched_time);

_cast_channel_save(c, debug);
_cast_channel_save(c, opts->debug);
}

rss_close(f);

return 0;
}

void _initialize_index(channel_index *index, int num_items, int reverse) {
index->ended = 0;
index->reverse = reverse;
index->iteration = 0;
if (reverse) {
index->start = num_items -1;
index->stop = 0;
index->current = num_items;
} else {
index->start = 0;
index->stop = num_items - 1;
index->current = -1;
}
}

int _next_index(channel_index *index) {
if (index->ended)
return 0;

index->iteration++;
if (index->reverse) {
index->current--;
if (index->current < index->stop) {
index->current = -1;
index->ended = 1;
}
} else {
index->current++;
if (index->current > index->stop) {
index->current = -1;
index->ended = 1;
}
}

return index->ended ? 0 : 1;
}

/* Match the (file) name of an enclosure against a regexp. Letters
in the pattern match both upper and lower case letters if
'caseless' is TRUE. Returns TRUE if the pattern matches, FALSE
Expand Down Expand Up @@ -398,6 +446,16 @@ static gboolean _enclosure_pattern_match(enclosure_filter *filter,
return match;
}

option_info *option_info_new()
{
option_info *opts = g_try_malloc0(sizeof(struct _option_info));
return opts;
}

void option_info_free(option_info *opts) {
g_free(opts);
}

enclosure_filter *enclosure_filter_new(const gchar *pattern, gboolean caseless)
{
enclosure_filter *e = g_malloc(sizeof(struct _enclosure_filter));
Expand Down
Loading