Astro-SpaceTrack

 view release on metacpan or  search on metacpan

lib/Astro/SpaceTrack.pm  view on Meta::CPAN

    },
    mccants	=> {
	classified	=> {
	    name	=> 'Classified TLE file',
	    member	=> undef,	# classfd.tle
	    spacetrack_type	=> 'orbit',
	    url		=> 'https://www.mmccants.org/tles/classfd.zip',
	},
	integrated	=> {
	    name	=> 'Integrated TLE file',
	    member	=> undef,	# inttles.tle
	    spacetrack_type	=> 'orbit',
	    url		=> 'https://www.mmccants.org/tles/inttles.zip',
	},
	mcnames	=> {
	    name	=> 'Molczan-format magnitude file',
	    member	=> undef,	# mcnames
	    spacetrack_type	=> 'molczan',
	    url		=> 'https://www.mmccants.org/tles/mcnames.zip',
	},
	# Removed 2025-12-15 or thereabouts
	quicksat	=> {
	    name	=> 'Quicksat-format magnitude file',
	    member	=> undef,	# qs.mag
	    spacetrack_type	=> 'quicksat',
	    url		=> 'https://www.mmccants.org/programs/qsmag.zip',
	},
	# Removed 2024-12-29.
	#rcs	=> {
	#    name	=> 'McCants-format RCS data (404 2024-04-27)',
	#    member	=> undef,	# rcs
	#    spacetrack_type	=> 'rcs.mccants',
	#    url		=> 'https://www.mmccants.org/catalogs/rcs.zip',
	#},
	vsnames	=> {
	    name	=> 'Molczan-format magnitude file (visual only)',
	    member	=> undef,	# vsnames
	    spacetrack_type	=> 'molczan',
	    url		=> 'https://www.mmccants.org/tles/vsnames.zip',
	},
    },
    spacetrack => [	# Numbered by space_track_version
	undef,	# No interface version 0
	undef,	# No interface version 1 any more
	{	# Interface version 2 (REST)

	    # On Space Track "Recent ELSETs" tab
	    full => {
		name	=> 'Full catalog',
		# As of 2026-01-19
		# https://www.space-track.org/basicspacedata/query/class/gp/EPOCH/%3Enow-30/orderby/NORAD_CAT_ID,EPOCH/format/3le
		# We have to go through satcat to eliminate bodies that
		# are not on orbit, since tle_latest includes bodies
		# decayed in the last two years or so
#		satcat	=> {},
		tle	=> {
		    EPOCH	=> '>now-30',
		},
#		number	=> 1,
	    },
	    geosynchronous => {		# GEO
		name	=> 'Geosynchronous satellites',
		# As of 2026-01-19
		# https://www.space-track.org/basicspacedata/query/class/gp/EPOCH/%3Enow-30/MEAN_MOTION/0.99--1.01/ECCENTRICITY/%3C0.01/OBJECT_TYPE/payload/orderby/NORAD_CAT_ID,EPOCH/format/3le
#		number	=> 3,
		# We have to go through satcat to eliminate bodies that
		# are not on orbit, since tle_latest includes bodies
		# decayed in the last two years or so
#		satcat	=> {
#		    PERIOD	=> '1425.6--1454.4'
#		},
		# Note that the v2 interface specimen query is
		#   PERIOD 1430--1450.
		# The v1 definition is
		#   MEAN_MOTION 0.99--1.01
		#   ECCENTRICITY <0.01
#		tle	=> {
#		    ECCENTRICITY	=> '<0.01',
##		    MEAN_MOTION		=> '0.99--1.01',
#		},
		tle	=> {
		    ECCENTRICITY	=> '<0.01',
		    EPOCH		=> '>now-30',
		    MEAN_MOTION		=> '0.99--1.01',
		    OBJECT_TYPE		=> 'payload',
		},
	    },
	    medium_earth_orbit => {	# MEO
		name	=> 'Medium Earth Orbit',
		# As of 2026-01-19
		# https://www.space-track.org/basicspacedata/query/class/gp/EPOCH/%3Enow-30/MEAN_MOTION/1.8--2.39/ECCENTRICITY/%3C0.25/OBJECT_TYPE/payload/orderby/NORAD_CAT_ID,EPOCH/format/3le
		tle	=> {
		    ECCENTRICITY	=> '<0.25',
		    EPOCH		=> '>now-30',
		    # The web page says '600 minutes <= Period <= 800
		    # minutes', but the query is in terms of mean
		    # motion.
		    MEAN_MOTION		=> '1.8--2.39',
		    OBJECT_TYPE		=> 'payload',
		},
	    },
	    low_earth_orbit => {	# LEO
		name	=> 'Low Earth Orbit',
		# As of 2026-01-19https://www.space-track.org/basicspacedata/query/class/gp/EPOCH/%3Enow-30/ECCENTRICITY/%3E0.25/OBJECT_TYPE/payload/orderby/NORAD_CAT_ID,EPOCH/format/3le
		# https://www.space-track.org/basicspacedata/query/class/gp/EPOCH/%3Enow-30/MEAN_MOTION/%3E11.25/ECCENTRICITY/%3C0.25/OBJECT_TYPE/payload/orderby/NORAD_CAT_ID,EPOCH/format/3le
		tle	=> {
		    ECCENTRICITY	=> '<0.25',
		    EPOCH		=> '>now-30',
		    MEAN_MOTION		=> '>11.25',
		    OBJECT_TYPE		=> 'payload',
		},
	    },
	    highly_elliptical_orbit => {	# HEO
		name	=> 'Highly Elliptical Orbit',
		# As of 2026-01-19
		# https://www.space-track.org/basicspacedata/query/class/gp/EPOCH/%3Enow-30/ECCENTRICITY/%3E0.25/OBJECT_TYPE/payload/orderby/NORAD_CAT_ID,EPOCH/format/3le
		tle	=> {
		    ECCENTRICITY	=> '>0.25',
		    EPOCH		=> '>now-30',
		    OBJECT_TYPE		=> 'payload',
		},
	    },

lib/Astro/SpaceTrack.pm  view on Meta::CPAN

	    },
	    well_tracked_objects	=> {
		name	=> 'Well-Tracked Objects',
		# As of 2026-01-19
		# https://www.space-track.org/basicspacedata/query/class/gp/EPOCH/%3Enow-30/NORAD_CAT_ID/80000--89999/orderby/NORAD_CAT_ID/format/tle/emptyresult/show
#		satcat	=> {
#		    COUNTRY	=> 'UNKN',
#		    SITE	=> 'UNKN',
#		},
		tle	=> {
		    EPOCH	=> '>now-30',
		    NORAD_CAT_ID	=> '80000--89999',
		    format	=> 'tle',
		    epmtyresult	=> 'show',
		},
	    },

	    # Favorites (whatever that means). As of 2026-01-19 these
	    # are specific to the individual user, and therefore
	    # useless.
	    navigation => {
		name => 'Navigation satellites',
		favorite	=> 'Navigation',
		tle => {
		    EPOCH	=> '>now-30',
		},
#		number => 5,
	    },
	    weather => {
		name => 'Weather satellites',
		favorite	=> 'Weather',
		tle => {
		    EPOCH	=> '>now-30',
		},
#		number => 7,
	    },
	    amateur => {
		favorite	=> 'Amateur',
		name => 'Amateur Radio satellites',
		tle => {
		    EPOCH	=> '>now-30',
		},
#		number => 19,
	    },
	    visible => {
		favorite	=> 'Visible',
		name => 'Visible satellites',
		tle => {
		    EPOCH	=> '>now-30',
		},
#		number => 21,
	    },
	    special => {
		favorite	=> 'Special_interest',
		name => 'Special interest satellites',
		tle => {
		    EPOCH	=> '>now-30',
		},
#		number => 23,
	    },
	    bright_geosynchronous => {
		favorite	=> 'brightgeo',
		name => 'Bright Geosynchronous satellites',
		tle => {
		    EPOCH	=> '>now-30',
		},
	    },
	    human_spaceflight => {
		favorite	=> 'human_spaceflight',
		name => 'Human Spaceflight',
		tle => {
		    EPOCH	=> '>now-30',
		},
	    },

	    # Added by TRW
	    payloads	=> {
		name	=> 'All payloads',
#		satcat	=> {
#		    OBJECT_TYPE	=> 'PAYLOAD',
#		},
		tle	=> {
		    EPOCH	=> '>now-30',
		    OBJECT_TYPE	=> 'payload',
		},
	    },
	},
    ],
);

my %mutator = (	# Mutators for the various attributes.
    addendum => \&_mutate_attrib,		# Addendum to banner text.
    banner => \&_mutate_attrib,
    cookie_expires => \&_mutate_spacetrack_interface,
    cookie_name => \&_mutate_spacetrack_interface,
    domain_space_track => \&_mutate_spacetrack_interface,
    dump_headers => \&_mutate_dump_headers,	# Dump all HTTP headers. Undocumented and unsupported.
    fallback => \&_mutate_attrib,
    filter => \&_mutate_attrib,
    identity	=> \&_mutate_identity,
    iridium_status_format => \&_mutate_iridium_status_format,
    max_range => \&_mutate_number,
    password => \&_mutate_authen,
    pretty => \&_mutate_attrib,
    prompt	=> \&_mutate_attrib,
    scheme_space_track => \&_mutate_attrib,
    session_cookie => \&_mutate_spacetrack_interface,
    space_track_version => \&_mutate_space_track_version,
    url_iridium_status_kelso => \&_mutate_attrib,
    url_iridium_status_mccants => \&_mutate_attrib,
    url_iridium_status_sladen => \&_mutate_attrib,
    username => \&_mutate_authen,
    verbose => \&_mutate_attrib,
    verify_hostname => \&_mutate_verify_hostname,
    webcmd => \&_mutate_attrib,
    with_name => \&_mutate_attrib,
);

my %accessor = (
    cookie_expires	=> \&_access_spacetrack_interface,
    cookie_name		=> \&_access_spacetrack_interface,
    domain_space_track	=> \&_access_spacetrack_interface,
    session_cookie	=> \&_access_spacetrack_interface,

lib/Astro/SpaceTrack.pm  view on Meta::CPAN

}

sub _get_readline {	## no critic (Subroutines::RequireArgUnpacking)
    my ( $self ) = @_;
    require Term::ReadLine;
    $rdln ||= Term::ReadLine->new (
	'SpaceTrack orbital element access');
    @_ > 1
	and $_[1] = ( $rdln->OUT || \*STDOUT );	# $stdout
    if ( 'Term::ReadLine::Perl' eq $rdln->ReadLine() ) {
	require File::Glob;

	$readline_word_break_re ||= qr<
	    [\Q$readline::rl_completer_word_break_characters\E]+
	>smx;

	no warnings qw{ once };
	$readline::rl_completion_function = sub {
	    my ( $text, $line, $start ) = @_;
	    return $self->__readline_completer(
		$text, $line, $start );
	};
    }
    return sub { $rdln->readline ( $self->getv( 'prompt' ) ) };
}


=for html <a name="source"></a>

=item $st->source ($filename);

This convenience method reads the given file, and passes the individual
lines to the shell method. It croaks if the file is not provided or
cannot be read.

=cut

# We really just delegate to _source, which unpacks.
sub source {
    my $self = _instance( $_[0], __PACKAGE__ ) ? shift :
	Astro::SpaceTrack->new ();
    $self->shell ($self->_source (@_), 'exit');
    return;
}


=for html <a name="spacetrack"></a>

=item $resp = $st->spacetrack ($name);

This method returns predefined sets of data from the Space Track web
site, using either canned queries or global favorites.

The following catalogs are available:

    Name            Description
    full            Full catalog
    payloads        All payloads
  * navigation      Navigation satellites
  * weather         Weather satellites
    geosynchronous  Geosynchronous bodies
    iridium         Iridium satellites
    orbcomm         OrbComm satellites
    globalstar      Globalstar satellites
    intelsat        Intelsat satellites
    inmarsat        Inmarsat satellites
  * amateur         Amateur Radio satellites
  * visible         Visible satellites
  * special         Special satellites
  * bright_geosynchronous
                    Bright Geosynchronous satellites
  * human_spaceflight
                    Human Spaceflight
    well_tracked_objects
                    Well-Tracked Objects not associated
		    with a specific launch

The starred items are 404 as of 2026-01-19. They are deprecated and will
be removed.

The following option is supported:

 -json
   specifies the TLE be returned in JSON format

Options may be specified either in command-line style
(that is, as C<< spacetrack( '-json', ... ) >>) or as a hash reference
(that is, as C<< spacetrack( { json => 1 }, ... ) >>).

This method returns an L<HTTP::Response|HTTP::Response> object. If the
operation succeeded, the content of the response will be the requested
data, unzipped if you used the version 1 interface.

If you requested a non-existent catalog, the response code will be
C<HTTP_NOT_FOUND> (a.k.a.  404); otherwise the response code will be
whatever the underlying HTTPS request returned.

A Space Track username and password are required to use this method.

If this method succeeds, the response will contain headers

 Pragma: spacetrack-type = orbit
 Pragma: spacetrack-source = spacetrack

These can be accessed by C<< $st->content_type( $resp ) >> and
C<< $st->content_source( $resp ) >> respectively.

A list of valid names and brief descriptions can be obtained by calling
C<< $st->names ('spacetrack') >>.

If you have set the C<verbose> attribute true (e.g.  C<< $st->set
(verbose => 1) >>), the content of the error response will include the
list of valid names. Note, however, that under version 1 of the
interface this list does not determine what can be retrieved.

This method implicitly calls the C<login()> method if the session cookie
is missing or expired. If C<login()> fails, you will get the
HTTP::Response from C<login()>.

=cut

{

    my %unpack_query = (
	ARRAY_REF()	=> sub { return @{ $_[0] } },
	HASH_REF()	=> sub { return $_[0] },
    );

    # Unpack a Space Track REST query. References are unpacked per the
    # above table, if found there. Undefined values return an empty hash
    # reference. Anything else croaks with a stack trace.

lib/Astro/SpaceTrack.pm  view on Meta::CPAN

	}
	return;
    }
}	# End local symbol block.

#	$self->_deprecation_notice( $method, $argument );
#
#	This method centralizes deprecation.  Deprecation is driven of
#	the %deprecate hash. Values are:
#	    false - no warning
#	    1 - warn on first use
#	    2 - warn on each use
#	    3 - die on each use.

{

    use constant _MASTER_IRIDIUM_DEPRECATION_LEVEL	=> 3;
    use constant _MASTER_FAVORITE_DEPRECATION_LEVEL	=> 2;

    my %deprecate = (
	celestrak => {
#	    sts	=> 3,
#	    '--descending'	=> 3,
#	    '--end_epoch'	=> 3,
#	    '--last5'		=> 3,
#	    '--sort'		=> 3,
#	    '--start_epoch'	=> 3,
	},
	amsat		=> 1,
	attribute	=> {
#	    direct		=> 3,
	    url_iridium_status_kelso	=> _MASTER_IRIDIUM_DEPRECATION_LEVEL,
	    url_iridium_status_mccants	=> _MASTER_IRIDIUM_DEPRECATION_LEVEL,
	    url_iridium_status_sladen	=> _MASTER_IRIDIUM_DEPRECATION_LEVEL,
	    iridium_status_format	=> 1,
	},
	iridium_status	=> _MASTER_IRIDIUM_DEPRECATION_LEVEL,
	iridium_status_format	=> {
	    kelso	=> 3,
	    mccants	=> 3,
	    sladen	=> _MASTER_IRIDIUM_DEPRECATION_LEVEL,
	},
	option => {
	    last5	=> 2,
	},
	mccants	=> {
	    mcnames	=> 3,
	    quicksat	=> 3,
	    vsnames	=> 3,
	},
	BODY_STATUS_IS_OPERATIONAL	=> _MASTER_IRIDIUM_DEPRECATION_LEVEL,
	BODY_STATUS_IS_SPARE	=> _MASTER_IRIDIUM_DEPRECATION_LEVEL,
	BODY_STATUS_IS_TUMBLING	=> _MASTER_IRIDIUM_DEPRECATION_LEVEL,
	BODY_STATUS_IS_DECAYED	=> _MASTER_IRIDIUM_DEPRECATION_LEVEL,
	spacetrack => {
	    navigation => _MASTER_FAVORITE_DEPRECATION_LEVEL,
	    weather => _MASTER_FAVORITE_DEPRECATION_LEVEL,
	    amateur => _MASTER_FAVORITE_DEPRECATION_LEVEL,
	    visible => _MASTER_FAVORITE_DEPRECATION_LEVEL,
	    special => _MASTER_FAVORITE_DEPRECATION_LEVEL,
	    bright_geosynchronous => _MASTER_FAVORITE_DEPRECATION_LEVEL,
	    human_spaceflight => _MASTER_FAVORITE_DEPRECATION_LEVEL,
	},
    );

    sub _deprecation_notice {
	my ( undef, $method, $argument ) = @_;	# Invocant unused
	defined $method
	    or ( $method = ( caller 1 )[3] ) =~ s/ .* :: //smx;
	my $level = $deprecate{$method}
	    or return;
	my $desc = $method;
	if ( ref $level ) {
	    defined $argument or Carp::confess( 'Bug - $argument undefined' );
	    $level = $level->{$argument}
		or return;
	    $desc = "$method $argument";
	}
	$level >= 3
	    and Carp::croak "$desc is retracted";
	warnings::enabled( 'deprecated' )
	    and Carp::carp "$desc is deprecated";
	1 == $level
	    or return;
	if ( ref $deprecate{$method} ) {
	    $deprecate{$method}{$argument} = 0;
	} else {
	    $deprecate{$method} = 0;
	}
	return;
    }

}

#	_dump_cookie is intended to be called from inside the
#	HTTP::Cookie->scan method. The first argument is prefix text
#	for the dump, and the subsequent arguments are the arguments
#	passed to the scan method.
#	It dumps the contents of the cookie to STDERR via a warn ().
#	A typical session cookie looks like this:
#	    version => 0
#	    key => 'spacetrack_session'
#	    val => whatever
#	    path => '/'
#	    domain => 'www.space-track.org'
#	    port => undef
#	    path_spec => 1
#	    secure => undef
#	    expires => undef
#	    discard => 1
#	    hash => {}
#	The response to the login, though, has an actual expiration
#	time, which we take cognisance of.

{	# begin local symbol block

    my @names = qw{version key val path domain port path_spec secure
	    expires discard hash};

    sub _dump_cookie {
	my ( $self, $prefix, @args ) = @_;



( run in 1.173 second using v1.01-cache-2.11-cpan-39bf76dae61 )