Merge branch 'master' into rich-presence

rich-presence
Matthew Chambers 2022-05-17 18:51:51 -05:00
commit ad30b9cda0
47 zmienionych plików z 6113 dodań i 3162 usunięć

2
.gitignore vendored
Wyświetl plik

@ -10,3 +10,5 @@ debian/tmp
.DS_Store
node_modules
package-lock.json
.vscode
desktop.ini

Wyświetl plik

@ -2,7 +2,7 @@
# see https://docs.gitlab.com/ee/ci/yaml/README.html for all available options
variables:
DEFAULT_IMAGE: debian:stable
DEFAULT_IMAGE: registry.gitlab.com/gridtracker.org/gtbuilder:v1-0
APT_CACHE_DIR: $CI_PROJECT_DIR/.cache/apt
NPM_CONFIG_CACHE: $CI_PROJECT_DIR/.cache/npm
@ -10,23 +10,37 @@ variables:
# We have code in here for releasing on both GS and S3, control it through variables
# on GitLab, do not change it in this file.
#
GCLOUD_PROJECT_ID: "cent7-288417"
GCLOUD_SERVICE_ACCOUNT: /dev/null
GCLOUD_RELEASE_DEPLOY_PATH: gs://download.gridtracker.org/release/$CI_COMMIT_TAG
GCLOUD_TESTING_DEPLOY_PATH: gs://download.gridtracker.org/testing/$CI_COMMIT_TAG
GCLOUD_DEPLOY_PATH: gs://gt_download/$CI_COMMIT_TAG
NR0Q_SERVER_ADDRESS: ""
NR0Q_SERVER_PASSWORD: ""
#
# Because it's getting to be that kind of world, we're going to have to
# sign our packages/exectuables with a signing key.
# That signing chain and spec file will be stored in a Gitlab CI Variable and protected,
# here's a placeholder for the script
G_CODE_SIGNING_CHAIN: ""
# nothing in this file ill be allowed to run automatically except for:
# 1. merge requests
# 2. manual tagging
# 3. committing to the default branch
include:
- template: "Workflows/MergeRequest-Pipelines.gitlab-ci.yml"
- template: "Security/Dependency-Scanning.gitlab-ci.yml"
- template: "Security/Secret-Detection.gitlab-ci.yml"
- template: "Security/SAST.gitlab-ci.yml"
stages:
- build
- test
- staging
- package
- pre-deploy
- deploy
default:
@ -35,7 +49,7 @@ default:
# just do a quick syntax check job, we don't need to "build" anything here other than the
# outer dev environment for gridtracker
npm_test:
npm:test:
stage: test
image: node:latest
script:
@ -49,7 +63,7 @@ npm_test:
# - echo "For example run a lint test"
# package binaries and create build artifacts that may be used in later stages
win-packaging:
win:package:
stage: package
rules:
# only do this with a manual tag starting with v or test_
@ -66,55 +80,53 @@ win-packaging:
files:
- package.json
- package.nw/package.json
before_script:
- |
mkdir -p $NPM_CONFIG_CACHE
mkdir -p artifacts
echo -e "\e[0Ksection_start:`date +%s`:apt_get[collapsed=true]\r\e[0KGetting Build Dependencies"
apt-get update && apt-get upgrade -y
apt-get install p7zip -y
wget https://nsis.sourceforge.io/mediawiki/images/4/47/Registry.zip
unzip -bj Registry.zip Desktop/Plugin/registry.dll -d /usr/share/nsis/Plugins/x86-unicode/
unzip -bj Registry.zip Desktop/Include/Registry.nsh -d /usr/share/nsis/Include/
wget https://nsis.sourceforge.io/mediawiki/images/1/18/NsProcess.zip
7zr e NsProcess.zip -y -o/usr/share/nsis/Include/ Include/nsProcess.nsh
7zr e NsProcess.zip -y -o/usr/share/nsis/Plugins/x86-unicode/ Plugin/nsProcessW.dll
mv /usr/share/nsis/Plugins/x86-unicode/nsProcessW.dll /usr/share/nsis/Plugins/x86-unicode/nsProcess.dll
## eval $(ssh-agent -s)
## echo "$NR0Q_PRIV" | tr -d '\r' | ssh-add -
## mkdir -p ~/.ssh; chmod 700 ~/.ssh
## scp -o StrictHostKeyChecking=no -P $NR0Q_SSH_PORT mchambers@$NR0Q_SERVER_ADDRESS:~/codecert.spc ./
script:
- |
mkdir -p $APT_CACHE_DIR $NPM_CONFIG_CACHE
mkdir -p artifacts
dpkg --add-architecture i386
- |
echo -e "\e[0Ksection_start:`date +%s`:apt_get[collapsed=true]\r\e[0KGetting Build Dependencies"
apt-get -qq update
apt-get -qq -o dir::cache::archives="$APT_CACHE_DIR" install -y npm wine wine32
apt-get -qq -o dir::cache::archives="$APT_CACHE_DIR" install -y build-essential devscripts
apt-get -qq -o dir::cache::archives="$APT_CACHE_DIR" install -y zip nsis nsis nsis-pluginapi wget
wget https://nsis.sourceforge.io/mediawiki/images/4/47/Registry.zip
unzip Registry.zip
mv Desktop/Plugin/registry.dll /usr/share/nsis/Plugins/x86-unicode/
mv Desktop/Include/Registry.nsh /usr/share/nsis/Include/
rm -Rf Desktop PocketPC Source
# Making our Windows packages
echo -e "\e[0Ksection_end:`date +%s`:apt_get\r\e[0K"
- test `node version.js` = `dpkg-parsechangelog -S version` || (echo "package.nw/package.json and debian/changelog version mismatch"; exit 1)
# Making our Windows packages
- |
test `node version.js` = `dpkg-parsechangelog -S version` || (echo "package.nw/package.json and debian/changelog version mismatch"; exit 1)
echo -e "\e[0Ksection_start:`date +%s`:native_build\r\e[0KBuilding native packages"
npm install --prefer-offline
npm run dist-win
for dir in dist/*-win-* ; do
if [ -d $dir ] ; then
rm $dir/locales/*.info
mkdir $dir/package.nw
for file in package.nw/* ; do
mv $dir/`basename $file` $dir/package.nw
done
elif [ -f $dir ] && [[ "$dir" == *"win-x86-Setup.exe"* ]] ; then
if [ -f $dir ] && [[ "$dir" == *"-Setup.exe" ]] ; then
echo "deleting broken installer $dir"
rm $dir
fi
done
sed "s#GridTracker-\${VERSION}-win-x86/#`pwd`/dist/GridTracker-\${VERSION}-win-x86/#g" windows/setup.nsi.tmpl > windows/setup.nsi.tmp.1
sed "s#GridTracker-Installer.#`pwd`/dist/GridTracker-Installer.#g" windows/setup.nsi.tmp.1 > windows/setup.nsi.tmp.2
sed "s#define VERSION <placeholder#define VERSION `node version.js`#g" windows/setup.nsi.tmp.2 > windows/setup.nsi
# Now we need to sign the executable before it get's stuffed into Nullsoft
# using mono signcode
## signcode -spc codecert.spc -t http://time.certum.pl/ -a sha256 dist/GridTracker-*-win-*/*.exe
# Now the executable should be signed
sed "s#<versionplaceholder>#`node version.js`#g" windows/win_installer.nsi > windows/setup.nsi.tmp.1
sed "s#<buildplaceholder>#`pwd`#g" windows/setup.nsi.tmp.1 > windows/setup.nsi
makensis windows/setup.nsi
# clean up generated files
rm windows/setup.nsi
rm windows/setup.nsi.tmp.1
rm windows/setup.nsi.tmp.2
## signcode -spc codecert.spc -t http://time.certum.pl/ -a sha256 dist/GridTracker-Installer.*.exe
(cd dist ; mv GridTracker-Installer.*.exe ../artifacts)
echo -e "\e[0Ksection_end:`date +%s`:native_build\e[0K"
intel-packaging:
linux:package:
stage: package
rules:
# only do this with a manual tag starting with v or test_
@ -131,22 +143,17 @@ intel-packaging:
files:
- package.json
- package.nw/package.json
before_script:
- |
mkdir -p $NPM_CONFIG_CACHE
mkdir -p artifacts
echo -e "\e[0Ksection_start:`date +%s`:apt_get[collapsed=true]\r\e[0KGetting Build Dependencies"
apt-get update && apt-get upgrade -y
echo -e "\e[0Ksection_end:`date +%s`:apt_get\r\e[0K"
script:
- |
mkdir -p $APT_CACHE_DIR $NPM_CONFIG_CACHE
mkdir -p artifacts/rpm
dpkg --add-architecture i386
- |
echo -e "\e[0Ksection_start:`date +%s`:apt_get[collapsed=true]\r\e[0KGetting Build Dependencies"
apt-get -qq update
apt-get -qq -o dir::cache::archives="$APT_CACHE_DIR" install -y npm wine wine32
apt-get -qq -o dir::cache::archives="$APT_CACHE_DIR" install -y build-essential devscripts
apt-get -qq -o dir::cache::archives="$APT_CACHE_DIR" install -y rpm zip wget
apt-get -qq -o dir::cache::archives="$APT_CACHE_DIR" build-dep .
echo -e "\e[0Ksection_end:`date +%s`:apt_get\r\e[0K"
- test `node version.js` = `dpkg-parsechangelog -S version` || (echo "package.nw/package.json and debian/changelog version mismatch"; exit 1)
# Making our MacOS and distro agnostic Linux packages
- |
# Making our distro agnostic Linux packages
test `node version.js` = `dpkg-parsechangelog -S version` || (echo "package.nw/package.json and debian/changelog version mismatch"; exit 1)
echo -e "\e[0Ksection_start:`date +%s`:native_build\r\e[0KBuilding native packages"
npm install --prefer-offline
npm run dist-nix
@ -158,30 +165,17 @@ intel-packaging:
tar -C dist -czf ${dir}.tar.gz `basename $dir`
fi
done
(cd dist ; mv *-mac-x64.zip *.tar.gz ../artifacts)
(cd dist; mv *.tar.gz ../artifacts/)
echo -e "\e[0Ksection_end:`date +%s`:native_build\e[0K"
# This section handles making RPMs for Fedora/CentOS/RHEL
- |
echo -e "\e[0Ksection_start:`date +%s`:rpm_build\r\e[0KBuilding RPM packages"
# mkdir -p $HOME/rpmbuild/SOURCES
# cp artifacts/*.tar.gz $HOME/rpmbuild/SOURCES/
setarch i386 rpmbuild -D "version `node ./version.js`" --build-in-place -bb gridtracker.i386.spec
setarch x86_64 rpmbuild -D "version `node ./version.js`" --build-in-place -bb gridtracker.x86_64.spec
mv $HOME/rpmbuild/RPMS/i386/*.rpm artifacts/rpm/
mv $HOME/rpmbuild/RPMS/x86_64/*.rpm artifacts/rpm/
echo -e "\e[0Ksection_end:`date +%s`:rpm_build\r\e[0K"
# This section does debian DEBs
#- |
# echo -e "\e[0Ksection_start:`date +%s`:debian_build\r\e[0KBuilding Debian packages"
# dpkg-buildpackage -uc -us
# mkdir artifacts/debian
# mv ../*.{deb,dsc,buildinfo,tar.xz,changes} artifacts/debian/
# echo -e "\e[0Ksection_end:`date +%s`:debian_build\r\e[0K"
- |
echo "we made packages!"
# This section does debian DEBs
echo -e "\e[0Ksection_start:`date +%s`:debian_build\r\e[0KBuilding Debian packages"
dpkg-buildpackage -b --no-sign
mv ../*.{deb,buildinfo,changes} artifacts/
echo -e "\e[0Ksection_end:`date +%s`:debian_build\r\e[0K"
echo "we made LINUX packages!"
ls -laR artifacts
arm-packaging:
mac:package:
stage: package
rules:
# only do this with a manual tag starting with v or test_
@ -198,118 +192,114 @@ arm-packaging:
files:
- package.json
- package.nw/package.json
before_script:
- |
mkdir -p $NPM_CONFIG_CACHE
mkdir -p artifacts
echo -e "\e[0Ksection_start:`date +%s`:apt_get[collapsed=true]\r\e[0KGetting Build Dependencies"
apt-get update && apt-get upgrade -y
echo -e "\e[0Ksection_end:`date +%s`:apt_get\r\e[0K"
script:
- |
mkdir -p $APT_CACHE_DIR $NPM_CONFIG_CACHE
mkdir -p artifacts/rpm
dpkg --add-architecture armhf
- |
echo -e "\e[0Ksection_start:`date +%s`:apt_get[collapsed=true]\r\e[0KGetting Build Dependencies"
apt-get -qq update
apt-get -qq -o dir::cache::archives="$APT_CACHE_DIR" install -y npm
apt-get -qq -o dir::cache::archives="$APT_CACHE_DIR" install -y build-essential devscripts
apt-get -qq -o dir::cache::archives="$APT_CACHE_DIR" install -y rpm zip wget
apt-get -qq -o dir::cache::archives="$APT_CACHE_DIR" build-dep .
echo -e "\e[0Ksection_end:`date +%s`:apt_get\r\e[0K"
- test `node version.js` = `dpkg-parsechangelog -S version` || (echo "package.nw/package.json and debian/changelog version mismatch"; exit 1)
# This is for ARM arch build
- |
echo -e "\e[0Ksection_start:`date +%s`:arm_build\r\e[0KBuilding ARM packages"
wget https://github.com/LeonardLaszlo/nw.js-armv7-binaries/releases/download/nw49_2020-10-26/nw49_2020-10-26.tar.gz
tar -xf nw49_2020-10-26.tar.gz
tar -xf usr/docker/dist/nwjs-chromium-ffmpeg-branding/nwjs-v0.49.2-linux-arm.tar.gz
rm nwjs-v0.49.2-linux-arm/locales/*.info
mv nwjs-v0.49.2-linux-arm/nw nwjs-v0.49.2-linux-arm/GridTracker
ls
version=`node ./version.js`
mkdir GridTracker-$version-linux-arm
cp -r nwjs-v0.49.2-linux-arm/* GridTracker-$version-linux-arm/
cp -r arm/* GridTracker-$version-linux-arm/
cp -r package.nw GridTracker-$version-linux-arm/
cp LICENSE GridTracker-$version-linux-arm/
tar -czf GridTracker-$version-linux-arm.tar.gz GridTracker-$version-linux-arm
mv GridTracker-$version-linux-arm.tar.gz artifacts/
# This section handles making RPMs for Fedora/CentOS/RHEL
#- |
# echo -e "\e[0Ksection_start:`date +%s`:rpm_build\r\e[0KBuilding RPM packages"
# mkdir -p $HOME/rpmbuild/SOURCES
# cp artifacts/*.tar.gz $HOME/rpmbuild/SOURCES/
#setarch --list
#setarch armhf rpmbuild -D "version `node ./version.js`" --build-in-place -bb gridtracker.arm.spec
#mv $HOME/rpmbuild/RPMS/armv7l/*.rpm artifacts/rpm/
#echo -e "\e[0Ksection_end:`date +%s`:rpm_build\r\e[0K"
# This section does debian DEBs
#- |
# echo -e "\e[0Ksection_start:`date +%s`:debian_build\r\e[0KBuilding Debian packages"
# dpkg-buildpackage -uc -us
# mkdir artifacts/debian
# mv ../*.{deb,dsc,buildinfo,tar.xz,changes} artifacts/debian/
# echo -e "\e[0Ksection_end:`date +%s`:debian_build\r\e[0K"
- |
echo "we made packages!"
# Making our MacOS packages
test `node version.js` = `dpkg-parsechangelog -S version` || (echo "package.nw/package.json and debian/changelog version mismatch"; exit 1)
echo -e "\e[0Ksection_start:`date +%s`:native_build\r\e[0KBuilding native packages"
npm install --prefer-offline
npm run dist-mac
(cd dist; mv *.zip ../artifacts/)
echo -e "\e[0Ksection_end:`date +%s`:native_build\e[0K"
echo "we made MAC packages!"
ls -laR artifacts
# copy test assets to NR0Q's server
nr0q_upload_testing:
stage: deploy
image: alpine
arm:package:
stage: package
variables:
NWJS_VERSION: "v0.54.2"
NWJS32_BUILD: "nw54_2021-07-09"
NWJS64_BUILD: "nw54-arm64_2021-07-10"
rules:
- if: '$CI_COMMIT_TAG =~ /^(test_).*/ && $NR0Q_SERVER_KEY != ""'
# only do this with a manual tag starting with v or test_
- if: '$CI_COMMIT_TAG =~ /^(v|test_).*/'
artifacts:
paths:
- artifacts/
name: '$CI_COMMIT_REF_SLUG'
cache:
paths:
- .cache/
- node_modules/
key:
files:
- package.json
- package.nw/package.json
before_script:
- |
apk add openssh-client
eval $(ssh-agent -s)
echo "$NR0Q_SERVER_KEY" | tr -d '\r' | ssh-add -
mkdir -p ~/.ssh; chmod 700 ~/.ssh
mkdir -p $NPM_CONFIG_CACHE
mkdir -p artifacts
#dpkg --add-architecture armhf
echo -e "\e[0Ksection_start:`date +%s`:apt_get[collapsed=true]\r\e[0KGetting Build Dependencies"
apt-get update && apt-get upgrade -y
apt-get build-dep .
echo -e "\e[0Ksection_end:`date +%s`:apt_get\r\e[0K"
script:
- |
cd artifacts
for FILE in *.*
do
echo "Calculating MD5 Hash for $FILE"
md5sum $FILE > $FILE.md5
done
for FILE in rpm/*.rpm
do
echo "Calculating MD5 Hash for $FILE"
md5sum $FILE > $FILE.md5
done
# This is for ARM 32 arch build
test `node version.js` = `dpkg-parsechangelog -S version` || (echo "package.nw/package.json and debian/changelog version mismatch"; exit 1)
echo -e "\e[0Ksection_start:`date +%s`:wget[collapsed=true]\r\e[0KGetting Upstream NWJS Binary"
wget https://github.com/LeonardLaszlo/nw.js-armv7-binaries/releases/download/$NWJS32_BUILD/$NWJS32_BUILD.tar.gz
tar -xf $NWJS32_BUILD.tar.gz
tar -xf usr/docker/dist/nwjs-chromium-ffmpeg-branding/nwjs-$NWJS_VERSION-linux-arm.tar.gz
echo -e "\e[0Ksection_end:`date +%s`:wget\r\e[0K"
rm nwjs-$NWJS_VERSION-linux-arm/locales/*.info
mv nwjs-$NWJS_VERSION-linux-arm/nw nwjs-$NWJS_VERSION-linux-arm/GridTracker
version=`node ./version.js`
mkdir GridTracker-$version-linux-arm32
cp -r nwjs-$NWJS_VERSION-linux-arm/* GridTracker-$version-linux-arm32/
cp -r arm/* GridTracker-$version-linux-arm32/
cp -r package.nw GridTracker-$version-linux-arm32/
cp LICENSE GridTracker-$version-linux-arm32/
tar -czf GridTracker-$version-linux-arm32.tar.gz GridTracker-$version-linux-arm32
mv GridTracker-$version-linux-arm32.tar.gz artifacts/
# This is for ARM 64 arch build
wget https://github.com/LeonardLaszlo/nw.js-armv7-binaries/releases/download/$NWJS64_BUILD/$NWJS64_BUILD.tar.gz
tar -xf $NWJS64_BUILD.tar.gz
tar -xf usr/docker/dist/nwjs-chromium-ffmpeg-branding/nwjs-$NWJS_VERSION-linux-arm64.tar.gz
rm nwjs-$NWJS_VERSION-linux-arm64/locales/*.info
mv nwjs-$NWJS_VERSION-linux-arm64/nw nwjs-$NWJS_VERSION-linux-arm64/GridTracker
version=`node ./version.js`
mkdir GridTracker-$version-linux-arm64
cp -r nwjs-$NWJS_VERSION-linux-arm64/* GridTracker-$version-linux-arm64/
cp -r arm/* GridTracker-$version-linux-arm64/
cp -r package.nw GridTracker-$version-linux-arm64/
cp LICENSE GridTracker-$version-linux-arm64/
tar -czf GridTracker-$version-linux-arm64.tar.gz GridTracker-$version-linux-arm64
mv GridTracker-$version-linux-arm64.tar.gz artifacts/
echo "we made ARM packages!"
ls -laR artifacts
ssh -o StrictHostKeyChecking=no gridtracker@$NR0Q_SERVER_ADDRESS "mkdir ~/$CI_COMMIT_TAG" && scp -o StrictHostKeyChecking=no -r ./* gridtracker@$NR0Q_SERVER_ADDRESS:~/$CI_COMMIT_TAG/ && ssh -o StrictHostKeyChecking=no gridtracker@$NR0Q_SERVER_ADDRESS "rm latest_test && ln -s $CI_COMMIT_TAG latest_test"
# copy release assets to NR0Q's server
nr0q_upload_release:
# copy test assets to Google Storage
upload-Google:
stage: deploy
image: alpine
image: google/cloud-sdk
variables:
GIT_STRATEGY: none
rules:
- if: '$CI_COMMIT_TAG =~ /^(v).*/ && $NR0Q_SERVER_KEY != ""'
before_script:
- |
apk add openssh-client
eval $(ssh-agent -s)
echo "$NR0Q_SERVER_KEY" | tr -d '\r' | ssh-add -
mkdir -p ~/.ssh; chmod 700 ~/.ssh
- if: '$CI_COMMIT_TAG =~ /^(v|test_).*/'
script:
- |
cd artifacts
for FILE in *.*
do
echo "Calculating MD5 Hash for $FILE"
md5sum $FILE > $FILE.md5
done
for FILE in rpm/*.rpm
do
echo "Calculating MD5 Hash for $FILE"
md5sum $FILE > $FILE.md5
done
ssh -o StrictHostKeyChecking=no gridtracker@$NR0Q_SERVER_ADDRESS "mkdir ~/$CI_COMMIT_TAG" && scp -o StrictHostKeyChecking=no -r ./* gridtracker@$NR0Q_SERVER_ADDRESS:~/$CI_COMMIT_TAG/
echo $GCP_SERVICE_KEY > gcloud-service-key.json
gcloud auth activate-service-account --key-file gcloud-service-key.json
gcloud config set project $GCLOUD_PROJECT_ID
gsutil -m cp -R artifacts/* $GCLOUD_DEPLOY_PATH/
# this only creates a "source code release" -- gitlab doesn't specify binaries
# except as links to external storage, which is suboptimal for now
source_release:
sourcerelease:
stage: deploy
image: registry.gitlab.com/gitlab-org/release-cli:latest
variables:
GIT_STRATEGY: none
rules:
- if: '$CI_COMMIT_TAG =~ /^(v).*/'
release:
@ -320,8 +310,48 @@ source_release:
assets:
links:
- name: Release Packages for $CI_COMMIT_TAG
url: https://fleetwood.mchambersradio.com/gridtracker/$CI_COMMIT_TAG/
url: https://https://storage.googleapis.com/gt_download/$CI_COMMIT_TAG/
external: true
link_type: package
script:
- echo 'Release for $CI_COMMIT_TAG'
update_arch_aur:
stage: deploy
image: archlinux:base-devel
rules:
# only do this with a manual tag starting with v
- if: '$CI_COMMIT_TAG =~ /^v.*/ && $AUR_KEY != ""'
before_script:
- |
pacman -Sy; pacman -S --needed --noconfirm openssh git
eval $(ssh-agent -s)
echo "$AUR_KEY" | tr -d '\r' | ssh-add -
mkdir -p ~/.ssh; chmod 700 ~/.ssh
git config --global user.name "nr0q"
git config --global user.email "nr0q@gridtracker.org"
script:
# generate the PKGBUILD
- |
cd arch-linux
curl -o gridtracker.tar.gz "https://gitlab.com/gridtracker.org/gridtracker/-/archive/${CI_COMMIT_TAG}/gridtracker-${CI_COMMIT_TAG}.tar.gz"
SHASUM=$(sha256sum gridtracker.tar.gz | cut -d ' ' -f1)
sed "s/REPLACE_WITH_VERSION/${CI_COMMIT_TAG#v}/;s/REPLACE_WITH_SHASUM/${SHASUM}/" PKGBUILD.template > PKGBUILD
# test that it builds
- |
useradd builder -m
passwd -d builder
printf 'builder ALL=(ALL) ALL\n' | tee -a /etc/sudoers
# build nwjs-bin
sudo -u builder bash -c 'git clone https://aur.archlinux.org/nwjs-bin.git nwjs-bin && cd nwjs-bin && makepkg -si --noconfirm'
# build gridtracker
sudo -u builder makepkg -si --noconfirm PKGBUILD
# push the new version
- |
sudo -u builder makepkg --printsrcinfo > .SRCINFO
git clone ssh://aur@aur.archlinux.org/gridtracker.git
cp PKGBUILD gridtracker/PKGBUILD
cp .SRCINFO gridtracker/.SRCINFO
cd gridtracker
git add PKGBUILD .SRCINFO && git commit -m "upgpkg: gridtracker ${CI_COMMIT_TAG#v}" && git push

Wyświetl plik

@ -1,6 +1,7 @@
BSD 3-Clause License
Copyright (c) 2018-2020 GridTricker.org
Copyright (c) 2018-2020 Stephen Tag Loomis
Copyright (c) 2018-2022 GridTricker.org
All rights reserved.
Redistribution and use in source and binary forms, with or without

Wyświetl plik

@ -21,6 +21,10 @@ clean:
@echo "Cleaning $(DESTDIR)..."
rm -rf $(DESTDIR)/*
.PHONY: build
build:
@echo "GridTracker doesn't need building :D"
.PHONY: install
install:
@echo "Installing gridtracker in $(DESTDIR)..."

22
NWJS-LICENSE 100644
Wyświetl plik

@ -0,0 +1,22 @@
NW.JS, the framekwork on which GridTracker is built is licensed uner the MIT licensed
Copyright (c) 2011-2019 NW.js Authors
Copyright (c) 2011-2019 The Chromium Authors
Copyright (c) 2011-2018 Intel Corp
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to use,
copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR
A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH
THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

Wyświetl plik

@ -1,5 +1,15 @@
# About GridTracker
GridTracker is designed for Amateur radio use. It's original tag-line was:   "GridTracker listens to traffic from WSJT-X and displays it on a map. It will also load ADIF log files".
This was back in February of 2018.  At its core GridTracker has remained true to that description but it has evolved to be a very powerful amateur radio tool and not just for FT8.
GridTracker is a warehouse of amateur radio information presented in an easy to use interface, from live traffic decodes, logbooks, spot reports, weather, current solar conditions and more.
[Read more](https://gitlab.com/gridtracker.org/gridtracker/-/wikis/Introduction/What-is-GridTracker)
See the [Wiki](https://gitlab.com/gridtracker.org/gridtracker/-/wikis/home) for the user documentation.
# Getting GridTracker
GridTracker can be downloaded for nearly all common platforms (Windows, MacOS, Linux, Raspberry Pi) from the [downloads](https://gridtracker.org/downloads/) page on our website GridTracker.org.
# Developing GridTracker
GridTracker runs using [NWJS](https://nwjs.io/), a tools that wraps both Chrome windows and node processes into
@ -21,10 +31,18 @@ automatically, but if you want to run on the command line, you can (after runnin
# Developer Environment Setup
Our builds and development environment are usually managed by [nwjs-builder-phoenix](https://github.com/evshiron/nwjs-builder-phoenix), but it only supports Intel-based architectures.
## x86-based Windows, Mac, Linux
Run `npm install` and then `npm start`
## Apple Silicon Macs (M1, M1 Pro, M1 Max)
Phoenix does not support ARM-based macs, so we have to explicitly tell it to use Intel-based versions of NWJS.
Run `npm install` and then `npm run start-x64`
## ARM-based Raspberry
Run `npm install`.
@ -89,3 +107,19 @@ Final build results are left in:
# Editing GeoJSON files
We've had success using https://vector.rocks/ and then cleaning up the output with https://jsonformatter.org/
# Hacks
### Roster Column Ordering
We've added internal support for reordering roster columns, but have yet to implement a UI to change these settings.
In the meantime you can:
* Open the roster window, right click on the "More Controls" link on the top right corner and select "Inspect" from the context menu.
* Select the "Console" tab in the Chrome DevTools window that should have appeared.
* Enter `g_rosterSettings.columnOrder` in the Console and press `[return]` to see the current list of columns.
* Enter the following in the Console, changing the values of `columnOrder` to fit your needs: `changeRosterColumnOrder(["Callsign", "Grid", "Spot"]);` and press `[return]`.
Any columns included in this list will be shown before all other columns.

Wyświetl plik

@ -0,0 +1,19 @@
# Maintainer: nr0q <nr0q@gridtracker.org>
# Contributor: classabbyamp <dev@kb6.ee>
pkgname=gridtracker
pkgver=REPLACE_WITH_VERSION
pkgrel=1
pkgdesc="Companion program for WSJT-X for mapping contacts"
arch=('x86_64')
url="https://gridtracker.org/grid-tracker/"
license=('BSD')
depends=('nwjs-bin>=0.54.0')
replaces=('gridtracker-bin')
source=("https://gitlab.com/gridtracker.org/$pkgname/-/archive/v$pkgver/$pkgname-v$pkgver.tar.gz")
sha256sums=('REPLACE_WITH_SHASUM')
package() {
cd "$srcdir/$pkgname-v$pkgver/"
make install DESTDIR=$pkgdir NO_DIST_INSTALL=true
}

65
debian/changelog vendored
Wyświetl plik

@ -1,10 +1,61 @@
gridtracker (1.22.0503) unstable; urgency=low
- Increment version for build with correct NWJS version
-- Matthew Chambers <nr0q@gridtracker.org> Mon, 01 May 2022 16:07:00 -0000
gridtracker (1.22.0502) unstable; urgency=low
[Bug Fixes]
- Fixed broken Call Roster due to online assets being moved from a web server to Google Storage Bucket.
- Don't highlight "CQ" rows if filtering by "CQ Only".
- Resolved #126 Windows Installer script updated to fix issues with install location and missing registry keys
- Resolved #124 removing IP-Geolocation when no all other means of locating failed, we now tell the user to
start WSJT-X or enter a location as Geo-Location services are costly and unreliable
- Resolved #137 missing libatomic dependency in Linux DEB and RPM spec files
[Enhancements]
- Include version number in main window title
- Call Roster colums refactored and wanted column added
-- Matthew Chambers <nr0q@gridtracker.org> Mon, 01 May 2022 02:25:40 -0000
gridtracker (1.21.1217) unstable; urgency=low
- Changed to newer NWJS to fix upstream bug that caused media playback to fail.
-- Matthew Chambers <nr0q@gridtracker.org> Fri, 17 Dec 2021 20:08:00 -0000
gridtracker (1.21.1212) unstable; urgency=low
Release build with the call roster refactor code that's been in the works for some time.
[Bug Fixes]
- Fix #76, unfinished ignore CQ and ITU zones.
- Improved handling of stations that are not in a valid DXCC (ie; /MM stations)
- Improved handling of free text decodes that don't contain valid callsigns (ie "HI BOB" and "MERRY XMAS")
- Fix how the Call Roster title bar counts are calculated.
[Enhancements]
- More clarity when a ULS Zip code falls in more then one county, replacing ~ with ? symbols and
better tool tip message.
- Fix #107, where the call roster timeout was longer then a single FT4 cycle.
- Fix #91, CQ is always highlighted, no matter status of CQ Only.
- Performance improvement by changing how call roster vars are handled ('let' vs 'var')
- Build system improved to push to Arch AUR, building of Debian (.deb) packages and triggering
of COPR RPM builds for Fedora/Cent/RHEL and their cousins.
-- Matthew Chambers <nr0q@gridtracker.org> Thu, 12 Dec 2021 15:10:00 -0000
gridtracker (1.21.0928) unstable; urgency=medium
[Bug Fixes]
- Treat ADIF record values as byte length vs string length (to better handle UTSF-8 data).
- Remove looking at fetched records for last date for LoTW fetches, Use only headers (More reliable LoTW fetches).
[Enhancements]
- ARM builds now with NWJS 0.54.2 and 64 bit ARM binaries.
-- Matthew Chambers <nr0q@gridtracker.org> Sun, 28 Sep 2021 00:00:00 -0000
gridtracker (1.21.0620) unstable; urgency=medium
[Bug Fixes]
- Fix pulling down of LoTW logs at start-up with a differential log syncing mechanism that only get's changes since last sync, also cool down timer to prevent rapid reloading of LoTW log.
[Enhancements]
- Automatic pulling down of acknowledgements.json file daily when doing version check (if enabled).
-- Matthew Chambers <nr0q@gridtracker.org> Sat, 19 June 20201 16:49:00 -0000
-- Matthew Chambers <nr0q@gridtracker.org> Sat, 19 Jun 2021 16:49:00 -0000
gridtracker (1.21.0613) unstable; urgency=medium
[Bug Fixes]
@ -12,7 +63,7 @@ gridtracker (1.21.0613) unstable; urgency=medium
[Enhancements]
- Updated list of contributors
-- Matthew Chambers <nr0q@gridtracker.org> Sun, 13 June 2021 03:04:00 -0000
-- Matthew Chambers <nr0q@gridtracker.org> Sun, 13 Jun 2021 03:04:00 -0000
gridtracker (1.21.0530) unstable; urgency=medium
[Bug Fixes]
@ -25,7 +76,7 @@ gridtracker (1.21.0530) unstable; urgency=medium
[Enhancements]
- Add statistical information to call roster title bar
-- Matthew Chambers <nr0q@gridtracker.org> Sat, 30 May 2021 00:10:00 -0000
-- Matthew Chambers <nr0q@gridtracker.org> Sat, 30 May 2021 00:10:00 -0000
gridtracker (1.21.0520) unstable; urgency=medium
[Bug Fixes]
@ -41,7 +92,7 @@ gridtracker (1.21.0520) unstable; urgency=medium
- Make settings icon a toggle that both opens and closes the settings pane
- Grid and IP Address Fields are slightly wider
-- Matthew Chambers <nr0q@gridtracker.org> Mon, 17 May 2021 02:30:00 -0000
-- Matthew Chambers <nr0q@gridtracker.org> Mon, 17 May 2021 02:30:00 -0000
gridtracker (1.21.0407) unstable; urgency=medium
[Bug Fixes]
@ -52,12 +103,12 @@ gridtracker (1.21.0407) unstable; urgency=medium
- new icon to request ClubLog OQRS QSL
- add eQSL check in log file processing
-- Matthew Chambers <nr0q@gridtracker.org> Wed, 07 Apr 2021 00:00:00 -0000
-- Matthew Chambers <nr0q@gridtracker.org> Wed, 07 Apr 2021 00:00:00 -0000
gridtracker (1.21.0327) unstable; urgency=medium
This is the public release of the 1.21.0324 hotfix release candidates
-- Matthew Chambers <nr0q@gridtracker.org> Fri, 27 Mar 2021 00:38:00 -0000
-- Matthew Chambers <nr0q@gridtracker.org> Fri, 27 Mar 2021 00:38:00 -0000
gridtracker (1.21.0324) unstable; urgency=medium
[Christian Bayer]
@ -104,6 +155,8 @@ gridtracker (1.21.0307) unstable; urgency=medium
queried from Callook since it usually has more data than free QRZ lookup
* fixed CR alert script not being triggered for Awared Tracker hits
-- Matthew Chambers <nr0q@gridtracker.org> Sun, 7 Mar 2021 12:00:00 -0000
gridtracker (1.20.1118) unstable; urgency=low
* GridTracker is now Open Source! Copyright assigned to GridTracker.org and

8
debian/control vendored
Wyświetl plik

@ -1,14 +1,14 @@
Source: gridtracker
Section: hamradio
Priority: optional
Maintainer: Paul Traina <216482-pleasantone@users.noreply.gitlab.com>
Maintainer: Matthew Chambers <nr0q@gridtracker.org>
Build-Depends: debhelper (>= 12.1)
Standards-Version: 4.3.0
Homepage: http://gridtracker.org/
Homepage: https://gridtracker.org/
Package: gridtracker
Architecture: any
Depends: ${misc:Depends}
Architecture: all
Depends: ${misc:Depends} nwjs
Recommends: speech-dispatcher-espeak-ng
Description: Companion program to WSJT-X/JTDX
.

4
debian/copyright vendored
Wyświetl plik

@ -4,9 +4,9 @@ Upstream-Contact: GridTracker Team <contact@gridtracker.org>
Source: https://gitlab.com/gridtracker.org/gridtracker
Files: *
Copyright: Copyright (c) 2018-2020 by Tag Loomis, 2020 by GridTracker.org
Copyright: Copyright (c) 2018-2020 by Tag Loomis, 2020-2022 by GridTracker.org
License: BSD-3-clause
Copyright (c) 2018-2020 GridTricker.org
Copyright (c) 2018-2022 GridTricker.org
All rights reserved.
.
Redistribution and use in source and binary forms, with or without

2
debian/rules vendored
Wyświetl plik

@ -1,4 +1,6 @@
#!/usr/bin/make -f
export NO_DIST_INSTALL = true
export DH_VERBOSE = 1
%:
dh $@

Wyświetl plik

@ -15,26 +15,18 @@ for dir in dist/*-linux-* ; do
fi
done
for dir in dist/*-win-* ; do
if [ -d $dir ] ; then
mkdir $dir/package.nw
for file in package.nw/* ; do
mv $dir/`basename $file` $dir/package.nw
done
elif [ -f $dir ] && [[ "$dir" == *"win-x86-Setup.exe"* ]] ; then
if [ -f $dir ] && [[ "$dir" == *"-Setup.exe" ]] ; then
echo "deleting broken installer $dir"
rm $dir
fi
done
sed "s#GridTracker-\${VERSION}-win-x86/#`pwd`/dist/GridTracker-\${VERSION}-win-x86/#g" windows/setup.nsi.tmpl > windows/setup.nsi.tmp.1
sed "s#GridTracker-Installer.#`pwd`/dist/GridTracker-Installer.#g" windows/setup.nsi.tmp.1 > windows/setup.nsi.tmp.2
sed "s#define VERSION <placeholder#define VERSION `node version.js`#g" windows/setup.nsi.tmp.2 > windows/setup.nsi
sed "s#<versionplaceholder>#`node version.js`#g" windows/win_installer.nsi > windows/setup.nsi.tmp.1
sed "s#<buildplaceholder>#`pwd`#g" windows/setup.nsi.tmp.1 > windows/setup.nsi
makensis windows/setup.nsi
# clean up generated files
rm windows/setup.nsi
rm windows/setup.nsi.tmp.1
rm windows/setup.nsi.tmp.2
mv dist/*{.exe,mac-x64.zip,.tar.gz} ../dist
rpmbuild -D "version `node ./version.js`" --build-in-place -bb gridtracker.i386.spec

Wyświetl plik

@ -43,7 +43,7 @@ Run gridtracker, no arguments needed.
.SH COPYRIGHT
.PP
Copyright (c) 2018-2020 Stephen Tag Loomis. All rights reserved.
Copyright (c) 2020 GridTracker.org. All rights reserved.
Copyright (c) 2020-2022 GridTracker.org. All rights reserved.
Released under BSD 3-Clause License
https://gridtracker.org

Wyświetl plik

@ -1,65 +0,0 @@
# Build with the following syntax:
#
# version=`node ./version.js`
# rpmbuild -D "version ${version}" --build-in-place -bb --target i386 gridtracker.i386.spec
Name: gridtracker
Summary: GridTracker: An amateur radio companion to WSJT-X or JTDX
Version: %{version}
Release: 1%{?dist}
BuildArch: armv7
Source0: GridTracker-%{version}-linux-arm.tar.gz
License: BSD 3-Clause License
URL: https://gridtracker.org
Group: Science & Math
Packager: Matthew Chambers <nr0q@gridtracker.org>
# Requires: nwjs
# BuildRequires: desktop-file-utils
%description
GridTracker listens to traffic from WSJT-X/JTDX, displays it on a map,
and has a sophisticated alerting and filtering system for finding and
working interesting stations. It also will upload QSO records to multiple
logging frameworks including Logbook of the World.
%prep
%setup -n GridTracker
#%build
%install
mkdir -p ${RPM_BUILD_ROOT}/usr/share/%{name}
cp -aR GridTracker-%version-linux-arm/ ${RPM_BUILD_ROOT}/usr/share/%{name}/
mkdir -p ${RPM_BUILD_ROOT}%{_mandir}/man1
cp -a %{name}.1 ${RPM_BUILD_ROOT}%{_mandir}/man1/
mkdir -p ${RPM_BUILD_ROOT}%{_docdir}/%{name}
cp -a LICENSE ${RPM_BUILD_ROOT}%{_docdir}/%{name}/
mkdir -p ${RPM_BUILD_ROOT}/usr/share/applications
cat > ${RPM_BUILD_ROOT}/usr/share/applications/%{name}.desktop << 'EOF'
[Desktop Entry]
Name=GridTracker
Comment=GridTracker
Exec=/usr/share/%{name}/GridTracker
Icon=/usr/share/%{name}/gridtracker.png
Path=/usr/share/%{name}
Type=Application
Encoding=UTF-8
Terminal=false
Categories=DataVisualization,Geography,Education;
EOF
chmod 755 ${RPM_BUILD_ROOT}/usr/share/%{name}/; chmod 755 ${RPM_BUILD_ROOT}/usr/share/%{name}/GridTracker; chmod 755 ${RPM_BUILD_ROOT}/usr/share/%{name}/lib; chmod 755 ${RPM_BUILD_ROOT}/usr/share/%{name}/locales
find ${RPM_BUILD_ROOT}/usr/share/ -type f \( -name '*.so' -o -name '*.so.*' \) -exec chmod 755 {} +
# %check
# %clean
%files
/usr/share/%{name}/
/usr/share/applications/%{name}.desktop
%{_datadir}/%{name}/
%{_mandir}/man1/
%license %{_docdir}/%{name}/

Wyświetl plik

@ -1,65 +0,0 @@
# Build with the following syntax:
#
# version=`node ./version.js`
# rpmbuild -D "version ${version}" --build-in-place -bb --target i386 gridtracker.i386.spec
Name: gridtracker
Summary: GridTracker: An amateur radio companion to WSJT-X or JTDX
Version: %{version}
Release: 1%{?dist}
BuildArch: i386
Source0: GridTracker-%{version}-linux-x86.tar.gz
License: BSD 3-Clause License
URL: https://gridtracker.org
Group: Science & Math
Packager: Matthew Chambers <nr0q@gridtracker.org>
# Requires: nwjs
# BuildRequires: desktop-file-utils
%description
GridTracker listens to traffic from WSJT-X/JTDX, displays it on a map,
and has a sophisticated alerting and filtering system for finding and
working interesting stations. It also will upload QSO records to multiple
logging frameworks including Logbook of the World.
%prep
%setup -n GridTracker
#%build
%install
mkdir -p ${RPM_BUILD_ROOT}/usr/share/%{name}
cp -aR dist/*-linux-x86/* ${RPM_BUILD_ROOT}/usr/share/%{name}/
mkdir -p ${RPM_BUILD_ROOT}%{_mandir}/man1
cp -a %{name}.1 ${RPM_BUILD_ROOT}%{_mandir}/man1/
mkdir -p ${RPM_BUILD_ROOT}%{_docdir}/%{name}
cp -a LICENSE ${RPM_BUILD_ROOT}%{_docdir}/%{name}/
mkdir -p ${RPM_BUILD_ROOT}/usr/share/applications
cat > ${RPM_BUILD_ROOT}/usr/share/applications/%{name}.desktop << 'EOF'
[Desktop Entry]
Name=GridTracker
Comment=GridTracker
Exec=/usr/share/%{name}/GridTracker
Icon=/usr/share/%{name}/gridtracker.png
Path=/usr/share/%{name}
Type=Application
Encoding=UTF-8
Terminal=false
Categories=DataVisualization,Geography,Education;
EOF
chmod 755 ${RPM_BUILD_ROOT}/usr/share/%{name}/; chmod 755 ${RPM_BUILD_ROOT}/usr/share/%{name}/GridTracker; chmod 755 ${RPM_BUILD_ROOT}/usr/share/%{name}/lib; chmod 755 ${RPM_BUILD_ROOT}/usr/share/%{name}/locales
find ${RPM_BUILD_ROOT}/usr/share/ -type f \( -name '*.so' -o -name '*.so.*' \) -exec chmod 755 {} +
# %check
# %clean
%files
/usr/share/%{name}/
/usr/share/applications/%{name}.desktop
%{_datadir}/%{name}/
%{_mandir}/man1/
%license %{_docdir}/%{name}/

73
gridtracker.spec 100644
Wyświetl plik

@ -0,0 +1,73 @@
Name: {{{ git_name name=gridtracker }}}
Summary: GridTracker: An amateur radio companion to WSJT-X or JTDX
Version: {{{ git_version lead=1.22.0503 }}}
Release: 1%{?dist}
BuildArch: noarch
Source0: {{{ git_dir_pack }}}
License: BSD 3-Clause License
URL: https://gridtracker.org
Group: Science & Math
Packager: Matthew Chambers <nr0q@gridtracker.org>
Requires: nwjs
BuildRequires: desktop-file-utils make nodejs
%description
GridTracker listens to traffic from WSJT-X/JTDX, displays it on a map,
and has a sophisticated alerting and filtering system for finding and
working interesting stations. It also will upload QSO records to multiple
logging frameworks including Logbook of the World.
%prep
{{{ git_dir_setup_macro }}}
%build
%install
DESTDIR=${RPM_BUILD_ROOT} make NO_DIST_INSTALL=true install
%check
%clean
DESTDIR=${RPM_BUILD_ROOT} make clean
%files
%{_datadir}/%{name}/
%{_datadir}/applications/%{name}.desktop
%{_datadir}/%{name}/
%{_bindir}/%{name}
%{_mandir}/man1/
%license %{_docdir}/%{name}/
%changelog
* Mon May 02 2022 Matthew Chambers <nr0q@gridtracker.org> - 1.22.0503-1
- Increment version number for build with correct vesion of NWJS
* Mon May 02 2022 Matthew Chambers <nr0q@gridtracker.org> - 1.22.0502-1
- [Bug Fixes]
- Fixed broken Call Roster due to online assets being moved from a web server to Google Storage Bucket.
- Don't highlight "CQ" rows if filtering by "CQ Only".
- Resolved #126 Windows Installer script updated to fix issues with install location and missing registry keys
- Resolved #124 removing IP-Geolocation when no all other means of locating failed, we now tell the user to
start WSJT-X or enter a location as Geo-Location services are costly and unreliable
- Resolved #137 missing libatomic dependency in Linux DEB and RPM spec files
- [Enhancements]
- Include version number in main window title
- Call Roster colums refactored and wanted column added
* Fri Dec 17 2021 Matthew Chambers <nr0q@gridtracker.org> - 1.21.1217-1
- Changed to newer NWJS to fix upstream bug that caused media playback to fail.
* Sun Dec 12 2021 Matthew Chambers <nr0q@gridtracker.org> - 1.21.1212-1
- Release build with the call roster refactor code that's been in the works for some time.
- [Bug Fixes]
- Fix #76, unfinished ignore CQ and ITU zones.
- Improved handling of stations that are not in a valid DXCC (ie; /MM stations)
- Improved handling of free text decodes that don't contain valid callsigns (ie "HI BOB" and "MERRY XMAS")
- Fix how the Call Roster title bar counts are calculated.
- [Enhancements]
- More clarity when a ULS Zip code falls in more then one county, replacing ~ with ? symbols and better tool tip message.
- Fix #107, where the call roster timeout was longer then a single FT4 cycle.
- Fix #91, CQ is always highlighted, no matter status of CQ Only.
- Performance improvement by changing how call roster vars are handled ('let' vs 'var')
- Build system improved to push to Arch AUR, building of Debian (.deb) packages and triggering
of COPR RPM builds for Fedora/Cent/RHEL and their cousins.
* Thu Sep 30 2021 Matthew Chambers <nr0q@gridtracker.org> - 1.21.0928-1
- First attempt at repo grade RPM builds

Wyświetl plik

@ -1,66 +0,0 @@
# Build with the following syntax:
#
# version=`node ./version.js`
# rpmbuild -D "version ${version}" --build-in-place -bb --target x86_64 gridtracker.x86_64.spec
Name: gridtracker
Summary: GridTracker: An amateur radio companion to WSJT-X or JTDX
Version: %{version}
Release: 1%{?dist}
BuildArch: x86_64
Source0: GridTracker-%{version}-linux-x64.tar.bz
License: BSD 3-Clause License
URL: https://gridtracker.org
Group: Science & Math
Packager: Matthew Chambers
# Requires: nwjs
# BuildRequires: desktop-file-utils
%description
GridTracker listens to traffic from WSJT-X/JTDX, displays it on a map,
and has a sophisticated alerting and filtering system for finding and
working interesting stations. It also will upload QSO records to multiple
logging frameworks including Logbook of the World.
%prep
%setup -n GridTracker
%build
%install
mkdir -p ${RPM_BUILD_ROOT}/usr/share/%{name}
cp -aR dist/*-linux-x64/* ${RPM_BUILD_ROOT}/usr/share/%{name}/
mkdir -p ${RPM_BUILD_ROOT}%{_mandir}/man1
cp -a %{name}.1 ${RPM_BUILD_ROOT}%{_mandir}/man1/
mkdir -p ${RPM_BUILD_ROOT}%{_docdir}/%{name}
cp -a LICENSE ${RPM_BUILD_ROOT}%{_docdir}/%{name}/
mkdir -p ${RPM_BUILD_ROOT}/usr/share/applications
cat > ${RPM_BUILD_ROOT}/usr/share/applications/%{name}.desktop << 'EOF'
[Desktop Entry]
Name=GridTracker
Comment=GridTracker
Exec=/usr/share/%{name}/GridTracker
Icon=/usr/share/%{name}/gridtracker.png
Path=/usr/share/%{name}
Type=Application
Encoding=UTF-8
Terminal=false
Categories=DataVisualization,Geography,Education;
EOF
chmod 755 ${RPM_BUILD_ROOT}/usr/share/%{name}/; chmod 755 ${RPM_BUILD_ROOT}/usr/share/%{name}/GridTracker; chmod 755 ${RPM_BUILD_ROOT}/usr/share/%{name}/lib; chmod 755 ${RPM_BUILD_ROOT}/usr/share/%{name}/locales
find ${RPM_BUILD_ROOT}/usr/share/ -type f \( -name '*.so' -o -name '*.so.*' \) -exec chmod 755 {} +
# %check
# %clean
%files
/usr/share/%{name}/
/usr/share/applications/%{name}.desktop
%{_datadir}/%{name}/
%{_mandir}/man1/
%license %{_docdir}/%{name}/

2638
package-lock.json wygenerowano 100644

Plik diff jest za duży Load Diff

Wyświetl plik

@ -13,12 +13,11 @@
"test": "eslint package.nw",
"lint-check": "eslint package.nw",
"lint-fix": "eslint --fix package.nw",
"dist-nix": "build --concurrent --tasks linux-x86,linux-x64,mac-x64 package.nw",
"dist-nix": "build --concurrent --tasks linux-x86,linux-x64 package.nw",
"dist-mac": "build --concurrent --tasks mac-x64 package.nw",
"dist-win": "build --concurrent --tasks win-x86,win-x64 package.nw",
"distsome": "build --debug --tasks linux-x64,mac-x64 package.nw",
"start": "run package.nw"
},
"dependencies": {
"discord-urpc": "^1.0.1"
"start": "run package.nw",
"start-x64": "run --x64 package.nw"
}
}

Wyświetl plik

@ -1,6 +1,6 @@
<!DOCTYPE html>
<!--
GridTracker Copyright © 2018-2021 GridTracker.org
GridTracker Copyright © 2018-2022 GridTracker.org
All rights reserved.
Redistribution and use in source and binary forms, with or without
@ -756,6 +756,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
id="myTooltip"
style="
-webkit-user-select: text;
user-select: text;
background-color: black;
padding: 5px;
text-align: center;
@ -1071,7 +1072,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
<br />
<div
class="button"
onclick="require('nw.gui').Shell.openExternal('http://app.gridtracker.org/gt_print.html');"
onclick="require('nw.gui').Shell.openExternal('https://storage.googleapis.com/gt_app/gt_print.html');"
>
Print
</div>
@ -2893,7 +2894,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
<td colspan="2">
<input
type="range"
min="15"
min="5"
max="300"
value="120"
step="15"
@ -2905,6 +2906,18 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
</tr>
</table>
</div>
<div class="mapItem">
<table align="center">
<tr align="center">
<td align="center">Clear Call Roster on Band change</td>
</tr>
<tr align="center">
<td colspan="2">
<input type="checkbox" id="clearRosterOnBandChange" onchange="clearRosterOnBandChangeValueChanged(this);" />
</td>
</tr>
</table>
</div>
<br />
<div class="mapItem" id="haltTXDiv" style="display: none">
<table align="center">
@ -3526,7 +3539,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
>GridTracker.org!</a
>
</p>
<p>Copyright &copy; 2021 GridTracker.org</p>
<p>Copyright &copy; 2022 GridTracker.org</p>
<img src="./gridview.png" /> <br />
</div>
</div>
@ -3623,6 +3636,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
<h2>GridTracker is up to date!</h2>
<div class="button" onclick="closeUpdateToDateDiv();">OK</div>
</div>
<div id="selectNodeDiv" style="-webkit-user-select: text; display: block; z-index: -10000"></div>
<div id="selectNodeDiv" style="-webkit-user-select: text; user-select: text; display: block; z-index: -10000"></div>
</body>
</html>

Wyświetl plik

@ -1,72 +1,20 @@
{
"A41MK": {
"badge": "img/emojis/money-bag.png",
"message": "GridTracker Donor"
},
"AA5KD": {
"badge": "img/emojis/money-bag.png",
"message": "GridTracker Donor"
},
"AD0WB": {
"badge": "img/emojis/money-bag.png",
"message": "GridTracker Donor"
},
"AE4ON": {
"badge": "img/emojis/money-bag.png",
"message": "GridTracker Donor"
},
"AF2V": {
"badge": "img/emojis/books.png",
"message": "GridTracker Documentation"
},
"AJ6RX": {
"badge": "img/emojis/money-bag.png",
"message": "GridTracker Donor"
},
"BD3OOX": {
"badge": "img/emojis/speech.png",
"message": "GridTracker Translator"
},
"CX4CD": {
"badge": "img/emojis/money-bag.png",
"message": "GridTracker Donor"
},
"DE1JPJ": {
"badge": "img/emojis/money-bag.png",
"message": "GridTracker Donor"
},
"DL6RA": {
"badge": "img/emojis/money-bag.png",
"message": "GridTracker Donor"
},
"EI8GS": {
"badge": "img/emojis/money-bag.png",
"message": "GridTracker Donor"
},
"GI1MIC": {
"badge": "img/emojis/pizza.png",
"message": "GridTracker Tester"
},
"GM4SJB": {
"badge": "img/emojis/money-bag.png",
"message": "GridTracker Donor"
},
"HB9VKL": {
"badge": "img/emojis/money-bag.png",
"message": "GridTracker Donor"
},
"HI80": {
"badge": "img/emojis/speech.png",
"message": "GridTracker Translator"
},
"I4SOI": {
"badge": "img/emojis/money-bag.png",
"message": "GridTracker Donor"
},
"IW2BUW": {
"badge": "img/emojis/money-bag.png",
"message": "GridTracker Donor"
},
"IW3HMH": {
"badge": "img/emojis/logbook.png",
"message": "Creator of Log4OM"
@ -79,98 +27,30 @@
"badge": "img/emojis/star.png",
"message": "Creator of FT8 and WSJT-X"
},
"K2PF": {
"badge": "img/emojis/money-bag.png",
"message": "GridTracker Donor"
},
"K4TLS": {
"badge": "img/emojis/money-bag.png",
"message": "GridTracker Donor"
},
"K5DCC": {
"badge": "img/emojis/money-bag.png",
"message": "GridTracker Donor"
},
"K5TUX": {
"badge": "img/emojis/penguin.png",
"message": "GridTracker Partner"
},
"K7CGA": {
"badge": "img/emojis/money-bag.png",
"message": "GridTracker Donor"
},
"K7YD": {
"badge": "img/emojis/money-bag.png",
"message": "GridTracker Donor"
},
"K8VSY": {
"badge": "img/emojis/money-bag.png",
"message": "GridTracker Donor"
},
"K9AN": {
"badge": "img/emojis/star.png",
"message": "Co-Creator of FT8"
},
"K9MIH": {
"badge": "img/emojis/money-bag.png",
"message": "GridTracker Donor"
},
"KA0AZS": {
"badge": "img/emojis/pizza.png",
"message": "GridTracker Tester"
},
"KA4JON": {
"badge": "img/emojis/money-bag.png",
"message": "GridTracker Donor"
},
"KA7JAZ": {
"badge": "img/emojis/money-bag.png",
"message": "GridTracker Donor"
},
"KB2BK": {
"badge": "img/emojis/money-bag.png",
"message": "GridTracker Donor"
},
"KB2YSI": {
"badge": "img/emojis/coffee.png",
"message": "GridTracker Developer"
},
"KB4RSM": {
"badge": "img/emojis/money-bag.png",
"message": "GridTracker Donor"
},
"KB5ITC": {
"badge": "img/emojis/money-bag.png",
"message": "GridTracker Donor"
},
"KC4HN": {
"badge": "img/emojis/money-bag.png",
"message": "GridTracker Donor"
},
"KC7ZXY": {
"badge": "img/emojis/money-bag.png",
"message": "GridTracker Donor"
},
"KD0YTE": {
"badge": "img/emojis/pizza.png",
"message": "GridTracker Tester"
},
"KD9QGP": {
"badge": "img/emojis/money-bag.png",
"message": "GridTracker Donor"
},
"KE0UL": {
"badge": "img/emojis/grandfather.png",
"message": "GridTracker's Grandfather"
},
"KE1Q": {
"badge": "img/emojis/money-bag.png",
"message": "GridTracker Donor"
},
"KE4WLE": {
"badge": "img/emojis/money-bag.png",
"message": "GridTracker Donor"
},
"KF5QHQ": {
"badge": "img/emojis/trophy.png",
"message": "GridTracker Developer"
@ -179,34 +59,6 @@
"badge": "img/emojis/flatbread.png",
"message": "GridTracker Developer"
},
"KJ7KRN": {
"badge": "img/emojis/money-bag.png",
"message": "GridTracker Donor"
},
"KO4BCN": {
"badge": "img/emojis/money-bag.png",
"message": "GridTracker Donor"
},
"KQ4Y": {
"badge": "img/emojis/money-bag.png",
"message": "GridTracker Donor"
},
"KW4AU": {
"badge": "img/emojis/money-bag.png",
"message": "GridTracker Donor"
},
"LA6YJA": {
"badge": "img/emojis/money-bag.png",
"message": "GridTracker Donor"
},
"LU7DK": {
"badge": "img/emojis/money-bag.png",
"message": "GridTracker Donor"
},
"N0GTO": {
"badge": "img/emojis/money-bag.png",
"message": "GridTracker Donor"
},
"N0TTL": {
"badge": "img/emojis/star.png",
"message": "Creator of GridTracker"
@ -219,78 +71,10 @@
"badge": "img/emojis/books.png",
"message": "GridTracker Documentation"
},
"N3TQM": {
"badge": "img/emojis/money-bag.png",
"message": "GridTracker Donor"
},
"N3UGI": {
"badge": "img/emojis/money-bag.png",
"message": "GridTracker Donor"
},
"N4MCC": {
"badge": "img/emojis/money-bag.png",
"message": "GridTracker Donor"
},
"N6GEB": {
"badge": "img/emojis/money-bag.png",
"message": "GridTracker Donor"
},
"N7HQ": {
"badge": "img/emojis/money-bag.png",
"message": "GridTracker Donor"
},
"NR0Q": {
"badge": "img/emojis/coffee.png",
"message": "GridTracker Developer"
},
"OH1LEU": {
"badge": "img/emojis/money-bag.png",
"message": "GridTracker Donor"
},
"OH3NZW": {
"badge": "img/emojis/money-bag.png",
"message": "GridTracker Donor"
},
"ON7IVE": {
"badge": "img/emojis/money-bag.png",
"message": "GridTracker Donor"
},
"OZ1LNR": {
"badge": "img/emojis/money-bag.png",
"message": "GridTracker Donor"
},
"OZ8QI": {
"badge": "img/emojis/money-bag.png",
"message": "GridTracker Donor"
},
"PA0LMA": {
"badge": "img/emojis/money-bag.png",
"message": "GridTracker Donor"
},
"VA7CND": {
"badge": "img/emojis/money-bag.png",
"message": "GridTracker Donor"
},
"VE3FMQ": {
"badge": "img/emojis/money-bag.png",
"message": "GridTracker Donor"
},
"VE7LGP": {
"badge": "img/emojis/money-bag.png",
"message": "GridTracker Donor"
},
"W0SP": {
"badge": "img/emojis/money-bag.png",
"message": "GridTracker Donor"
},
"W0YRE": {
"badge": "img/emojis/money-bag.png",
"message": "GridTracker Donor"
},
"W4DHK": {
"badge": "img/emojis/money-bag.png",
"message": "GridTracker Donor"
},
"W4IPA": {
"badge": "img/emojis/beer-mug.png",
"message": "GridTracker Tester"
@ -299,36 +83,8 @@
"badge": "img/emojis/pizza.png",
"message": "GridTracker Tester"
},
"W6FVO": {
"badge": "img/emojis/money-bag.png",
"message": "GridTracker Donor"
},
"W9LL": {
"badge": "img/emojis/money-bag.png",
"message": "GridTracker Donor"
},
"W9VZR": {
"badge": "img/emojis/money-bag.png",
"message": "GridTracker Donor"
},
"WA4YA": {
"badge": "img/emojis/trophy.png",
"message": "GridTracker Developer"
},
"WA6JQB": {
"badge": "img/emojis/money-bag.png",
"message": "GridTracker Donor"
},
"WB6RJH": {
"badge": "img/emojis/money-bag.png",
"message": "GridTracker Donor"
},
"WD5FBW": {
"badge": "img/emojis/money-bag.png",
"message": "GridTracker Donor"
},
"WS4S": {
"badge": "img/emojis/money-bag.png",
"message": "GridTracker Donor"
}
}

Wyświetl plik

@ -31878,6 +31878,7 @@
"=NH6MG",
"=NH6NG",
"=NH6NS",
"=NH6PK",
"=NH6QR",
"=NH6R",
"=NH6RG",
@ -43922,6 +43923,31 @@
"worked_modes": {},
"confirmed_modes": {}
},
"390": {
"dxcc": "0",
"cc": "-",
"ccc": "-",
"name": "None",
"continent": "-",
"ituzone": ["-"],
"cqzone": ["-"],
"timezone": "1",
"ccode": "-",
"aname": "None",
"mh": [],
"prefix": [],
"worked": false,
"confirmed": false,
"flag": "un.png",
"pp": "-",
"lat": 0.0,
"lon": 0.0,
"geo": "deleted",
"worked_bands": {},
"confirmed_bands": {},
"worked_modes": {},
"confirmed_modes": {}
},
"-1": {
"dxcc": "-1",
"cc": "-",

Wyświetl plik

@ -22,6 +22,15 @@
<script src="./lib/protos.js" type="text/javascript"></script>
<script src="./lib/third-party.js" type="text/javascript"></script>
<script src="./lib/roster.js" type="text/javascript"></script>
<script src="./lib/roster/prepareRosterSettings.js" type="text/javascript"></script>
<script src="./lib/roster/processRosterFiltering.js" type="text/javascript"></script>
<script src="./lib/roster/processRosterHunting.js" type="text/javascript"></script>
<script src="./lib/roster/renderCompactRoster.js" type="text/javascript"></script>
<script src="./lib/roster/renderNormalRoster.js" type="text/javascript"></script>
<script src="./lib/roster/renderRoster.js" type="text/javascript"></script>
<script src="./lib/roster/rosterColumns.js" type="text/javascript"></script>
<script src="./lib/roster/rosterColumnFunctions.js" type="text/javascript"></script>
<script src="./lib/roster/sendAlerts.js" type="text/javascript"></script>
<script src="./lib/screens.js"></script>
</head>
<body onload="init()" class="roster" oncontextmenu="return handleContextMenu(event);">

Plik binarny nie jest wyświetlany.

Plik binarny nie jest wyświetlany.

Wyświetl plik

@ -1,4 +1,4 @@
// GridTracker Copyright © 2021 GridTracker.org
// GridTracker Copyright © 2022 GridTracker.org
// All rights reserved.
// See LICENSE for more information.
@ -86,36 +86,6 @@ function onAdiLoadComplete(adiBuffer, saveAdifFile, adifFileName, newFile)
{
let finalMode = "";
let appLoTW_RXQSO = findAdiField(
activeAdifArray[x],
"APP_LoTW_RXQSO"
);
if (appLoTW_RXQSO != "")
{
let dRXQSO = Date.parse(appLoTW_RXQSO);
let dLastLOTW_QSO = Date.parse(g_adifLogSettings.lastFetch.lotw_qso);
if ((isNaN(dRXQSO) == false) && (isNaN(dLastLOTW_QSO) == false) && (dRXQSO > dLastLOTW_QSO))
{
g_adifLogSettings.lastFetch.lotw_qso = appLoTW_RXQSO;
}
}
let appLoTW_RXQSL = findAdiField(
activeAdifArray[x],
"APP_LoTW_RXQSL"
);
if (appLoTW_RXQSL != "")
{
let dRXQSL = Date.parse(appLoTW_RXQSL);
let dLastLOTW_QSL = Date.parse(g_adifLogSettings.lastFetch.lotw_qsl);
if ((isNaN(dRXQSL) == false) && (isNaN(dLastLOTW_QSL) == false) && (dRXQSL > dLastLOTW_QSL))
{
g_adifLogSettings.lastFetch.lotw_qsl = appLoTW_RXQSL;
}
}
if (activeAdifArray[x].length > 3)
{
if (activeAdifLogMode)
@ -1668,7 +1638,7 @@ function sendTcpMessage(msg, length, port, address)
client.setTimeout(30000);
client.connect(port, address, function ()
{
client.write(msg);
client.write(Buffer.from(msg, "utf-8"));
});
client.on("close", function () {});
@ -1677,7 +1647,7 @@ function sendTcpMessage(msg, length, port, address)
function valueToAdiField(field, value)
{
var adi = "<" + field + ":";
adi += String(value).length + ">";
adi += Buffer.byteLength(String(value)) + ">";
adi += String(value) + " ";
return adi;
}
@ -1957,7 +1927,7 @@ function finishSendingReport(record, localMode)
for (let key in record)
{
report += "<" + key + ":" + record[key].length + ">" + record[key] + " ";
report += "<" + key + ":" + Buffer.byteLength(record[key]) + ">" + record[key] + " ";
}
report += "<EOR>";
@ -2139,7 +2109,7 @@ function finishSendingReport(record, localMode)
for (var key in record)
{
report +=
"<" + key + ":" + record[key].length + ">" + record[key] + " ";
"<" + key + ":" + Buffer.byteLength(record[key]) + ">" + record[key] + " ";
}
report += "<EOR>";
}

Wyświetl plik

@ -1,4 +1,4 @@
// GridTracker Copyright © 2021 GridTracker.org
// GridTracker Copyright © 2022 GridTracker.org
// All rights reserved.
// See LICENSE for more information.

Wyświetl plik

@ -1,4 +1,4 @@
// GridTracker Copyright © 2021 GridTracker.org
// GridTracker Copyright © 2022 GridTracker.org
// All rights reserved.
// See LICENSE for more information.
@ -279,7 +279,7 @@ function oqrsDownload(fromSettings)
{
oqrsUpdatedTd.innerHTML = "<b><i>Downloading...</i></b>";
getBuffer(
"http://app.gridtracker.org/callsigns/clublog.json",
"https://storage.googleapis.com/gt_app/callsigns/clublog.json",
processoqrsCallsigns,
null,
"http",
@ -539,7 +539,7 @@ function ulsDownload()
ulsUpdatedTd.innerHTML = "<b><i>Downloading...</i></b>";
ulsCountTd.innerHTML = 0;
getChunkedBuffer(
"http://app.gridtracker.org/callsigns/callsigns.txt",
"https://storage.googleapis.com/gt_app/callsigns/callsigns.txt",
processulsCallsigns,
null,
"http",

Wyświetl plik

@ -1,3 +1,9 @@
// FIXME ****************************************************************************** //
// The datepicker's "Time" section doesn't work. This really needs to be fixed before
// the next big RTTY Roundup or Field Day where there may be a lot of hams that want
// to use this feature to only reference their log starting when the contest starts.
// Which isn't always 00:00 UTC.
// ************************************************************************************ //
var picker = {
attach: function (opt)
{

Wyświetl plik

@ -1,265 +1,266 @@
var validSettings = [
"HRDLogbookLogSettings",
"N1MMSettings",
"acLogSettings",
"adifLogSettings",
"alertSettings",
"appSettings",
"audioSettings",
"awardTracker",
"bandActivity",
"blockedCQ",
"blockedCalls",
"blockedDxcc",
"callsignLookups",
"classicAlerts",
"classicAlertsVersion",
"currentVersion",
"dxkLogSettings",
"log4OMSettings",
"mapMemory",
"mapSettings",
"msgSettings",
"receptionSettings",
"rosterSettings",
"savedAlerts",
"speechSettings",
"startupLogs",
"trustedQslSettings",
"screenSettings",
"legendColors"
];
var def_appSettings = {
alertMute: 0,
rosterAlwaysOnTop: false,
centerGridsquare: "",
chatUUID: "",
crScript: 0,
distanceUnit: "MI",
earthImgSrc: 0,
gridViewMode: 3,
gridsquareDecayTime: 300,
gtAgree: "",
gtBandFilter: "",
gtFlagImgSrc: 0,
gtModeFilter: "",
gtPropFilter: "mixed",
gtMsgEnable: true,
gtShareEnable: true,
heatEnabled: 0,
loadAdifAtStartup: false,
lookupLoginCq: "",
lookupLoginQrz: "",
lookupLoginQth: "",
lookupOnTx: false,
lookupCloseLog: false,
lookupMerge: true,
lookupMissingGrid: false,
lookupPasswordCq: "",
lookupPasswordQrz: "",
lookupPasswordQth: "",
lookupService: "CALLOOK",
lookupCallookPreferred: false,
moonPath: 0,
moonTrack: 0,
mouseTrack: 0,
multicast: false,
myBand: "OOB",
myDEGrid: "",
myDEcall: "NOCALL",
myMode: "",
myRawCall: "NOCALL",
myRawFreq: "",
myRawGrid: "",
pathWidthWeight: 1.0,
pushPinMode: false,
qrzPathWidthWeight: 1.2,
sixWideMode: 0,
savedAppData: null,
soundCard: "default",
spotsEnabled: 0,
stopAskingVersion: false,
useLocalTime: 0,
wsjtForwardUdpEnable: false,
wsjtForwardUdpIp: "127.0.0.1",
wsjtForwardUdpPort: 2238,
wsjtIP: "",
wsjtUdpPort: 0,
workingCallsignEnable: false,
workingCallsigns: {},
workingDateEnable: false,
workingDate: 0,
gtSpotEnable: true
};
var def_mapSettings = {
animate: true,
animateSpeed: 4,
CQhilite: true,
fitQRZ: false,
focusRig: true,
gridAlpha: 136,
haltAllOnTx: true,
legend: true,
longitude: 0.0,
latitude: 0.0,
loudness: 1,
mapIndex: 19,
mergeOverlay: false,
mouseOver: true,
nightLoudness: 0.8,
nightMapEnable: false,
nightMapIndex: 20,
nightPathColor: 361,
nightQrzPathColor: 1,
offlineMode: false,
pathColor: 0,
qrzDxccFallback: false,
qrzPathColor: 1,
rosterTime: 120,
shadow: 0.1,
splitQSL: true,
strikes: false,
strikesAlert: 2,
strikesGlobal: false,
strikesNotify: false,
trafficDecode: true,
usNexrad: false,
zoom: 4,
mapTrans: 0.5
};
var def_adifLogSettings = {
menu: {
buttonAdifCheckBox: false,
buttonClubCheckBox: false,
buttonLOTWCheckBox: false,
buttonQRZCheckBox: false,
buttonPsk24CheckBox: true
},
startup: {
loadAdifCheckBox: false,
loadPsk24CheckBox: false,
loadQRZCheckBox: false,
loadLOTWCheckBox: false,
loadClubCheckBox: false,
loadGTCheckBox: true
},
qsolog: {
logQRZqsoCheckBox: false,
logGTqsoCheckBox: true,
logLOTWqsoCheckBox: false,
logHRDLOGqsoCheckBox: false,
logClubqsoCheckBox: false,
logCloudlogQSOCheckBox: false,
logeQSLQSOCheckBox: false
},
nickname: {
nicknameeQSLCheckBox: false
},
text: {
lotwLogin: "",
clubCall: "",
clubEmail: "",
clubPassword: "",
lotwPassword: "",
lotwTrusted: "",
lotwStation: "",
qrzApiKey: "",
HRDLOGCallsign: "",
HRDLOGUploadCode: "",
CloudlogURL: "http://127.0.0.1/index.php/api/qso",
CloudlogAPI: "",
eQSLUser: "",
eQSLPassword: "",
eQSLNickname: ""
},
downloads: {},
lastFetch: {
lotw_qso: "1970-01-01",
lotw_qsl: "1970-01-01"
}
};
var def_msgSettings = {
msgAlertSelect: 1,
msgAlertWord: "New chat message",
msgAlertMedia: "none",
msgFrequencySelect: 0,
msgActionSelect: 1,
msgAwaySelect: 0,
msgAwayText: "I am away from the shack at the moment"
};
var def_receptionSettings = {
lastSequenceNumber: "0", // Treat as a string, it's friggin big
lastDownloadTimeSec: 0,
viewHistoryTimeSec: 900,
viewPaths: false,
pathColor: -1,
pathNightColor: 361,
spotWidth: 0.8,
mergeSpots: true
};
var def_N1MMSettings = {
enable: false,
port: 2333,
ip: "127.0.0.1"
};
var def_log4OMSettings = {
enable: false,
port: 2236,
ip: "127.0.0.1"
};
var def_dxkLogSettings = {
enable: false,
port: 52000,
ip: "127.0.0.1"
};
var def_HRDLogbookLogSettings = {
enable: false,
port: 7826,
ip: "127.0.0.1"
};
var def_acLogSettings = {
enable: false,
port: 1100,
ip: "127.0.0.1"
};
var def_trustedQslSettings = {
stationFile: "",
stationFileValid: false,
binaryFile: "",
binaryFileValid: false
};
var def_callsignLookups = {
lotwUseEnable: true,
lotwWeeklyEnable: true,
lotwLastUpdate: 0,
eqslUseEnable: true,
eqslWeeklyEnable: true,
eqslLastUpdate: 0,
ulsUseEnable: true,
ulsWeeklyEnable: true,
ulsLastUpdate: 0,
oqrsUseEnable: false,
oqrsWeeklyEnable: false,
oqrsLastUpdate: 0
};
var def_bandActivity = {
lastUpdate: {},
lines: {}
};
var def_legendColors = {
QSO: "#EEEE00",
QSL: "#EE0000",
QSX: "#1111EE",
CQ: "#00FF00",
CQDX: "#00FFFF",
QRZ: "#FFFF00",
QTH: "#FFA600"
};
var validSettings = [
"HRDLogbookLogSettings",
"N1MMSettings",
"acLogSettings",
"adifLogSettings",
"alertSettings",
"appSettings",
"audioSettings",
"awardTracker",
"bandActivity",
"blockedCQ",
"blockedCalls",
"blockedDxcc",
"callsignLookups",
"classicAlerts",
"classicAlertsVersion",
"currentVersion",
"dxkLogSettings",
"log4OMSettings",
"mapMemory",
"mapSettings",
"msgSettings",
"receptionSettings",
"rosterSettings",
"savedAlerts",
"speechSettings",
"startupLogs",
"trustedQslSettings",
"screenSettings",
"legendColors"
];
var def_appSettings = {
alertMute: 0,
rosterAlwaysOnTop: false,
centerGridsquare: "",
chatUUID: "",
crScript: 0,
distanceUnit: "MI",
earthImgSrc: 0,
gridViewMode: 3,
gridsquareDecayTime: 300,
gtAgree: "",
gtBandFilter: "",
gtFlagImgSrc: 0,
gtModeFilter: "",
gtPropFilter: "mixed",
gtMsgEnable: true,
gtShareEnable: true,
heatEnabled: 0,
loadAdifAtStartup: false,
lookupLoginCq: "",
lookupLoginQrz: "",
lookupLoginQth: "",
lookupOnTx: false,
lookupCloseLog: false,
lookupMerge: true,
lookupMissingGrid: false,
lookupPasswordCq: "",
lookupPasswordQrz: "",
lookupPasswordQth: "",
lookupService: "CALLOOK",
lookupCallookPreferred: false,
clearRosterOnBandChange: false,
moonPath: 0,
moonTrack: 0,
mouseTrack: 0,
multicast: false,
myBand: "OOB",
myDEGrid: "",
myDEcall: "NOCALL",
myMode: "",
myRawCall: "NOCALL",
myRawFreq: "",
myRawGrid: "",
pathWidthWeight: 1.0,
pushPinMode: false,
qrzPathWidthWeight: 1.2,
sixWideMode: 0,
savedAppData: null,
soundCard: "default",
spotsEnabled: 0,
stopAskingVersion: false,
useLocalTime: 0,
wsjtForwardUdpEnable: false,
wsjtForwardUdpIp: "127.0.0.1",
wsjtForwardUdpPort: 2238,
wsjtIP: "",
wsjtUdpPort: 0,
workingCallsignEnable: false,
workingCallsigns: {},
workingDateEnable: false,
workingDate: 0,
gtSpotEnable: true
};
var def_mapSettings = {
animate: true,
animateSpeed: 4,
CQhilite: true,
fitQRZ: false,
focusRig: true,
gridAlpha: 136,
haltAllOnTx: true,
legend: true,
longitude: 0.0,
latitude: 0.0,
loudness: 1,
mapIndex: 19,
mergeOverlay: false,
mouseOver: true,
nightLoudness: 0.8,
nightMapEnable: false,
nightMapIndex: 20,
nightPathColor: 361,
nightQrzPathColor: 1,
offlineMode: false,
pathColor: 0,
qrzDxccFallback: false,
qrzPathColor: 1,
rosterTime: 120,
shadow: 0.1,
splitQSL: true,
strikes: false,
strikesAlert: 2,
strikesGlobal: false,
strikesNotify: false,
trafficDecode: true,
usNexrad: false,
zoom: 4,
mapTrans: 0.5
};
var def_adifLogSettings = {
menu: {
buttonAdifCheckBox: false,
buttonClubCheckBox: false,
buttonLOTWCheckBox: false,
buttonQRZCheckBox: false,
buttonPsk24CheckBox: true
},
startup: {
loadAdifCheckBox: false,
loadPsk24CheckBox: false,
loadQRZCheckBox: false,
loadLOTWCheckBox: false,
loadClubCheckBox: false,
loadGTCheckBox: true
},
qsolog: {
logQRZqsoCheckBox: false,
logGTqsoCheckBox: true,
logLOTWqsoCheckBox: false,
logHRDLOGqsoCheckBox: false,
logClubqsoCheckBox: false,
logCloudlogQSOCheckBox: false,
logeQSLQSOCheckBox: false
},
nickname: {
nicknameeQSLCheckBox: false
},
text: {
lotwLogin: "",
clubCall: "",
clubEmail: "",
clubPassword: "",
lotwPassword: "",
lotwTrusted: "",
lotwStation: "",
qrzApiKey: "",
HRDLOGCallsign: "",
HRDLOGUploadCode: "",
CloudlogURL: "http://127.0.0.1/index.php/api/qso",
CloudlogAPI: "",
eQSLUser: "",
eQSLPassword: "",
eQSLNickname: ""
},
downloads: {},
lastFetch: {
lotw_qso: "1970-01-01",
lotw_qsl: "1970-01-01"
}
};
var def_msgSettings = {
msgAlertSelect: 1,
msgAlertWord: "New chat message",
msgAlertMedia: "none",
msgFrequencySelect: 0,
msgActionSelect: 1,
msgAwaySelect: 0,
msgAwayText: "I am away from the shack at the moment"
};
var def_receptionSettings = {
lastSequenceNumber: "0", // Treat as a string, it's friggin big
lastDownloadTimeSec: 0,
viewHistoryTimeSec: 900,
viewPaths: false,
pathColor: -1,
pathNightColor: 361,
spotWidth: 0.8,
mergeSpots: true
};
var def_N1MMSettings = {
enable: false,
port: 2333,
ip: "127.0.0.1"
};
var def_log4OMSettings = {
enable: false,
port: 2236,
ip: "127.0.0.1"
};
var def_dxkLogSettings = {
enable: false,
port: 52000,
ip: "127.0.0.1"
};
var def_HRDLogbookLogSettings = {
enable: false,
port: 7826,
ip: "127.0.0.1"
};
var def_acLogSettings = {
enable: false,
port: 1100,
ip: "127.0.0.1"
};
var def_trustedQslSettings = {
stationFile: "",
stationFileValid: false,
binaryFile: "",
binaryFileValid: false
};
var def_callsignLookups = {
lotwUseEnable: true,
lotwWeeklyEnable: true,
lotwLastUpdate: 0,
eqslUseEnable: true,
eqslWeeklyEnable: true,
eqslLastUpdate: 0,
ulsUseEnable: true,
ulsWeeklyEnable: true,
ulsLastUpdate: 0,
oqrsUseEnable: false,
oqrsWeeklyEnable: false,
oqrsLastUpdate: 0
};
var def_bandActivity = {
lastUpdate: {},
lines: {}
};
var def_legendColors = {
QSO: "#EEEE00",
QSL: "#EE0000",
QSX: "#1111EE",
CQ: "#00FF00",
CQDX: "#00FFFF",
QRZ: "#FFFF00",
QTH: "#FFA600"
};

Wyświetl plik

@ -1,8 +1,9 @@
// GridTracker Copyright © 2021 GridTracker.org
// GridTracker Copyright © 2022 GridTracker.org
// All rights reserved.
// See LICENSE for more information.
const pjson = require("./package.json");
var gtVersion = parseInt(pjson.version.replace(/\./g, ""));
var gtVersionStr = pjson.version
var gtVersion = parseInt(gtVersionStr.replace(/\./g, ""));
var gtBeta = pjson.betaVersion;
var g_startVersion = 0;
@ -116,14 +117,7 @@ function loadAllSettings()
def_adifLogSettings
);
g_msgSettings = loadDefaultsAndMerge("msgSettings", def_msgSettings);
// one-time override of oams pop-up messages: if pop-ups disabled
// and new version, reset msgActionSelect to 1 (pop up)
if (g_msgSettings.msgActionSelect == 0 &&
String(gtVersion) != String(g_startVersion))
{
g_msgSettings.msgActionSelect = 1;
localStorage.msgSettings = JSON.stringify(g_msgSettings);
}
g_receptionSettings = loadDefaultsAndMerge(
"receptionSettings",
def_receptionSettings
@ -1098,7 +1092,11 @@ function addDeDx(
details.grid.length < 6 &&
(details.grid.substr(0, 4) == finalGrid.substr(0, 4) ||
details.grid.length == 0)
) { details.grid = finalGrid; }
)
{
details.grid = finalGrid;
details.grid4 = finalGrid.substr(0, 4);
}
}
if (finalRSTsent.length > 0) details.RSTsent = finalRSTsent;
if (finalRSTrecv.length > 0) details.RSTrecv = finalRSTrecv;
@ -1118,6 +1116,7 @@ function addDeDx(
{
details = {};
details.grid = finalGrid;
details.grid4 = finalGrid.length > 0 ? finalGrid.substr(0, 4) : "-";
details.RSTsent = finalRSTsent;
details.RSTrecv = finalRSTrecv;
details.msg = "-";
@ -1159,10 +1158,9 @@ function addDeDx(
finalGrid.length > 0
)
{
var fourGrid = finalGrid.substr(0, 4);
if (fourGrid in g_gridToState && g_gridToState[fourGrid].length == 1)
if (details.grid4 in g_gridToState && g_gridToState[details.grid4].length == 1)
{
details.state = g_gridToState[fourGrid][0];
details.state = g_gridToState[details.grid4][0];
}
lookupCall = true;
}
@ -3108,30 +3106,23 @@ function makeTitleInfo(mapWindow)
? myMode
: g_appSettings.gtModeFilter;
var space = " ";
var news = "GridTracker [Band: " + band + " Mode: " + mode;
var news = `GridTracker ${gtVersionStr} [Band: ${band} Mode: ${mode}`;
var end = "]";
if (mapWindow)
{
news += " Layer: " + g_viewInfo[g_currentOverlay][1];
news += ` Layer: ${g_viewInfo[g_currentOverlay][1]}`;
}
if (g_currentOverlay == 0 && g_appSettings.gridViewMode == 1) { return news + end; }
var workline =
" - Worked " +
g_viewInfo[g_currentOverlay][2] +
" Confirmed " +
g_viewInfo[g_currentOverlay][3];
var workline = ` - Worked ${g_viewInfo[g_currentOverlay][2]} Confirmed ${g_viewInfo[g_currentOverlay][3]}`
if (
g_viewInfo[g_currentOverlay][2] <= g_viewInfo[g_currentOverlay][4] &&
g_viewInfo[g_currentOverlay][4] > 0
)
{
end =
" Needed " +
(g_viewInfo[g_currentOverlay][4] - g_viewInfo[g_currentOverlay][2]) +
"]";
end = ` Needed ${(g_viewInfo[g_currentOverlay][4] - g_viewInfo[g_currentOverlay][2])}]`;
}
return news + workline + end;
}
@ -10112,7 +10103,7 @@ function renderStatsBox()
worker +=
"<br/> In Section: " +
scoreSection +
"<br/>Error Generating Stats<br/>Please take a screenshot and send to gridtracker@gmail.com";
"<br/>Error Generating Stats<br/>Please take a screenshot and send to team@gridtracker.org";
}
setStatsDiv("statViewDiv", worker);
@ -11183,7 +11174,7 @@ function checkForNewVersion(showUptoDate)
if (typeof nw != "undefined")
{
getBuffer(
"http://app.gridtracker.org/version.txt?lang=",
"https://storage.googleapis.com/gt_app/version.txt",
versionCheck,
showUptoDate,
"http",
@ -11197,20 +11188,15 @@ function downloadAcknowledgements()
if (g_mapSettings.offlineMode == false)
{
getBuffer(
"http://app.gridtracker.org/acknowledgements.json",
"https://storage.googleapis.com/gt_app/acknowledgements.json",
updateAcks,
null,
"http",
80
);
}
}
function checkForNewAcknowledgements()
{
downloadAcknowledgements();
setTimeout(checkForNewAcknowledgements, 8640000);
readAcksFromDisk();
setTimeout(downloadAcknowledgements, 8640000);
}
}
function renderBandActivity()
@ -11352,7 +11338,13 @@ function pskBandActivityCallback(buffer, flag)
renderBandActivity();
}
/* FIXME ******************************************************************************
Should we somewhere in settings, have a checkbox to enable / disable PSK spots
specifically? We can disable the overall spots, both PSK and OAMS, and OAMS has a
checkbox in the OAMS tab. I'm thinking for the situation where I only want to
pull in OAMS spots and not PSK reporter's spots.
************************************************************************************
*/
function pskGetBandActivity()
{
if (g_mapSettings.offlineMode == true) return;
@ -11616,14 +11608,7 @@ function updateBasedOnIni()
{
if (typeof nw != "undefined")
{
// lets see if we can find our location the hard way
getBuffer(
"https://api.ipstack.com/check?access_key=8c9233ec1c09861a707951ab3718a7f6&format=1",
ipLocation,
null,
"https",
443
);
alert("Location not available!\nEither start WSJT-X/JTDX or enter your grid square in the settings ");
}
}
}
@ -12101,27 +12086,6 @@ function selectElementContents(el)
}
}
function ipLocation(buffer, flag)
{
var obj = JSON.parse(buffer);
if (
typeof obj != "undefined" &&
obj != null &&
typeof obj.latitude != "undefined"
)
{
g_appSettings.centerGridsquare = latLonToGridSquare(
obj.latitude,
obj.longitude
).substr(0, 6);
if (g_appSettings.centerGridsquare.length > 0)
{
homeQTHInput.value = g_appSettings.centerGridsquare;
if (ValidateGridsquare(homeQTHInput, null)) setCenterGridsquare();
}
}
}
function popupNewWindows()
{
if (typeof nw != "undefined")
@ -12179,7 +12143,7 @@ function callsignToDxcc(insign)
{
if (parts[end].toUpperCase() == "MM")
{
return -1;
return 0;
}
parts.pop();
end = parts.length - 1;
@ -12766,8 +12730,7 @@ function updateAcks(buffer)
{
try
{
g_acks = JSON.parse(buffer);
fs.writeFileSync(g_NWappData + "acknowledgements.json", JSON.stringify(g_acks));
g_acknowledgedCalls = JSON.parse(buffer);
}
catch (e)
{
@ -13004,6 +12967,7 @@ function loadMapSettings()
focusRigValue.checked = g_mapSettings.focusRig;
haltAllOnTxValue.checked = g_mapSettings.haltAllOnTx;
strikesAlert.value = g_mapSettings.strikesAlert;
clearRosterOnBandChange.checked = g_appSettings.clearRosterOnBandChange;
setStrikesButton();
@ -14435,6 +14399,11 @@ function loadLookupDetails()
else lookupCredentials.style.display = "block";
}
function clearRosterOnBandChangeValueChanged(what)
{
g_appSettings.clearRosterOnBandChange = clearRosterOnBandChange.checked;
}
function lookupValueChanged(what)
{
if (g_appSettings.lookupService != lookupService.value)
@ -14630,6 +14599,7 @@ function callookResults(buffer, gridPass)
callObject.lat = results.location.latitude;
callObject.lon = results.location.longitude;
callObject.grid = results.location.gridsquare;
callObject.grid4 = callObject.grid.length > 1 ? callObject.grid.substr(0, 4) : "-";
callObject.efdate = results.otherInfo.grantDate;
callObject.expdate = results.otherInfo.expiryDate;
callObject.frn = results.otherInfo.frn;

Wyświetl plik

@ -1,4 +1,4 @@
// GridTracker Copyright © 2021 GridTracker.org
// GridTracker Copyright © 2022 GridTracker.org
// All rights reserved.
// See LICENSE for more information.

Wyświetl plik

@ -1,4 +1,4 @@
// GridTracker Copyright © 2021 GridTracker.org
// GridTracker Copyright © 2022 GridTracker.org
// All rights reserved.
// See LICENSE for more information.
@ -129,6 +129,27 @@ Number.prototype.toDHMS = function ()
return val;
};
Number.prototype.toDHMS15 = function ()
{
// round to earliest 15 seconds
var seconds = Math.floor(this / 15) * 15;
var days = Math.floor(seconds / (3600 * 24));
seconds -= days * 3600 * 24;
var hrs = Math.floor(seconds / 3600);
seconds -= hrs * 3600;
var mnts = Math.floor(seconds / 60);
seconds -= mnts * 60;
days = days ? days + "d " : "";
hrs = hrs ? hrs + "h " : "";
mnts = mnts ? mnts + "m " : "";
var first = days + hrs + mnts;
if (first == "") val = seconds + "s";
else val = first + (seconds > 0 ? seconds + "s" : "");
return val;
};
Number.prototype.toDHM = function ()
{
var seconds = this;
@ -141,8 +162,10 @@ Number.prototype.toDHM = function ()
days = days ? days + "d " : "";
hrs = hrs ? hrs + "h " : "";
mnts = mnts ? mnts + "m " : "";
mnts = mnts || seconds ? mnts + "m " : "";
val = days + hrs + mnts;
if (val == "") val = "0m";
return val;
};

Plik diff jest za duży Load Diff

Wyświetl plik

@ -0,0 +1,83 @@
function prepareRosterSettings()
{
let rosterSettings = {
bands: {},
modes: {},
callMode: g_rosterSettings.callsign,
onlyHits: false,
isAwardTracker: false,
now: timeNowSec()
}
if (rosterSettings.callMode == "hits")
{
rosterSettings.callMode = "all"
rosterSettings.onlyHits = true;
}
if (referenceNeed.value == LOGBOOK_AWARD_TRACKER)
{
rosterSettings.callMode = "all";
rosterSettings.onlyHits = false;
rosterSettings.isAwardTracker = true;
g_rosterSettings.huntNeed = "confirmed";
}
// this appears to be determine if we should show the OAMS column
// if the user is not in offline mode and has OAMS enabled, this could
// be it's own function maybe?
rosterSettings.canMsg =
window.opener.g_mapSettings.offlineMode == false &&
window.opener.g_appSettings.gtShareEnable == "true" &&
window.opener.g_appSettings.gtMsgEnable == "true";
// The following 3 sections deal with QSLing, do we break them out
// individually or lump them into a qslUser function that sets
// all three at the same time?
// this section is for LoTW users, can be a function
if (window.opener.g_callsignLookups.lotwUseEnable == true)
{
usesLoTWDiv.style.display = "";
if (g_rosterSettings.usesLoTW == true)
{
maxLoTW.style.display = "";
maxLoTWView.style.display = "";
}
else
{
maxLoTW.style.display = "none";
maxLoTWView.style.display = "none";
}
}
else
{
usesLoTWDiv.style.display = "none";
maxLoTW.style.display = "none";
maxLoTWView.style.display = "none";
}
if (g_rosterSettings.huntNeed == "mixed")
{
rosterSettings.huntIndex = g_confirmed;
rosterSettings.workedIndex = g_worked;
rosterSettings.layeredMode = LAYERED_MODE_FOR[String(g_rosterSettings.reference)];
}
else if (g_rosterSettings.huntNeed == "worked")
{
rosterSettings.huntIndex = g_worked;
rosterSettings.workedIndex = false;
rosterSettings.layeredMode = false;
}
else if (g_rosterSettings.huntNeed == "confirmed")
{
rosterSettings.huntIndex = g_confirmed;
rosterSettings.workedIndex = g_worked;
rosterSettings.layeredMode = false;
}
else
{
rosterSettings.huntIndex = false;
rosterSettings.workedIndex = false;
rosterSettings.layeredMode = false;
}
return rosterSettings
}

Wyświetl plik

@ -0,0 +1,384 @@
function processRosterFiltering(callRoster, rosterSettings)
{
// First loop, exclude calls, mostly based on "Exceptions" settings
// this whole section is full of individual if's that could be broken out
for (let callHash in callRoster)
{
let entry = callRoster[callHash];
let callObj = entry.callObj;
let call = entry.DEcall;
entry.tx = true;
callObj.shouldAlert = false;
callObj.reason = Array();
callObj.awardReason = "Callsign";
if (rosterSettings.now - callObj.age > window.opener.g_mapSettings.rosterTime)
{
entry.tx = false;
entry.alerted = false;
callObj.qrz = false;
callObj.reset = true;
continue;
}
if (!callObj.dxcc || callObj.dxcc == -1)
{
entry.tx = false;
continue;
}
if (window.opener.g_instances[callObj.instance].crEnable == false)
{
entry.tx = false;
continue;
}
if (call in g_blockedCalls)
{
entry.tx = false;
continue;
}
if (
entry.DXcall + " from All" in g_blockedCQ ||
entry.DXcall + " from " + window.opener.g_dxccToAltName[callObj.dxcc] in g_blockedCQ
)
{
entry.tx = false;
continue;
}
if (callObj.ituza in g_blockedITUz)
{
entry.tx = false;
continue;
}
if (callObj.cqza in g_blockedCQz)
{
entry.tx = false;
continue;
}
if (callObj.dxcc in g_blockedDxcc)
{
entry.tx = false;
continue;
}
if (g_rosterSettings.cqOnly == true && callObj.CQ == false)
{
entry.tx = false;
continue;
}
if (g_rosterSettings.useRegex && g_rosterSettings.callsignRegex.length > 0)
{
try
{
if (!call.match(g_rosterSettings.callsignRegex))
{
entry.tx = false;
continue;
}
}
catch (e) {}
}
if (g_rosterSettings.requireGrid == true && callObj.grid.length != 4)
{
entry.tx = false;
continue;
}
if (g_rosterSettings.wantMinDB == true && entry.message.SR < g_rosterSettings.minDb)
{
entry.tx = false;
continue;
}
if (g_rosterSettings.wantMaxDT == true && Math.abs(entry.message.DT) > g_rosterSettings.maxDT)
{
entry.tx = false;
continue;
}
if (g_rosterSettings.wantMinFreq == true && entry.message.DF < g_rosterSettings.minFreq)
{
entry.tx = false;
continue;
}
if (g_rosterSettings.wantMaxFreq == true && entry.message.DF > g_rosterSettings.maxFreq)
{
entry.tx = false;
continue;
}
if (g_rosterSettings.noMsg == true)
{
try
{
if (callObj.msg.match(g_rosterSettings.noMsgValue))
{
entry.tx = false;
continue;
}
}
catch (e) {}
}
if (g_rosterSettings.onlyMsg == true)
{
try
{
if (!callObj.msg.match(g_rosterSettings.onlyMsgValue))
{
entry.tx = false;
continue;
}
}
catch (e) {}
}
if (callObj.dxcc == window.opener.g_myDXCC)
{
if (g_rosterSettings.noMyDxcc == true)
{
entry.tx = false;
continue;
}
}
else
{
if (g_rosterSettings.onlyMyDxcc == true)
{
entry.tx = false;
continue;
}
}
if (window.opener.g_callsignLookups.lotwUseEnable == true && g_rosterSettings.usesLoTW == true)
{
if (!(call in window.opener.g_lotwCallsigns))
{
entry.tx = false;
continue;
}
if (g_rosterSettings.maxLoTW < 27)
{
let months = (g_day - window.opener.g_lotwCallsigns[call]) / 30;
if (months > g_rosterSettings.maxLoTW)
{
entry.tx = false;
continue;
}
}
}
if (window.opener.g_callsignLookups.eqslUseEnable == true && g_rosterSettings.useseQSL == true)
{
if (!(call in window.opener.g_eqslCallsigns))
{
entry.tx = false;
continue;
}
}
if (window.opener.g_callsignLookups.oqrsUseEnable == true && g_rosterSettings.usesOQRS == true)
{
if (!(call in window.opener.g_oqrsCallsigns))
{
entry.tx = false;
continue;
}
}
if (rosterSettings.callMode != "all")
{
if (entry.DXcall == "CQ DX" && callObj.dxcc == window.opener.g_myDXCC)
{
entry.tx = false;
continue;
}
let hash = hashMaker(call, callObj, g_rosterSettings.reference);
if (rosterSettings.callMode == "worked" && hash in g_worked.call)
{
entry.tx = false;
continue;
}
if (rosterSettings.callMode == "confirmed" && hash in g_confirmed.call)
{
entry.tx = false;
continue;
}
if (g_rosterSettings.hunting == "grid")
{
let hash = hashMaker(callObj.grid.substr(0, 4),
callObj, g_rosterSettings.reference);
if (rosterSettings.huntIndex && hash in rosterSettings.huntIndex.grid)
{
entry.tx = false;
continue;
}
if (callObj.grid.length == 0)
{
entry.tx = false;
continue;
}
continue;
}
if (g_rosterSettings.hunting == "dxcc")
{
let hash = hashMaker(String(callObj.dxcc),
callObj, g_rosterSettings.reference);
if (rosterSettings.huntIndex && (hash in rosterSettings.huntIndex.dxcc))
{
entry.tx = false;
continue;
}
continue;
}
if (callObj.dxcc === -1)
{
entry.tx = false;
continue;
}
if (g_rosterSettings.hunting == "dxccs" && r_currentDXCCs != -1)
{
if (callObj.dxcc != r_currentDXCCs)
{
entry.tx = false;
continue;
}
}
if (g_rosterSettings.hunting == "wpx")
{
if (String(callObj.px) == null)
{
entry.tx = false;
continue;
}
let hash = hashMaker(String(callObj.px),
callObj, g_rosterSettings.reference);
if (rosterSettings.huntIndex && (hash in rosterSettings.huntIndex.px))
{
entry.tx = false;
continue;
}
continue;
}
if (g_rosterSettings.hunting == "cq")
{
let huntTotal = callObj.cqza.length;
if (huntTotal == 0 || !rosterSettings.huntIndex)
{
entry.tx = false;
continue;
}
let huntFound = 0;
for (index in callObj.cqza)
{
let hash = hashMaker(callObj.cqza[index], callObj, g_rosterSettings.reference);
if (hash in rosterSettings.huntIndex.cqz) huntFound++;
}
if (huntFound == huntTotal)
{
entry.tx = false;
continue;
}
continue;
}
if (g_rosterSettings.hunting == "itu")
{
let huntTotal = callObj.ituza.length;
if (huntTotal == 0 || !rosterSettings.huntIndex)
{
entry.tx = false;
continue;
}
let huntFound = 0;
for (index in callObj.ituza)
{
let hash = hashMaker(callObj.ituza[index], callObj, g_rosterSettings.reference);
if (hash in rosterSettings.huntIndex.ituz) huntFound++;
}
if (huntFound == huntTotal)
{
entry.tx = false;
continue;
}
if (callObj.grid.length == 0)
{
entry.tx = false;
continue;
}
continue;
}
if (g_rosterSettings.hunting == "usstates" && window.opener.g_callsignLookups.ulsUseEnable == true)
{
let state = callObj.state;
let finalDxcc = callObj.dxcc;
if (finalDxcc == 291 || finalDxcc == 110 || finalDxcc == 6)
{
if (state in window.opener.g_StateData)
{
let hash = hashMaker(state, callObj, g_rosterSettings.reference);
if (rosterSettings.huntIndex && hash in rosterSettings.huntIndex.state)
{
entry.tx = false;
continue;
}
}
else entry.tx = false;
}
else entry.tx = false;
continue;
}
if (g_rosterSettings.hunting == "usstate" && g_currentUSCallsigns)
{
if (call in g_currentUSCallsigns)
{
// Do Nothing
}
else
{
entry.tx = false;
continue;
}
continue;
}
}
if (rosterSettings.isAwardTracker)
{
let tx = false;
let baseHash = hashMaker("", callObj, g_rosterSettings.reference);
for (let award in g_awardTracker)
{
if (g_awardTracker[award].enable)
{
tx = testAward(award, callObj, baseHash);
if (tx)
{
let x = g_awardTracker[award];
// TODO: Move award reason out of exclusions code?
callObj.awardReason =
g_awards[x.sponsor].awards[x.name].tooltip +
" (" +
g_awards[x.sponsor].sponsor +
")";
break;
}
}
}
entry.tx = tx;
}
}
}

Wyświetl plik

@ -0,0 +1,700 @@
function processRosterHunting(callRoster, rosterSettings)
{
// these lets, do they rely on anything between the top and here?
// if not could they be put in the let list at the beginning?
let hasGtPin = false;
let inversionAlpha = "DD";
let row = "#000000";
let bold = "#000000;font-weight: bold;";
let unconf = "background-clip:padding-box;box-shadow: 0 0 7px 3px inset ";
let layeredAlpha = "77";
let layeredInversionAlpha = "66";
let layeredUnconf = "background-clip:padding-box;box-shadow: 0 0 4px 2px inset ";
let layeredUnconfAlpha = "AA";
// TODO: Hunting results might be used to filter, based on the "Callsigns: Only Wanted" option,
// so maybe we can move this loop first, and add a check to the filtering loop?
// Second loop, hunting and highlighting
for (let callHash in callRoster)
{
let entry = callRoster[callHash];
let callObj = entry.callObj;
// Special case check for called station
if (callObj.qrz == true && entry.tx == false)
{
// The instance has to be enabled
if (window.opener.g_instances[callObj.instance].crEnable == true)
{
// Calling us, but we wouldn't normally display
// If they are not ignored or we're in a QSO with them, let it through
// TODO: This is here because it's after the filtering stage
if ((!(entry.DEcall in g_blockedCalls) && !(callObj.dxcc in g_blockedDxcc)) ||
window.opener.g_instances[callObj.instance].status.DXcall == entry.DEcall)
{
entry.tx = true;
}
}
}
// Only render entries with `tx == true`, ignore the rest
if (callObj.dxcc != -1 && entry.tx == true)
{
// In layered mode ("Hunting: mixed") the workHashSuffix becomes a more stricter 'live band',
// while the layered suffix is a broader 'mixed band'
let workHashSuffix, layeredHashSuffix;
if (rosterSettings.layeredMode)
{
workHashSuffix = hashMaker("", callObj, rosterSettings.layeredMode);
layeredHashSuffix = hashMaker("", callObj, g_rosterSettings.reference);
}
else
{
workHashSuffix = hashMaker("", callObj, g_rosterSettings.reference);
layeredHashSuffix = false
}
let workHash = workHashSuffix; // TODO: Remove after replacing all occurrences with Suffix
let callsign = entry.DEcall;
callObj.hunting = {}
callObj.callFlags = {}
let colorObject = Object();
let callPointer = callObj.CQ == true ? "cursor:pointer" : "";
let didWork = false;
let call = "#FFFF00";
let grid = "#00FFFF";
let calling = "#90EE90";
let dxcc = "#FFA500";
let state = "#90EE90";
let cnty = "#CCDD00";
let cont = "#00DDDD";
let cqz = "#DDDDDD";
let ituz = "#DDDDDD";
let wpx = "#FFFF00";
hasGtPin = false;
let shouldAlert = false;
let callBg, gridBg, callingBg, dxccBg, stateBg, cntyBg, contBg, cqzBg, ituzBg, wpxBg, gtBg;
let callConf, gridConf, callingConf, dxccConf, stateConf, cntyConf, contConf, cqzConf, ituzConf, wpxConf;
callBg = gridBg = callingBg = dxccBg = stateBg = cntyBg = contBg = cqzBg = ituzBg = wpxBg = gtBg = row;
callConf = gridConf = callingConf = dxccConf = stateConf = cntyConf = contConf = cqzConf = ituzConf = wpxConf =
"";
let hash = callsign + workHashSuffix;
let layeredHash = layeredHashSuffix && (callsign + layeredHashSuffix)
// Call worked in current logbook settings, regardless of hunting mode
if (hash in g_worked.call)
{
callObj.callFlags.worked = true;
didWork = true;
callConf = `${unconf}${call}${inversionAlpha};`;
if (hash in g_confirmed.call)
{
callObj.callFlags.confirmed = true;
callPointer = "text-decoration: line-through; ";
callConf = "";
}
}
// Calls that have OAMS chat support
if (
callsign in window.opener.g_gtCallsigns &&
window.opener.g_gtCallsigns[callsign] in window.opener.g_gtFlagPins &&
window.opener.g_gtFlagPins[window.opener.g_gtCallsigns[callsign]].canmsg == true
)
{
callObj.callFlags.oams = true;
// grab the CID
callObj.gt = window.opener.g_gtCallsigns[callsign];
hasGtPin = true;
}
else
{
callObj.gt = 0;
}
// We only do hunt highlighting when showing all entries
// This means "Callsigns: All Traffic", "Callsigns: All Traffic/Only Wanted" and "Logbook: Award Tracker"
// There is no highlighting in other modes
if (rosterSettings.callMode == "all")
{
// Skip when "only new calls"
// Questions: Move to the first loop? Why only skip new calls in "all traffic" and not other modes?
if (allOnlyNew.checked == true && didWork && callObj.qrz == false)
{
entry.tx = false;
continue;
}
// Hunting for callsigns
if (huntCallsign.checked == true)
{
let hash = callsign + workHashSuffix;
let layeredHash = rosterSettings.layeredMode && (callsign + layeredHashSuffix)
if (rosterSettings.huntIndex && !(hash in rosterSettings.huntIndex.call))
{
shouldAlert = true;
callObj.reason.push("call");
if (rosterSettings.workedIndex && hash in rosterSettings.workedIndex.call)
{
if (rosterSettings.layeredMode && layeredHash in rosterSettings.huntIndex.call)
{
callObj.hunting.call = "worked-and-mixed";
callConf = `${layeredUnconf}${call}${layeredUnconfAlpha};`;
callBg = `${call}${layeredInversionAlpha}`;
call = bold;
}
// /* Currently we don't have a way to figure out
// * if the call is worked only in this band or also others,
// * so we cannot cover this particular combination
// * and have to default to just showing it as plain "worked"
// */
// else if (rosterSettings.layeredMode && layeredHash in rosterSettings.workedIndex.call)
// {
// callObj.hunting.call = "worked-and-mixed-worked";
// callConf = `${layeredUnconf}${call}${layeredAlpha};`;
// }
else
{
callObj.hunting.call = "worked";
callConf = `${unconf}${call}${inversionAlpha};`;
}
}
else
{
if (rosterSettings.layeredMode && layeredHash in rosterSettings.huntIndex.call)
{
callObj.hunting.call = "mixed";
callBg = `${call}${layeredAlpha};`;
call = bold;
}
else if (rosterSettings.layeredMode && layeredHash in rosterSettings.workedIndex.call)
{
callObj.hunting.call = "mixed-worked";
callConf = `${unconf}${call}${layeredAlpha};`;
}
else
{
callObj.hunting.call = "hunted";
callBg = `${call}${inversionAlpha};`;
call = bold;
}
}
}
}
// Hunting for "stations calling you"
if (huntQRZ.checked == true && callObj.qrz == true)
{
callObj.callFlags.calling = true
shouldAlert = true;
callObj.reason.push("qrz");
}
// Hunting for stations with OAMS
if (huntOAMS.checked == true && hasGtPin == true)
{
callObj.hunting.oams = "hunted";
shouldAlert = true;
callObj.reason.push("oams");
}
// Hunting for grids
if (huntGrid.checked == true && callObj.grid.length > 1)
{
let hash = callObj.grid.substr(0, 4) + workHashSuffix;
let layeredHash = rosterSettings.layeredMode && (callObj.grid.substr(0, 4) + layeredHashSuffix)
if (rosterSettings.huntIndex && !(hash in rosterSettings.huntIndex.grid))
{
shouldAlert = true;
callObj.reason.push("grid");
if (rosterSettings.workedIndex && hash in rosterSettings.workedIndex.grid)
{
if (rosterSettings.layeredMode && layeredHash in rosterSettings.huntIndex.grid)
{
callObj.hunting.grid = "worked-and-mixed";
gridConf = `${layeredUnconf}${grid}${layeredUnconfAlpha};`;
gridBg = `${grid}${layeredInversionAlpha}`;
grid = bold;
}
else
{
callObj.hunting.grid = "worked";
gridConf = `${unconf}${grid}${inversionAlpha};`;
}
}
else
{
if (rosterSettings.layeredMode && layeredHash in rosterSettings.huntIndex.grid)
{
callObj.hunting.grid = "mixed";
gridBg = `${grid}${layeredAlpha};`;
grid = bold;
}
else if (rosterSettings.layeredMode && layeredHash in rosterSettings.workedIndex.grid)
{
callObj.hunting.grid = "mixed-worked";
gridConf = `${unconf}${grid}${layeredAlpha};`;
}
else
{
callObj.hunting.grid = "hunted";
gridBg = `${grid}${inversionAlpha};`;
grid = bold;
}
}
}
}
// Hunting for DXCC
if (huntDXCC.checked == true)
{
let hash = String(callObj.dxcc) + workHashSuffix;
let layeredHash = rosterSettings.layeredMode && (String(callObj.dxcc) + layeredHashSuffix)
if (rosterSettings.huntIndex && !(hash in rosterSettings.huntIndex.dxcc))
{
shouldAlert = true;
callObj.reason.push("dxcc");
if (rosterSettings.workedIndex && hash in rosterSettings.workedIndex.dxcc)
{
if (rosterSettings.layeredMode && layeredHash in rosterSettings.huntIndex.dxcc)
{
callObj.hunting.dxcc = "worked-and-mixed";
dxccConf = `${layeredUnconf}${dxcc}${layeredUnconfAlpha};`;
dxccBg = `${dxcc}${layeredInversionAlpha}`;
dxcc = bold;
}
else
{
callObj.hunting.dxcc = "worked";
dxccConf = `${unconf}${dxcc}${inversionAlpha};`;
}
}
else
{
if (rosterSettings.layeredMode && layeredHash in rosterSettings.huntIndex.dxcc)
{
callObj.hunting.dxcc = "mixed";
dxccBg = `${dxcc}${layeredAlpha};`;
dxcc = bold;
}
else if (rosterSettings.layeredMode && layeredHash in rosterSettings.workedIndex.dxcc)
{
callObj.hunting.dxcc = "mixed-worked";
dxccConf = `${unconf}${dxcc}${layeredAlpha};`;
}
else
{
callObj.hunting.dxcc = "hunted";
dxccBg = `${dxcc}${inversionAlpha};`;
dxcc = bold;
}
}
}
}
// Hunting for US States
if (huntState.checked == true && window.opener.g_callsignLookups.ulsUseEnable == true)
{
let stateSearch = callObj.state;
let finalDxcc = callObj.dxcc;
if (finalDxcc == 291 || finalDxcc == 110 || finalDxcc == 6)
{
if (stateSearch in window.opener.g_StateData)
{
let hash = stateSearch + workHashSuffix;
let layeredHash = rosterSettings.layeredMode && (stateSearch + layeredHashSuffix)
if (rosterSettings.huntIndex && !(hash in rosterSettings.huntIndex.state))
{
shouldAlert = true;
callObj.reason.push("state");
if (rosterSettings.workedIndex && hash in rosterSettings.workedIndex.state)
{
if (rosterSettings.layeredMode && layeredHash in rosterSettings.huntIndex.state)
{
callObj.hunting.state = "worked-and-mixed";
stateConf = `${layeredUnconf}${state}${layeredUnconfAlpha};`;
stateBg = `${state}${layeredInversionAlpha}`;
state = bold;
}
else
{
callObj.hunting.state = "worked";
stateConf = `${unconf}${state}${inversionAlpha};`;
}
}
else
{
if (rosterSettings.layeredMode && layeredHash in rosterSettings.huntIndex.state)
{
callObj.hunting.state = "mixed";
stateBg = `${state}${layeredAlpha};`;
state = bold;
}
else if (rosterSettings.layeredMode && layeredHash in rosterSettings.workedIndex.state)
{
callObj.hunting.state = "mixed-worked";
stateConf = `${unconf}${state}${layeredAlpha};`;
}
else
{
callObj.hunting.state = "hunted";
stateBg = `${state}${inversionAlpha};`;
state = bold;
}
}
}
}
}
}
// Hunting for US Counties
if (huntCounty.checked == true && window.opener.g_callsignLookups.ulsUseEnable == true)
{
let finalDxcc = callObj.dxcc;
if (
callObj.cnty &&
(finalDxcc == 291 || finalDxcc == 110 || finalDxcc == 6 || finalDxcc == 202) &&
callObj.cnty.length > 0
)
{
let hash = callObj.cnty + (rosterSettings.layeredMode ? layeredHashSuffix : workHashSuffix);
if ((rosterSettings.huntIndex && !(hash in rosterSettings.huntIndex.cnty)) || callObj.qual == false)
{
if (callObj.qual == false)
{
let counties = window.opener.g_zipToCounty[callObj.zipcode];
let foundHit = false;
for (let cnt in counties)
{
let hh = counties[cnt] + workHash;
callObj.cnty = counties[cnt];
if (rosterSettings.huntIndex && !(hh in rosterSettings.huntIndex.cnty))
{
foundHit = true;
break;
}
}
if (foundHit) shouldAlert = true;
}
else
{
shouldAlert = true;
}
if (shouldAlert)
{
callObj.reason.push("cnty");
if (rosterSettings.workedIndex && hash in rosterSettings.workedIndex.cnty)
{
callObj.hunting.cnty = "worked";
cntyConf = `${unconf}${cnty}${inversionAlpha};`;
}
else
{
callObj.hunting.cnty = "hunted";
cntyBg = `${cnty}${inversionAlpha}`;
cnty = bold;
}
}
}
}
}
// Hunting for CQ Zones
if (huntCQz.checked == true)
{
let huntTotal = callObj.cqza.length;
let huntFound = 0, layeredFound = 0, workedFound = 0, layeredWorkedFound = 0;
for (index in callObj.cqza)
{
let hash = callObj.cqza[index] + workHashSuffix;
let layeredHash = rosterSettings.layeredMode && (callObj.cqza[index] + layeredHashSuffix)
if (rosterSettings.huntIndex && hash in rosterSettings.huntIndex.cqz) huntFound++;
if (rosterSettings.layeredMode && layeredHash in rosterSettings.huntIndex.cqz) layeredFound++;
if (rosterSettings.workedIndex && hash in rosterSettings.workedIndex.cqz) workedFound++;
if (rosterSettings.layeredMode && layeredHash in rosterSettings.workedIndex.cqz) layeredWorkedFound++;
}
if (huntFound != huntTotal)
{
shouldAlert = true;
callObj.reason.push("cqz");
if (rosterSettings.workedIndex && workedFound == huntTotal)
{
if (rosterSettings.layeredMode && layeredFound == huntTotal)
{
callObj.hunting.cqz = "worked-and-mixed";
cqzConf = `${layeredUnconf}${cqz}${layeredUnconfAlpha};`;
cqzBg = `${cqz}${layeredInversionAlpha}`;
cqz = bold;
}
else
{
callObj.hunting.cqz = "worked";
cqzConf = `${unconf}${cqz}${inversionAlpha};`;
}
}
else
{
if (rosterSettings.layeredMode && layeredFound == huntTotal)
{
callObj.hunting.cqz = "mixed";
cqzBg = `${cqz}${layeredAlpha};`;
cqz = bold;
}
else if (rosterSettings.layeredMode && layeredWorkedFound == huntTotal)
{
callObj.hunting.cqz = "mixed-worked";
cqzConf = `${unconf}${cqz}${layeredAlpha};`;
}
else
{
callObj.hunting.cqz = "hunted";
cqzBg = `${cqz}${inversionAlpha};`;
cqz = bold;
}
}
}
}
// Hunting for ITU Zones
if (huntITUz.checked == true)
{
let huntTotal = callObj.ituza.length;
let huntFound = 0, layeredFound = 0, workedFound = 0, layeredWorkedFound = 0;
for (index in callObj.ituza)
{
let hash = callObj.ituza[index] + workHashSuffix;
let layeredHash = rosterSettings.layeredMode && (callObj.ituza[index] + layeredHashSuffix)
if (rosterSettings.huntIndex && hash in rosterSettings.huntIndex.ituz) huntFound++;
if (rosterSettings.layeredMode && layeredHash in rosterSettings.huntIndex.ituz) layeredFound++;
if (rosterSettings.workedIndex && hash in rosterSettings.workedIndex.ituz) workedFound++;
if (rosterSettings.layeredMode && layeredHash in rosterSettings.workedIndex.ituz) layeredWorkedFound++;
}
if (huntFound != huntTotal)
{
shouldAlert = true;
callObj.reason.push("ituz");
if (rosterSettings.workedIndex && workedFound == huntTotal)
{
if (rosterSettings.layeredMode && layeredFound == huntTotal)
{
callObj.hunting.ituz = "worked-and-mixed";
ituzConf = `${layeredUnconf}${ituz}${layeredUnconfAlpha};`;
ituzBg = `${ituz}${layeredInversionAlpha}`;
ituz = bold;
}
else
{
callObj.hunting.ituz = "worked";
ituzConf = `${unconf}${ituz}${inversionAlpha};`;
}
}
else
{
if (rosterSettings.layeredMode && layeredFound == huntTotal)
{
callObj.hunting.ituz = "mixed";
ituzBg = `${ituz}${layeredAlpha};`;
ituz = bold;
}
else if (rosterSettings.layeredMode && layeredWorkedFound == huntTotal)
{
callObj.hunting.ituz = "mixed-worked";
ituzConf = `${unconf}${ituz}${layeredAlpha};`;
}
else
{
callObj.hunting.ituz = "hunted";
ituzBg = `${ituz}${inversionAlpha};`;
ituz = bold;
}
}
}
}
// Hunting for WPX (Prefixes)
if (huntPX.checked == true && callObj.px)
{
let hash = String(callObj.px) + workHashSuffix;
let layeredHash = rosterSettings.layeredMode && (String(callObj.px) + layeredHashSuffix)
if (rosterSettings.huntIndex && !(hash in rosterSettings.huntIndex.px))
{
shouldAlert = true;
callObj.reason.push("wpx");
if (rosterSettings.workedIndex && hash in rosterSettings.workedIndex.px)
{
if (rosterSettings.layeredMode && layeredHash in rosterSettings.huntIndex.px)
{
callObj.hunting.wpx = "worked-and-mixed";
wpxConf = `${layeredUnconf}${wpx}${layeredUnconfAlpha};`;
wpxBg = `${wpx}${layeredInversionAlpha}`;
wpx = bold;
}
else
{
callObj.hunting.wpx = "worked";
wpxConf = `${unconf}${wpx}${inversionAlpha};`;
}
}
else
{
if (rosterSettings.layeredMode && layeredHash in rosterSettings.huntIndex.px)
{
callObj.hunting.wpx = "mixed";
wpxBg = `${wpx}${layeredAlpha};`;
wpx = bold;
}
else if (rosterSettings.layeredMode && layeredHash in rosterSettings.workedIndex.px)
{
callObj.hunting.wpx = "mixed-worked";
wpxConf = `${unconf}${wpx}${layeredAlpha};`;
}
else
{
callObj.hunting.wpx = "hunted";
wpxBg = `${wpx}${inversionAlpha};`;
wpx = bold;
}
}
}
}
// Hunting for Continents
if (huntCont.checked == true && callObj.cont)
{
let hash = String(callObj.cont) + workHashSuffix;
let layeredHash = rosterSettings.layeredMode && (String(callObj.cont) + layeredHashSuffix)
if (rosterSettings.huntIndex && !(hash in rosterSettings.huntIndex.cont))
{
shouldAlert = true;
callObj.reason.push("cont");
if (rosterSettings.workedIndex && hash in rosterSettings.workedIndex.cont)
{
if (rosterSettings.layeredMode && layeredHash in rosterSettings.huntIndex.cont)
{
callObj.hunting.cont = "worked-and-mixed";
contConf = `${layeredUnconf}${cont}${layeredUnconfAlpha};`;
contBg = `${cont}${layeredInversionAlpha}`;
cont = bold;
}
else
{
callObj.hunting.cont = "worked";
contConf = `${unconf}${cont}${inversionAlpha};`;
}
}
else
{
if (rosterSettings.layeredMode && layeredHash in rosterSettings.huntIndex.cont)
{
callObj.hunting.cont = "mixed";
contBg = `${cont}${layeredAlpha};`;
cont = bold;
}
else if (rosterSettings.layeredMode && layeredHash in rosterSettings.workedIndex.cont)
{
callObj.hunting.cont = "mixed-worked";
contConf = `${unconf}${cont}${layeredAlpha};`;
}
else
{
callObj.hunting.cont = "hunted";
contBg = `${cont}${inversionAlpha};`;
cont = bold;
}
}
}
}
}
// Station is calling us
if (callObj.DXcall == window.opener.myDEcall)
{
callingBg = "#0000FF" + inversionAlpha;
calling = "#FFFF00;text-shadow: 0px 0px 2px #FFFF00";
}
else if (callObj.CQ == true && !g_rosterSettings.cqOnly)
{
callingBg = calling + inversionAlpha;
calling = bold;
}
// Assemble all styles
colorObject.call = "style='" + callConf + "background-color:" + callBg + ";color:" +
call + ";" + callPointer + "'";
colorObject.grid = "style='" + gridConf + "background-color:" + gridBg + ";color:" + grid + ";cursor:pointer'";
colorObject.calling = "style='" + callingConf + "background-color:" + callingBg + ";color:" + calling + "'";
colorObject.dxcc = "style='" + dxccConf + "background-color:" + dxccBg + ";color:" + dxcc + "'";
colorObject.state = "style='" + stateConf + "background-color:" + stateBg + ";color:" + state + "'";
colorObject.cnty = "style='" + cntyConf + "background-color:" + cntyBg + ";color:" + cnty + "'";
colorObject.cont = "style='" + contConf + "background-color:" + contBg + ";color:" + cont + "'";
colorObject.cqz = "style='" + cqzConf + "background-color:" + cqzBg + ";color:" + cqz + "'";
colorObject.ituz = "style='" + ituzConf + "background-color:" + ituzBg + ";color:" + ituz + "'";
colorObject.px = "style='" + wpxConf + "background-color:" + wpxBg + ";color:" + wpx + "'";
// Just in case, don't alert if we worked this callsign alread
if (didWork && shouldAlert) shouldAlert = false;
callObj.shouldAlert = shouldAlert;
callObj.style = colorObject;
if (g_rosterSettings.columns.Spot)
{
callObj.spot = window.opener.getSpotTime(
callObj.DEcall + callObj.mode + callObj.band + callObj.grid
);
if (callObj.spot == null)
{
callObj.spot = { when: 0, snr: 0 };
}
}
else
{
callObj.spot = { when: 0, snr: 0 };
}
rosterSettings.modes[callObj.mode] = true;
rosterSettings.bands[callObj.band] = true;
}
}
}

Wyświetl plik

@ -0,0 +1,55 @@
function renderCompactRosterHeaders()
{
return "<div id=\"buttonsDiv\" style=\"margin-left:0px;white-space:normal;\">";
}
function renderCompactRosterRow(callObj)
{
var thisCall = callObj.DEcall;
var tt =
callObj.RSTsent +
"&#13256;, " +
parseInt(callObj.dt * 100) +
"ms, " +
callObj.delta +
"hz" +
(callObj.grid.length ? ", " + callObj.grid : "") +
", " +
(timeNowSec() - callObj.age).toDHMS();
var worker =
"<div class='compact' onClick='initiateQso(\"" +
thisCall +
callObj.band +
callObj.mode +
"\")' ";
worker +=
"id='" +
thisCall +
callObj.band +
callObj.mode +
"' title='" +
tt +
"'>";
worker +=
"<div class='compactCallsign' name='Callsign' " +
callObj.style.call +
" >" +
thisCall.formatCallsign() +
"</div>";
worker +=
"<div class='compactDXCC' name='DXCC (" +
callObj.dxcc +
")' " +
callObj.style.dxcc +
">" +
window.opener.g_dxccToAltName[callObj.dxcc] +
"</div>";
worker += "</div>";
return worker;
}
function renderCompactRosterFooter()
{
return "</div>";
}

Wyświetl plik

@ -0,0 +1,27 @@
function renderNormalRosterHeaders(columns)
{
let html = "<table id='callTable' class='rosterTable' align=left><thead>"
html = html + columns.map(column => renderHeaderForColumn(column)).join("\n")
html = html + "</thead><tbody>"
return html
}
function renderNormalRosterRow(columns, callObj)
{
callObj.grid4 = callObj.grid4 || (callObj.grid && callObj.grid.length > 1) ? callObj.grid.substr(0, 4) : "-";
callObj.hash = callObj.hash || `${callObj.DEcall}${callObj.band}${callObj.mode}`;
let html = `<tr id='${callObj.hash}'>`;
html = html + columns.map(column => renderEntryForColumn(column, callObj)).join("\n")
html += "</tr>";
return html;
}
function renderNormalRosterFooter()
{
return "</tbody></table>";
}

Wyświetl plik

@ -0,0 +1,142 @@
function renderRoster(callRoster, rosterSettings)
{
let columnOverrides = {
Callsign: true,
Grid: true
}
if (window.opener.g_callsignLookups.eqslUseEnable == true)
{
useseQSLDiv.style.display = "";
}
else
{
columnOverrides.eQSL = false;
useseQSLDiv.style.display = "none";
}
if (window.opener.g_callsignLookups.oqrsUseEnable == true)
{
usesOQRSDiv.style.display = "";
}
else
{
columnOverrides.OQRS = false;
usesOQRSDiv.style.display = "none";
}
if (window.opener.g_callsignLookups.lotwUseEnable == true)
{
// Do nothing
}
else
{
columnOverrides.LoTW = false;
}
// dealing with spots
if (g_rosterSettings.columns.Spot == true) onlySpotDiv.style.display = "";
else onlySpotDiv.style.display = "none";
// callmode (all or only new)
if (rosterSettings.callMode == "all") allOnlyNewDiv.style.display = "";
else allOnlyNewDiv.style.display = "none";
// Show the roster count in the window title
// let visibleCallList = callRoster.filter(entry => entry.tx);
let visibleCallList = [];
let band =
window.opener.g_appSettings.gtBandFilter == "auto"
? window.opener.g_appSettings.myBand
: window.opener.g_appSettings.gtBandFilter.length == 0
? ""
: window.opener.g_appSettings.gtBandFilter;
for (entry in callRoster)
{
// entry should populate in general
if (callRoster[entry].tx)
{
// check setting for call roster clear on band change.
// if true and band is current band, populate
if (window.opener.g_appSettings.clearRosterOnBandChange)
{
if (callRoster[entry].callObj.band == band)
{
visibleCallList.push(callRoster[entry]);
}
}
else if (!window.opener.g_appSettings.clearRosterOnBandChange)
{
visibleCallList.push(callRoster[entry]);
}
}
}
let totalCount = Object.keys(callRoster).length;
let visibleCount = visibleCallList.length;
let huntedCount = visibleCallList.filter(obj => Object.keys(obj.callObj.hunting).length > 0).length
let countParts = [];
if (totalCount != visibleCount)
{
countParts.push(`${totalCount} heard`);
}
countParts.push(`${visibleCount} in roster`);
if (huntedCount != visibleCount)
{
countParts.push(`${huntedCount} wanted`);
}
window.document.title = `Call Roster: ${countParts.join(" • ")}`;
if (g_rosterSettings.compact)
{
sortCallList(visibleCallList, "Age", false);
}
else
{
sortCallList(visibleCallList, g_rosterSettings.sortColumn, g_rosterSettings.sortReverse);
}
let showBands = (Object.keys(rosterSettings.bands).length > 1) || g_rosterSettings.columns.Band;
let showModes = (Object.keys(rosterSettings.modes).length > 1) || g_rosterSettings.columns.Mode;
columnOverrides.Band = showBands
columnOverrides.Mode = showModes
const rosterColumns = rosterColumnList(g_rosterSettings.columns, columnOverrides)
let worker = g_rosterSettings.compact ? renderCompactRosterHeaders() : renderNormalRosterHeaders(rosterColumns)
// Third loop: render all rows
for (let x in visibleCallList)
{
let callObj = visibleCallList[x].callObj;
// TODO: This is filtering
if (callObj.shouldAlert == false && rosterSettings.onlyHits == true && callObj.qrz == false)
{ continue; }
if (callObj.DEcall.match("^[A-Z][0-9][A-Z](/w+)?$"))
{ callObj.style.call = "class='oneByOne'"; }
if (callObj.DEcall == window.opener.g_instances[callObj.instance].status.DXcall)
{
if (window.opener.g_instances[callObj.instance].status.TxEnabled == 1)
{
callObj.style.call = "class='dxCalling'";
}
else
{
callObj.style.call = "class='dxCaller'";
}
}
worker += g_rosterSettings.compact ? renderCompactRosterRow(callObj) : renderNormalRosterRow(rosterColumns, callObj)
}
worker += g_rosterSettings.compact ? renderCompactRosterFooter() : renderNormalRosterFooter()
RosterTable.innerHTML = worker;
}

Wyświetl plik

@ -0,0 +1,95 @@
function rosterColumnList(settings = {}, overrides = {})
{
return g_rosterSettings.columnOrder.filter(column =>
{
return column && (settings[column] || overrides[column]) && !(overrides[column] === false)
})
}
function renderHeaderForColumn(column)
{
const columnInfo = ROSTER_COLUMNS[column]
let attrs = (columnInfo && columnInfo.tableHeader && columnInfo.tableHeader()) || {}
attrs.html = attrs.html || column
if (columnInfo.compare)
{
attrs.style = "cursor: pointer"
attrs.onClick = `setRosterSorting('${column}');`
}
return renderRosterTableHTML("th", attrs)
}
function renderEntryForColumn(column, entry)
{
const columnInfo = ROSTER_COLUMNS[column]
let attrs = (columnInfo && columnInfo.tableData && columnInfo.tableData(entry)) || {}
return renderRosterTableHTML("td", attrs)
}
function renderRosterTableHTML(tag, attrs)
{
let innerHtml = attrs.html || ""
delete attrs.html
let rawAttrs = attrs.rawAttrs || ""
delete attrs.rawAttrs
let attrEntries = Object.entries(attrs).filter(kv => !!kv[1])
return `<${tag} ${rawAttrs} ${attrEntries.map((kv) => `${kv[0]}="${kv[1].replace(/"/g, "&quot;")}"`).join(" ")}>${innerHtml}</${tag}>`
}
function setRosterSorting(column)
{
if (g_rosterSettings.sortColumn === column)
{
g_rosterSettings.sortReverse = !g_rosterSettings.sortReverse
}
else
{
g_rosterSettings.sortColumn = column
g_rosterSettings.sortReverse = false
}
writeRosterSettings();
window.opener.goProcessRoster();
}
function sortCallList(callList, sortColumn, sortReverse)
{
const columnInfo = ROSTER_COLUMNS[sortColumn]
callList.sort((columnInfo && columnInfo.compare) || ROSTER_COLUMNS.Age.compare)
if (sortReverse)
{
callList.reverse()
}
}
function validateRosterColumnOrder(columns)
{
let correctedColumnOrder = (columns || DEFAULT_COLUMN_ORDER || []).slice();
DEFAULT_COLUMN_ORDER.forEach(column =>
{
if (!correctedColumnOrder.includes(column)) correctedColumnOrder.push(column);
})
correctedColumnOrder = correctedColumnOrder.filter(column => !!ROSTER_COLUMNS[column])
return correctedColumnOrder;
}
function changeRosterColumnOrder(columns)
{
g_rosterSettings.columnOrder = validateRosterColumnOrder(columns);
writeRosterSettings();
window.opener.goProcessRoster();
}

Wyświetl plik

@ -0,0 +1,378 @@
const DEFAULT_COLUMN_ORDER = [
"Callsign", "Band", "Mode", "Grid", "Calling", "Msg",
"DXCC", "Flag", "State", "County", "Cont",
"dB", "Freq", "DT", "Dist", "Azim",
"CQz", "ITUz", "PX",
"LoTW", "eQSL", "OQRS",
"Life", "Spot", "OAMS", "Age"
]
const LEGACY_COLUMN_SORT_ID = {
0: "Callsign",
1: "Grid",
2: "dB",
3: "DT",
4: "Freq",
5: "DXCC",
7: "Dist",
8: "Azim",
9: "State",
10: "Calling",
11: "PX",
12: "Life",
13: "Spot",
14: "OAMS",
15: "County",
16: "Cont"
}
const getterSimpleComparer = (getter) => (a, b) =>
{
const aVal = getter(a);
const bVal = getter(b);
if (aVal == null) return 1;
if (bVal == null) return -1;
if (aVal > bVal) return 1;
if (aVal < bVal) return -1;
return 0;
}
const callObjSimpleComparer = (attr) => getterSimpleComparer((elem) => elem.callObj[attr])
const callObjLocaleComparer = (attr) => (a, b) =>
{
if (a.callObj[attr] == null) return 1;
if (b.callObj[attr] == null) return -1;
return a.callObj[attr].localeCompare(b.callObj[attr]);
}
const ROSTER_COLUMNS = {
Callsign: {
compare: callObjLocaleComparer("DEcall"),
tableHeader: () => ({ align: "left" }),
tableData: (callObj) =>
{
let attrs = {
title: callObj.awardReason,
name: "Callsign",
align: "left",
onClick: `initiateQso("${callObj.hash}")`,
rawAttrs: callObj.style.call,
html: html = callObj.DEcall.formatCallsign()
}
let acks = window.opener.g_acknowledgedCalls;
if (acks[callObj.DEcall])
{
attrs.html = `${attrs.html} <span class='acknowledged'><img class='ackBadge' src='${acks[callObj.DEcall].badge}'></span>`
attrs.title = `${attrs.title} - ${acks[callObj.DEcall].message}`
}
return attrs
}
},
Band: {
compare: false,
tableData: (callObj) => ({
style: `color: #${window.opener.g_pskColors[callObj.band]};`,
html: callObj.band
})
},
Mode: {
compare: false,
tableData: (callObj) => ({
style: `color: #${g_modeColors[callObj.mode] || "888888"};`,
html: callObj.mode
})
},
Grid: {
compare: callObjSimpleComparer("grid"),
tableData: (callObj) => ({
rawAttrs: callObj.style.grid,
onClick: `centerOn("${callObj.grid4}")`,
html: callObj.grid4
})
},
Calling: {
compare: callObjLocaleComparer("DXcall"),
tableData: (callObj) => ({
rawAttrs: callObj.style.calling,
name: callObj.CQ ? "CQ" : "Calling",
html: callObj.DXcall.formatCallsign()
})
},
Msg: {
compare: callObjLocaleComparer("DXcall"),
tableData: (callObj) => ({ html: callObj.msg })
},
DXCC: {
compare: (a, b) => window.opener.myDxccCompare(a.callObj, b.callObj),
tableData: (callObj) => ({
title: window.opener.g_worldGeoData[window.opener.g_dxccToGeoData[callObj.dxcc]].pp,
name: `DXCC (${callObj.dxcc})`,
rawAttrs: callObj.style.dxcc,
html: window.opener.g_dxccToAltName[callObj.dxcc]
})
},
Flag: {
compare: (a, b) => window.opener.myDxccCompare(a.callObj, b.callObj),
tableData: (callObj) => ({
align: "center",
style: "margin:0; padding:0;",
html: `<img style='padding-top:3px' src='./img/flags/16/${window.opener.g_worldGeoData[window.opener.g_dxccToGeoData[callObj.dxcc]].flag}'>`
})
},
State: {
compare: callObjSimpleComparer("state"),
tableData: (callObj) => ({
align: "center",
rawAttrs: callObj.style.state,
html: callObj.state ? callObj.state.substr(3) : ""
})
},
County: {
// Not sure why this comparison uses substring, but this is what the original code did
compare: getterSimpleComparer((elem) => elem.callObj.cnty && elem.callObj.cnty.substr(3)),
tableData: (callObj) =>
{
let attrs = {
align: "center",
rawAttrs: callObj.style.cnty,
html: callObj.cnty ? window.opener.g_cntyToCounty[callObj.cnty] : ""
}
if (callObj.cnty && callObj.qual)
{
attrs.title = "ZIP Code matches multiple counties, click to do a full lookup"
attrs.onClick = `lookupZip("${callObj.DEcall}", "${callObj.grid4}")`
attrs.html = `¿ ${attrs.html} ?`
}
return attrs
}
},
Cont: {
compare: callObjSimpleComparer("cont"),
tableData: (callObj) => ({
align: "center",
rawAttrs: callObj.style.cont,
html: callObj.cont ? callObj.cont : ""
})
},
dB: {
compare: callObjSimpleComparer("RSTsent"),
tableData: (callObj) => ({
style: "color:#DD44DD;",
html: `<b>${callObj.RSTsent}</b>`
})
},
Freq: {
compare: callObjSimpleComparer("delta"),
tableData: (callObj) => ({
style: "color: #00FF00;",
html: callObj.delta
})
},
DT: {
compare: callObjSimpleComparer("dt"),
tableData: (callObj) => ({
style: "color: #1E90FF;",
html: callObj.dt
})
},
Dist: {
compare: callObjSimpleComparer("distance"),
tableHeader: () => ({ html: `Dist (${window.opener.distanceUnit.value.toLowerCase()})` }),
tableData: (callObj) => ({
style: "color: cyan;",
html: Math.round(callObj.distance * MyCircle.validateRadius(window.opener.distanceUnit.value))
})
},
Azim: {
compare: callObjSimpleComparer("heading"),
tableData: (callObj) => ({
style: "color: yellow;",
html: Math.round(callObj.heading)
})
},
CQz: {
compare: false,
tableData: (callObj) => ({
name: "CQz",
rawAttrs: callObj.style.cqz,
html: callObj.cqza.join(",")
})
},
ITUz: {
compare: false,
tableData: (callObj) => ({
name: "ITUz",
rawAttrs: callObj.style.ituz,
html: callObj.ituza.join(",")
})
},
PX: {
compare: callObjSimpleComparer("px"),
tableData: (callObj) => ({
rawAttrs: callObj.style.px,
html: callObj.px ? callObj.px : ""
})
},
LoTW: {
compare: false,
tableData: (callObj) =>
{
if (callObj.DEcall in window.opener.g_lotwCallsigns)
{
if (g_rosterSettings.maxLoTW < 27)
{
let months = (g_day - window.opener.g_lotwCallsigns[callObj.DEcall]) / 30;
if (months > g_rosterSettings.maxLoTW)
{
return {
style: "color: yellow;",
align: "center",
title: `Has not updated a QSO in ${Number(months).toYM()}`,
html: "?"
}
}
else
{
return {
style: "color: #0F0;",
align: "center",
title: `Last Upload&#10;${
window.opener.userDayString(window.opener.g_lotwCallsigns[callObj.DEcall] * 86400000)
}`,
html: "&#10004;"
}
}
}
else
{
return {
style: "color: #0F0;",
align: "center",
title: `Last Upload&#10;${
window.opener.userDayString(window.opener.g_lotwCallsigns[callObj.DEcall] * 86400000)
}`,
html: "&#10004;"
}
}
}
}
},
eQSL: {
compare: false,
tableData: (callObj) => ({
style: "color: #0F0;",
align: "center",
html: (callObj.DEcall in window.opener.g_eqslCallsigns ? "&#10004;" : "")
})
},
OQRS: {
compare: false,
tableData: (callObj) => ({
style: "color: #0F0;",
align: "center",
html: (callObj.DEcall in window.opener.g_oqrsCallsigns ? "&#10004;" : "")
})
},
Life: {
compare: callObjSimpleComparer("life"),
tableData: (callObj) => ({
style: "color: #EEE;",
class: "lifeCol",
id: `lm${callObj.hash}`,
html: (timeNowSec() - callObj.life).toDHMS15()
})
},
OAMS: {
tableHeader: () => ({ description: "Off-Air Message User" }),
compare: getterSimpleComparer((elem) => elem.callObj.gt != 0 ? 1 : 0),
tableData: (callObj) =>
{
if (callObj.gt != 0)
{
if (callObj.reason.includes("oams"))
{
return {
align: "center",
style: "margin: 0; padding: 0; cursor: pointer; background-clip: content-box; box-shadow: 0 0 4px 4px inset #2222FFFF;",
onClick: `openChatToCid("${callObj.gt}")`,
html: "<img height='16px' style='' src='./img/gt_chat.png' />"
}
}
else
{
return {
align: "center",
style: "margin: 0; padding: 0; cursor: pointer;",
onClick: `openChatToCid("${callObj.gt}")`,
html: "<img height='16px' style='' src='./img/gt_chat.png' />"
}
}
}
}
},
Age: {
compare: callObjSimpleComparer("time"),
tableData: (callObj) => ({
style: "color: #EEE;",
class: "timeCol",
id: `tm${callObj.hash}`,
title: (timeNowSec() - callObj.age).toDHMS(),
html: (timeNowSec() - callObj.age).toDHMS15()
})
},
Spot: {
compare: (a, b) =>
{
let cutoff = timeNowSec() - window.opener.g_receptionSettings.viewHistoryTimeSec;
if (a.callObj.spot.when <= cutoff) return -1;
if (b.callObj.spot.when <= cutoff) return 1;
let aSNR = Number(a.callObj.spot.snr);
let bSNR = Number(b.callObj.spot.snr);
if (aSNR > bSNR) return 1;
if (aSNR < bSNR) return -1;
if (a.callObj.spot.when > b.callObj.spot.when) return 1;
if (a.callObj.spot.when < b.callObj.spot.when) return -1;
return 0;
},
tableData: (callObj) => ({
style: "color: #EEE;",
class: "spotCol",
id: `sp${callObj.hash}`,
html: getSpotString(callObj)
})
}
}

Wyświetl plik

@ -0,0 +1,140 @@
function sendAlerts(callRoster, rosterSettings)
{
var dirPath = window.opener.g_scriptDir;
var scriptExists = false;
var script = "cr-alert.sh";
var shouldAlert = 0;
for (entry in callRoster)
{
var callObj = callRoster[entry].callObj;
// chrbayer: what does the tx field mean? no alerts are generated (at all) if this is in place...
// if (!callObj.tx) continue;
// TODO: Get rid of realtime
if (g_rosterSettings.realtime == false)
{
var call = callObj.DEcall;
g_scriptReport[call] = Object.assign({}, callObj);
g_scriptReport[call].dxccName =
window.opener.g_dxccToAltName[callObj.dxcc];
g_scriptReport[call].distance = parseInt(
callObj.distance *
MyCircle.validateRadius(window.opener.distanceUnit.value)
);
delete g_scriptReport[call].DEcall;
g_scriptReport[call].rect = null;
delete g_scriptReport[call].rect;
delete g_scriptReport[call].style;
delete g_scriptReport[call].wspr;
delete g_scriptReport[call].qso;
delete g_scriptReport[call].instance;
if (rosterSettings.callMode != "all")
{
g_scriptReport[call].shouldAlert = true;
g_scriptReport[call].reason.push(g_rosterSettings.hunting);
}
}
if (
callObj.alerted == false &&
rosterSettings.callMode == "all" &&
callObj.shouldAlert == true
)
{
callObj.alerted = true;
shouldAlert++;
}
else if (callObj.alerted == false && rosterSettings.callMode != "all")
{
callObj.alerted = true;
shouldAlert++;
}
callObj.shouldAlert = false;
}
// NOTE: Ring alerts if needed
try
{
if (fs.existsSync(dirPath))
{
if (window.opener.g_platform == "windows")
{
script = "cr-alert.bat";
}
if (
fs.existsSync(dirPath + script) &&
g_rosterSettings.realtime == false
)
{
scriptExists = true;
scriptIcon.innerHTML =
"<div class='buttonScript' onclick='window.opener.toggleCRScript();'>" +
(window.opener.g_crScript == 1
? "<font color='lightgreen'>Script Enabled</font>"
: "<font color='yellow'>Script Disabled</font>") +
"</div>";
scriptIcon.style.display = "block";
}
else
{
scriptIcon.style.display = "none";
}
}
}
catch (e) {}
if (shouldAlert > 0)
{
if (window.opener.g_classicAlerts.huntRoster == true)
{
var notify = window.opener.huntRosterNotify.value;
if (notify == "0")
{
var media = window.opener.huntRosterNotifyMedia.value;
if (media != "none") window.opener.playAlertMediaFile(media);
}
else if (notify == "1")
{
window.opener.speakAlertString(
window.opener.huntRosterNotifyWord.value
);
}
}
if (
g_rosterSettings.realtime == false &&
scriptExists &&
window.opener.g_crScript == 1
)
{
try
{
fs.writeFileSync(
dirPath + "cr-alert.json",
JSON.stringify(g_scriptReport, null, 2)
);
var thisProc = dirPath + script;
var cp = require("child_process");
var child = cp.spawn(thisProc, [], {
detached: true,
cwd: dirPath.slice(0, -1),
stdio: ["ignore", "ignore", "ignore"]
});
child.unref();
}
catch (e)
{
conosle.log(e);
}
g_scriptReport = Object();
}
else g_scriptReport = Object();
}
}

Wyświetl plik

@ -1,4 +1,4 @@
// GridTracker Copyright © 2021 GridTracker.org
// GridTracker Copyright © 2022 GridTracker.org
// All rights reserved.
// See LICENSE for more information.

Wyświetl plik

@ -1,7 +1,7 @@
{
"name": "GridTracker",
"product_string_do_not_use": "gridtracker",
"version": "1.21.0620",
"version": "1.22.0503",
"betaVersion": "",
"description": "GridTracker, an amateur radio companion",
"author": "Stephen Loomis (N0TTL) and GridTracker.org",
@ -23,7 +23,7 @@
"start": "run --mirror https://dl.nwjs.io/ ."
},
"build": {
"nwVersion": "0.49.2",
"nwVersion": "0.59.0",
"output": "../dist/.",
"targets": [
"zip",
@ -31,7 +31,7 @@
],
"mac": {
"icon": "gridview.icns",
"copyright": "Copyright (c) 2021 GridTracker.org",
"copyright": "Copyright (c) 2022 GridTracker.org",
"plistStrings": {
"CFBundleIdentifier": "org.gridtracker.gridtracker",
"CFBundleDocumentTypes": []
@ -39,7 +39,7 @@
},
"win": {
"icon": "gridview.ico",
"copyright": "Copyright (c) 2021 GridTracker.org"
"copyright": "Copyright (c) 2022 GridTracker.org"
},
"nsis": {
"installDirectory": "$PROGRAMFILES\\${_APPNAME}",

Wyświetl plik

@ -65,7 +65,7 @@ VIAddVersionKey CompanyName "${COMPANY}"
VIAddVersionKey CompanyWebsite "${URL}"
VIAddVersionKey FileVersion "${VERSION}"
VIAddVersionKey FileDescription "An Amateur Radio Community"
VIAddVersionKey LegalCopyright "2021 Gridtracker.org"
VIAddVersionKey LegalCopyright "2022 Gridtracker.org"
InstallDirRegKey HKLM "${REGKEY}" Path
ShowUninstDetails nevershow

Wyświetl plik

@ -0,0 +1,170 @@
/*
GridTracker Installation Script
*/
# Installer Attributes
RequestExecutionLevel highest
SetCompressor /SOLID LZMA
Unicode true
!include Sections.nsh
!include Registry.nsh
!include LogicLib.nsh
ReserveFile "${NSISDIR}/Plugins/x86-unicode/registry.dll"
CRCCheck on
# Define Common Variables
!define NAME "GridTracker"
!define COMPANY "Gridtracker.org"
!define VERSION <versionplaceholder>
!define URL "http://gridtracker.org"
!define HELPURL "https://gitlab.com/gridtracker.org/gridtracker/-/wikis/Home"
!define REGPATH_UNINSTSUBKEY "Software\Microsoft\Windows\CurrentVersion\Uninstall\${NAME}"
!define SMPATH "$SMPROGRAMS\${NAME}"
!define /date CPYEAR "%Y"
!define BUILDPATH "<buildplaceholder>"
Name "${NAME} ${VERSION} Installer"
Icon "${BUILDPATH}/dist/GridTracker-${VERSION}-win-x86/gridview.ico"
OutFile "${BUILDPATH}/dist/GridTracker-Installer.${VERSION}.exe"
VIProductVersion ${VERSION}.0
VIAddVersionKey ProductName "${NAME}"
VIAddVersionKey ProductVersion "${VERSION}"
VIAddVersionKey CompanyName "${COMPANY}"
VIAddVersionKey CompanyWebsite "${URL}"
VIAddVersionKey FileVersion "${VERSION}"
VIAddVersionKey FileDescription "An Amateur Radio Community"
VIAddVersionKey LegalCopyright "${CPYEAR} Gridtracker.org"
# Add registry reading plugin early on as we need to see if we are installed already
# Set Default install dir then look at uninstall key to find if previously installed #
InstallDir "$ProgramFiles\${NAME}"
## For 32 bit installs on 64 bit OS this is located in the WOW6432Node [HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall] ##
InstallDirRegKey HKLM "${REGPATH_UNINSTSUBKEY}" "InstallPath"
# Pages displayed
#Page license
Page directory
Page components
Page instfiles
# Display license file to user #
#LicenseData "LICENSE"
Function .onInit
nsProcess::_FindProcess "GridTracker.exe"
Pop $R0
${If} $R0 = 0
MessageBox MB_OK|MB_ICONEXCLAMATION "GridTracker is still running. Please close GridTracker and run the installer again."
Abort
${EndIf}
call checkMSVC
FunctionEnd
Function checkMSVC
ClearErrors
ReadRegStr $0 HKCR "Installer\Dependencies\VC,redist.x86,x86,14.30,bundle" ""
IfErrors 0 +15
ClearErrors
ReadRegStr $0 HKCR "Installer\Dependencies\Microsoft.VS.VC_RuntimeMinimumVSU_x86,v14" ""
IfErrors 0 +12
ClearErrors
ReadRegStr $0 HKCR "Installer\Dependencies\Microsoft.VS.VC_RuntimeAdditionalVSU_x86,v14" ""
IfErrors 0 +9
ClearErrors
ReadRegStr $0 HKCR "Installer\Products\679E80FBE29B63345BF612177149674C" "PackageCode"
IfErrors 0 +6
MessageBox MB_YESNO|MB_ICONQUESTION "GridTracker requires MSVC Runtime Libraries. Do you want to install them now?" IDYES InstallNow IDNO Next
InstallNow:
Call InstallMSVC
Goto Next
Next:
FunctionEnd
Function InstallMSVC
NSISdl::download "https://aka.ms/vs/17/release/vc_redist.x86.exe" "$TEMP\vc_redist.x86.exe" $0
StrCmp $0 success fail
success:
ExecWait '"$TEMP\vc_redist.x86.exe" /PASSIVE /NORESTART' $1
Goto is_reboot_requested
fail:
MessageBox MB_OK|MB_ICONEXCLAMATION "Unable to download MSVC Runtime files. Please see GridTracker.org for details on download"
is_reboot_requested:
${If} $1 = 1641
${OrIf} $1 = 3010
SetRebootFlag true
${EndIf}
FunctionEnd
InstType "Full"
InstType "Minimal"
Section "Program Files (Required)"
SectionIn 1 2 RO
SetOverwrite ifdiff
SetOutPath $InstDir
File /r "${BUILDPATH}/dist/GridTracker-${VERSION}-win-x86/*"
CreateDirectory "${SMPATH}"
CreateShortcut "${SMPATH}\${NAME}.lnk" "$InstDir\${NAME}.exe"
CreateShortcut "${SMPATH}\Help Wiki.lnk" "${HELPURL}" "" "$InstDir\gridview.ico"
CreateShortcut "${SMPATH}\Uninstall.lnk" $INSTDIR\uninstall.exe
WriteRegStr HKLM "${REGPATH_UNINSTSUBKEY}" "DisplayName" "${NAME}"
WriteRegStr HKLM "${REGPATH_UNINSTSUBKEY}" "DisplayVersion" "${VERSION}"
WriteRegStr HKLM "${REGPATH_UNINSTSUBKEY}" "Publisher" "${COMPANY}"
WriteRegStr HKLM "${REGPATH_UNINSTSUBKEY}" "URLInfoAbout" "${URL}"
WriteRegStr HKLM "${REGPATH_UNINSTSUBKEY}" "DisplayIcon" "$InstDir\gridview.ico"
WriteRegStr HKLM "${REGPATH_UNINSTSUBKEY}" "UninstallString" '"$InstDir\uninstall.exe"'
WriteRegStr HKLM "${REGPATH_UNINSTSUBKEY}" "QuietUninstallString" '"$InstDir\uninstall.exe" /S'
WriteRegStr HKLM "${REGPATH_UNINSTSUBKEY}" "InstallPath" $InstDir
WriteRegDWORD HKLM "${REGPATH_UNINSTSUBKEY}" "NoModify" 1
WriteRegDWORD HKLM "${REGPATH_UNINSTSUBKEY}" "NoRepair" 1
WriteUninstaller "$InstDir\uninstall.exe"
SectionEnd
# Section for PDF when we have it #
/*
Section "Offline Help Docs"
SectionIn 1
SectionEnd
*/
# Section for Locales when we have it #
/*
SectionGroup "Locales"
SetOutPath $INSTDIR\locales
Section "de"
SectionEnd
Section "es"
SectionEnd
SectionGroupEnd
*/
# Give User Option for Desktop Shortcut #
Section "Desktop Shortcut"
SectionIn 1
CreateShortcut /NoWorkingDir "$DESKTOP\${NAME}.lnk" "$InstDir\${NAME}.exe"
SectionEnd
# Uninstall stuffs #
Section -un.Main
RmDir /r /REBOOTOK $INSTDIR
RmDir /r /REBOOTOK "${SMPATH}"
Delete /REBOOTOK "$DESKTOP\${NAME}.lnk"
DeleteRegKey HKLM "${REGPATH_UNINSTSUBKEY}"
Delete "$InstDir\uninstall.exe"
SectionEnd