return 0;
}
+static int
+api_service_remove_unseen
+ ( access_t *perm, void *opaque, const char *op, htsmsg_t *args, htsmsg_t **resp )
+{
+ int days = htsmsg_get_s32_or_default(args, "days", 7);
+ const char *type = htsmsg_get_str(args, "type");
+
+ pthread_mutex_lock(&global_lock);
+ service_remove_unseen(type, days);
+ pthread_mutex_unlock(&global_lock);
+ return 0;
+}
+
void api_service_init ( void )
{
extern const idclass_t service_class;
{ "service/mapper/status", ACCESS_ADMIN, api_mapper_status, NULL },
{ "service/list", ACCESS_ADMIN, api_idnode_load_by_class, (void*)&service_class },
{ "service/streams", ACCESS_ADMIN, api_service_streams, NULL },
+ { "service/removeunseen", ACCESS_ADMIN, api_service_remove_unseen, NULL },
{ NULL },
};
*size += tvh_strlen(ms->s_dvb_charset);
}
+static int
+mpegts_service_unseen( service_t *t, const char *type, time_t before )
+{
+ mpegts_service_t *ms = (mpegts_service_t*)t;
+ int pat = type && strcasecmp(type, "pat") == 0;
+ if (pat && ms->s_auto != SERVICE_AUTO_PAT_MISSING) return 0;
+ return ms->s_dvb_last_seen < before;
+}
+
/* **************************************************************************
* Creation/Location
* *************************************************************************/
s->s_mapped = mpegts_service_mapped;
s->s_satip_source = mpegts_service_satip_source;
s->s_memoryinfo = mpegts_service_memoryinfo;
+ s->s_unseen = mpegts_service_unseen;
pthread_mutex_lock(&s->s_stream_mutex);
service_make_nicename((service_t*)s);
htsmsg_add_msg(m, "stream", list);
}
+/**
+ *
+ */
+void
+service_remove_unseen(const char *type, int days)
+{
+ service_t *s, *sn;
+ time_t before = gclk() - MAX(days, 5) * 24 * 3600;
+
+ lock_assert(&global_lock);
+ for (s = TAILQ_FIRST(&service_all); s; s = sn) {
+ sn = TAILQ_NEXT(s, s_all_link);
+ if (s->s_unseen && s->s_unseen(s, type, before))
+ service_destroy(s, 1);
+ }
+}
+
/**
*
*/
void (*s_memoryinfo)(struct service *t, int64_t *size);
+ int (*s_unseen)(struct service *t, const char *type, time_t before);
+
/**
* Channel info
*/
void service_save ( service_t *s, htsmsg_t *c );
+void service_remove_unseen(const char *type, int days);
+
void sort_elementary_streams(service_t *t);
const char *service_get_channel_name (service_t *s);
abuttons.map.setText(_('Map All'));
};
+ var unseencb = function(type) {
+ tvheadend.Ajax({
+ url: 'api/service/removeunseen',
+ params: {
+ type: type,
+ },
+ success: function(d) {
+ store.reload();
+ }
+ });
+ };
+
+ var maintenanceButton = {
+ name: 'misc',
+ builder: function() {
+ var m = new Ext.menu.Menu()
+ m.add({
+ name: 'rmunsnpat',
+ tooltip: _('Remove old services marked as missing in PAT/SDT which were not detected more than 7 days (last seen column)'),
+ iconCls: 'remove',
+ text: _('Remove unseen services (PAT/SDT) (7 days+)'),
+ });
+ m.add({
+ name: 'rmunsn',
+ tooltip: _('Remove old services which were not detected more than 7 days (last seen column)'),
+ iconCls: 'remove',
+ text: _('Remove all unseen services (7 days+)'),
+ });
+ return new Ext.Toolbar.Button({
+ tooltip: _('Maintenance operations'),
+ iconCls: 'wrench',
+ text: _('Maintenance'),
+ menu: m,
+ disabled: false
+ });
+ },
+ callback: {
+ rmunsnpat: function() { unseencb('pat'); },
+ rmunsn: function() { unseencb(''); }
+ }
+ };
+
var actions = new Ext.ux.grid.RowActions({
header: _('Details'),
width: 10,
destroy: function() {
}
});
- conf.tbar = [mapButton];
+ conf.tbar = [mapButton, maintenanceButton];
conf.selected = selected;
conf.lcol[1] = actions;
conf.plugins = [actions];