18 Commits

Author SHA1 Message Date
alessandro90
6e234a1530 Add a changelog 2019-08-01 15:33:56 +02:00
Marco
f5bad77a36 Linux deploy script bug fix 2019-08-01 01:28:26 +02:00
alessandro90
d386555c16 Loop button for audio samples always enabled
(cherry picked from commit 09afe6b016342fe36b7e306f863f581dcd65cb18)
2019-07-31 23:33:42 +02:00
Marco
0d2d395639 Merge remote-tracking branch 'origin/audio_loop' 2019-07-31 23:16:14 +02:00
alessandro90
03f0f7a81f Easier way to change the displayed release version 2019-07-31 22:58:27 +02:00
alessandro90
f23359f3cb Close #3 Implement a loop functionality for audio samples 2019-07-31 22:39:04 +02:00
alessandro90
0cc99f0ac9 Fix #7 Show maximized window at startup 2019-07-31 19:47:54 +02:00
Marco
dbae83eb89 Changed few URL protocol to the 'over SSL' version
(cherry picked from commit 7db82fd09efc6f66365057777c0f10e7a51cdcc2)
2019-07-31 19:40:23 +02:00
alessandro90
fecadb132f Merge branch 'SSL_test' 2019-07-31 19:37:53 +02:00
alessandro90
e5e80b693e Fix #6 Add cacert.pem also for async downloads 2019-07-31 19:36:04 +02:00
Marco
d1699db5a6 Merge branch 'SSL_fix' 2019-07-29 15:33:18 +02:00
alessandro90
0735039213 Remove other unused imports 2019-07-24 22:06:37 +02:00
alessandro90
09abbf5d0c Remove unused import 2019-07-24 21:55:37 +02:00
alessandro90
0732dcb816 Always include cacert in get_pool_manager 2019-07-24 21:08:24 +02:00
alessandro90
0e6c826ac2 Add full cacert support for all platforms also for the checksum.
Distinguish compiled and script case. Adjust .spec files
2019-07-24 20:45:20 +02:00
Marco
1a35d12609 Urllib3 downgrade to 1.24.3 for Request compatibility 2019-07-24 18:26:34 +02:00
Marco
0fa4a40869 Urllib3 SSL secure connection with server. Works with all OSs 2019-07-24 18:25:28 +02:00
Marco
dcf726a72a Added SSL certificates into the bundle 2019-07-24 18:17:38 +02:00
13 changed files with 4840 additions and 121 deletions

25
CHANGELOG.md Normal file
View File

@@ -0,0 +1,25 @@
# Changelog
This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html) and the format is based on The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
The first release is [3.0.0] because this is actually the third major version (completely rewritten) of the software.
## [Unreleased]
## [3.0.1] - 2019-8-1
### Added
- The audio player has now a loop button ([#3](https://github.com/AresValley/Artemis/pull/3)).
- The project has now a Changelog file.
### Fixed
- Added SSL certificates for all downloads. Avoid a crash of the program for certain systems ([#6](https://github.com/AresValley/Artemis/pull/6)).
- Start the application in maximized mode. The label in the propagation data are well displayed ([#7](https://github.com/AresValley/Artemis/pull/7)).
- Compile the executable for Linux on an older version to avoid GLIBC compatibilities issues ([#8](https://github.com/AresValley/Artemis/pull/8)).
## [3.0.0] - 2019-07-23
First release.
<!-- Links definitions -->
[Unreleased]: https://github.com/AresValley/Artemis/compare/v3.0.1...HEAD
[3.0.1]: https://github.com/AresValley/Artemis/compare/v3.0.0...v3.0.1
[3.0.0]: https://github.com/AresValley/Artemis/releases/tag/v3.0.0

View File

@@ -1,7 +1,7 @@
pandas>=0.24.2
certifi>=2019.6.16
aiohttp>=3.5.4
urllib3>=1.25.3
urllib3==1.24.3
pygame>=1.9.6
QtAwesome>=0.5.7
PyQt5==5.12.2

View File

@@ -5,6 +5,7 @@ block_cipher = None
import glob, os
data_file = [(f, '.') for f in glob.glob('*.[pu][yi]') if f != "artemis.py"]
data_file.append(('cacert.pem', '.'))
a = Analysis(['artemis.py'],
pathex=[os.getcwd()],

View File

@@ -23,12 +23,12 @@ if [ -e "$file" ]; then
read -p "" doit
case $doit in
u|U)
echo "#!/usr/bin/env xdg-open" > /home/$USER/.local/share/applications/artemis.desktop
echo "[Desktop Entry]" >> /home/$USER/.local/share/applications/artemis.desktop
echo "Name=Artemis" >> /home/$USER/.local/share/applications/artemis.desktop
echo "Type=Application" >> /home/$USER/.local/share/applications/artemis.desktop
echo "StartupWMClass=artemis3" >> /home/$USER/.local/share/applications/artemis.desktop
echo "Exec=sh -c 'cd $DIR && ./artemis' " >> /home/$USER/.local/share/applications/artemis.desktop
echo "Terminal=False" >> /home/$USER/.local/share/applications/artemis.desktop
echo "Exec=sh -c \"cd $DIR && ./Artemis\" " >> /home/$USER/.local/share/applications/artemis.desktop
echo "Terminal=false" >> /home/$USER/.local/share/applications/artemis.desktop
echo "Icon=artemis3" >> /home/$USER/.local/share/applications/artemis.desktop
sudo cp ./artemis3.svg /usr/share/icons/
echo "Link Updated!"
@@ -41,12 +41,12 @@ if [ -e "$file" ]; then
*) echo "Sorry! Invalid option $REPLY";;
esac
else
echo "#!/usr/bin/env xdg-open" > /home/$USER/.local/share/applications/artemis.desktop
echo "[Desktop Entry]" >> /home/$USER/.local/share/applications/artemis.desktop
echo "Name=Artemis" >> /home/$USER/.local/share/applications/artemis.desktop
echo "Type=Application" >> /home/$USER/.local/share/applications/artemis.desktop
echo "StartupWMClass=artemis3" >> /home/$USER/.local/share/applications/artemis.desktop
echo "Exec=sh -c 'cd $DIR && ./artemis' " >> /home/$USER/.local/share/applications/artemis.desktop
echo "Terminal=False" >> /home/$USER/.local/share/applications/artemis.desktop
echo "Exec=sh -c \"cd $DIR && ./Artemis\" " >> /home/$USER/.local/share/applications/artemis.desktop
echo "Terminal=false" >> /home/$USER/.local/share/applications/artemis.desktop
echo "Icon=artemis3" >> /home/$USER/.local/share/applications/artemis.desktop
sudo cp ./artemis3.svg /usr/share/icons/
echo "

View File

@@ -5,6 +5,7 @@ block_cipher = None
import glob,os
data_file = [(f, '.') for f in glob.glob('*.[pu][yi]') if f != "artemis.py"]
data_file.append(('cacert.pem', '.'))
a = Analysis(['artemis.py'],
pathex=[os.getcwd()],

View File

@@ -5,6 +5,7 @@ import glob, os
data_file = [(f, '.') for f in glob.glob('*.[pu][yi]') if f != "artemis.py"]
data_file.append(('themes','./themes'))
data_file.append(('cacert.pem', '.'))
a = Analysis(['artemis.py'],
pathex=[os.getcwd()],

View File

@@ -19,8 +19,7 @@ from PyQt5.QtGui import QPixmap
from PyQt5 import uic
from PyQt5.QtCore import (QFileInfo,
Qt,
pyqtSlot,
QRect,)
pyqtSlot,)
from audio_player import AudioPlayer
from weatherdata import SpaceWeatherData, ForecastData
@@ -43,11 +42,12 @@ from utilities import (checksum_ok,
is_undef_band,
format_numbers,
resource_path,
safe_cast)
safe_cast,
is_mac_os)
# import default_imgs_rc
__VERSION__ = "3.0.1"
qt_creator_file = resource_path("artemis.ui")
Ui_MainWindow, _ = uic.loadUiType(qt_creator_file)
@@ -59,6 +59,7 @@ class Artemis(QMainWindow, Ui_MainWindow):
"""Set all connections of the application."""
super().__init__()
self.setupUi(self)
self.setWindowTitle("ARTΣMIS " + __VERSION__)
self.set_initial_size()
self.closing = False
self.download_window = DownloadWindow()
@@ -493,6 +494,7 @@ class Artemis(QMainWindow, Ui_MainWindow):
self.pause,
self.stop,
self.volume,
self.loop,
self.audio_progress,
self.active_color,
self.inactive_color
@@ -845,18 +847,12 @@ class Artemis(QMainWindow, Ui_MainWindow):
"""Handle high resolution screens.
Set bigger sizes for all the relevant fixed-size widgets.
Also by default set the size to 3/4 of the available space both
vertically and horizontally.
"""
d = QDesktopWidget().availableGeometry()
center = d.center()
w = d.width()
h = d.height()
rect = QRect()
rect.setHeight((3 * h) // 4)
rect.setWidth((3 * w) // 4)
rect.moveCenter(center)
self.setGeometry(rect)
self.showMaximized()
if w > 3000 or h > 2000:
self.fixed_audio_and_image.setFixedSize(540, 1150)
self.fixed_audio_and_image.setMaximumSize(540, 1150)
@@ -1627,7 +1623,7 @@ class Artemis(QMainWindow, Ui_MainWindow):
if __name__ == '__main__':
# For executables running on Mac Os systems.
if hasattr(sys, "_MEIPASS") and sys.platform == 'darwin':
if hasattr(sys, "_MEIPASS") and is_mac_os():
os.chdir(sys._MEIPASS)
my_app = QApplication(sys.argv)

View File

@@ -17,7 +17,7 @@
</sizepolicy>
</property>
<property name="windowTitle">
<string>ARTΣMIS 3.0</string>
<string>ARTΣMIS</string>
</property>
<property name="windowIcon">
<iconset resource="default_imgs.qrc">
@@ -9177,8 +9177,8 @@ STORM</string>
<property name="styleSheet">
<string notr="true"/>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<layout class="QGridLayout" name="gridLayout_11">
<item row="0" column="0">
<widget class="QWidget" name="audio_widget" native="true">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
@@ -9199,7 +9199,101 @@ QPushButton {
}</string>
</property>
<layout class="QGridLayout" name="gridLayout_3">
<item row="3" column="0" colspan="3">
<item row="0" column="0">
<widget class="QPushButton" name="play">
<property name="enabled">
<bool>false</bool>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>45</width>
<height>45</height>
</size>
</property>
<property name="text">
<string/>
</property>
<property name="checkable">
<bool>false</bool>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QPushButton" name="pause">
<property name="enabled">
<bool>false</bool>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>45</width>
<height>45</height>
</size>
</property>
<property name="text">
<string/>
</property>
<property name="checkable">
<bool>false</bool>
</property>
</widget>
</item>
<item row="0" column="2">
<widget class="QPushButton" name="stop">
<property name="enabled">
<bool>false</bool>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>45</width>
<height>45</height>
</size>
</property>
<property name="text">
<string/>
</property>
</widget>
</item>
<item row="0" column="3">
<widget class="QPushButton" name="loop">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>45</width>
<height>45</height>
</size>
</property>
<property name="text">
<string/>
</property>
<property name="checkable">
<bool>true</bool>
</property>
</widget>
</item>
<item row="2" column="0" colspan="4">
<widget class="QProgressBar" name="audio_progress">
<property name="enabled">
<bool>false</bool>
@@ -9227,79 +9321,7 @@ QPushButton {
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QPushButton" name="play">
<property name="enabled">
<bool>false</bool>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>70</width>
<height>70</height>
</size>
</property>
<property name="text">
<string/>
</property>
<property name="checkable">
<bool>false</bool>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QPushButton" name="pause">
<property name="enabled">
<bool>false</bool>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>70</width>
<height>70</height>
</size>
</property>
<property name="text">
<string/>
</property>
<property name="checkable">
<bool>false</bool>
</property>
</widget>
</item>
<item row="0" column="2">
<widget class="QPushButton" name="stop">
<property name="enabled">
<bool>false</bool>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>70</width>
<height>70</height>
</size>
</property>
<property name="text">
<string/>
</property>
</widget>
</item>
<item row="2" column="0" colspan="3">
<item row="1" column="0" colspan="4">
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QLabel" name="volume_label">
@@ -9368,7 +9390,7 @@ QSlider::handle:horizontal {
</layout>
</widget>
</item>
<item>
<item row="1" column="0">
<widget class="QLabel" name="spectrogram">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">

View File

@@ -19,17 +19,21 @@ class AudioPlayer(QObject):
pause,
stop,
volume,
loop,
audio_progress,
active_color,
inactive_color):
"""Initialize the player."""
super().__init__()
self._active_color = active_color
self._inactive_color = inactive_color
self._paused = False
self._first_call = True
self._play = play
self._pause = pause
self._stop = stop
self._volume = volume
self._loop = loop
self._audio_progress = audio_progress
self._audio_file = None
self._timer = QTimer()
@@ -38,22 +42,45 @@ class AudioPlayer(QObject):
self._pause.clicked.connect(self._pause_audio)
self._stop.clicked.connect(self._stop_audio)
self._volume.valueChanged.connect(self._set_volume)
self._loop.clicked.connect(self._set_loop_icon)
self._play.setIconSize(self._play.size())
self._pause.setIconSize(self._pause.size())
self._stop.setIconSize(self._stop.size())
self._loop.setIconSize(self._loop.size())
self.refresh_btns_colors(active_color, inactive_color)
@pyqtSlot()
def _set_loop_icon(self):
"""Set the icon for the loop audio button."""
if self._loop.isChecked():
loop_icon = qta.icon(
'fa5s.redo-alt',
color=self._active_color,
color_disabled=self._inactive_color,
animation=qta.Spin(self._loop)
)
else:
loop_icon = qta.icon(
'fa5s.redo-alt',
color=self._active_color,
color_disabled=self._inactive_color
)
self._loop.setIcon(loop_icon)
def refresh_btns_colors(self, active_color, inactive_color):
"""Repaint the buttons of the widgetd after the theme has changed."""
self._play.setIcon(qta.icon('fa5.play-circle',
self._active_color = active_color
self._inactive_color = inactive_color
self._play.setIcon(qta.icon('fa5s.play',
color=active_color,
color_disabled=inactive_color))
self._pause.setIcon(qta.icon('fa5.pause-circle',
self._pause.setIcon(qta.icon('fa5s.pause',
color=active_color,
color_disabled=inactive_color))
self._stop.setIcon(qta.icon('fa5.stop-circle',
self._stop.setIcon(qta.icon('fa5s.stop',
color=active_color,
color_disabled=inactive_color))
self._set_loop_icon()
@pyqtSlot()
def _set_volume(self):
@@ -72,7 +99,6 @@ class AudioPlayer(QObject):
mixer.quit()
self._audio_progress.reset()
self._enable_buttons(False, False, False)
self._paused = False
@pyqtSlot()
def _update_bar(self):
@@ -81,7 +107,11 @@ class AudioPlayer(QObject):
if pos == -1:
self._timer.stop()
self._audio_progress.reset()
self._enable_buttons(True, False, False)
if self._loop.isChecked():
self._play_audio()
self._enable_buttons(False, True, True)
else:
self._enable_buttons(True, False, False)
else:
self._audio_progress.setValue(pos)

4619
src/cacert.pem Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -123,13 +123,13 @@ class Constants:
SPACE_WEATHER_SGAS = "https://services.swpc.noaa.gov/text/sgas.txt"
SPACE_WEATHER_GEO_STORM = "https://services.swpc.noaa.gov/text/3-day-forecast.txt"
SPACE_WEATHER_INFO = "https://www.swpc.noaa.gov/sites/default/files/images/NOAAscales.pdf"
SPACE_WEATHER_IMGS = ["http://www.mmmonvhf.de/eme/eme.png",
"http://www.mmmonvhf.de/ms/ms.png",
"http://www.mmmonvhf.de/es/es.png",
"http://www.mmmonvhf.de/solar/solar.png",
"http://amunters.home.xs4all.nl/eskip50status.gif",
"http://amunters.home.xs4all.nl/eskip70status.gif",
"http://amunters.home.xs4all.nl/eskipstatus.gif",
SPACE_WEATHER_IMGS = ["https://www.mmmonvhf.de/eme/eme.png",
"https://www.mmmonvhf.de/ms/ms.png",
"https://www.mmmonvhf.de/es/es.png",
"https://www.mmmonvhf.de/solar/solar.png",
"https://amunters.home.xs4all.nl/eskip50status.gif",
"https://amunters.home.xs4all.nl/eskip70status.gif",
"https://amunters.home.xs4all.nl/eskipstatus.gif",
"https://amunters.home.xs4all.nl/eskipstatusNA.gif",
"https://amunters.home.xs4all.nl/aurorastatus.gif"]
SEARCH_LABEL_IMG = "search_icon.png"

View File

@@ -7,10 +7,10 @@ from shutil import rmtree
from time import perf_counter
from zipfile import ZipFile
import aiohttp
import urllib3
from PyQt5.QtCore import QThread, pyqtSignal
from constants import Constants, Database, ChecksumWhat
from utilities import checksum_ok
from utilities import checksum_ok, get_pool_manager, get_cacert_file
import ssl
# Needed for pyinstaller compilation.
import encodings.idna
@@ -87,7 +87,7 @@ class DownloadThread(BaseDownloadThread):
raw_data = bytes(0)
sub_data = bytes(0)
try:
self._db = urllib3.PoolManager().request(
self._db = get_pool_manager().request(
'GET',
Database.LINK_LOC,
preload_content=False,
@@ -157,7 +157,11 @@ class _AsyncDownloader:
async def _download_resource(self, session, link):
"""Return the content of 'link' as bytes."""
resp = await session.get(link)
ssl_context = ssl.create_default_context(
purpose=ssl.Purpose.SERVER_AUTH,
cafile=get_cacert_file()
)
resp = await session.get(link, ssl=ssl_context)
return await resp.read()

View File

@@ -2,10 +2,8 @@ from functools import partial
import hashlib
import sys
import os
from pandas import read_csv
from PyQt5.QtWidgets import QMessageBox
import urllib3
from constants import Constants, Signal, Database, ChecksumWhat
@@ -51,6 +49,25 @@ def pop_up(cls, title, text,
return msg
def is_mac_os():
"""Return True if running OS is Mac."""
return sys.platform == 'darwin'
def get_cacert_file():
"""Return the path to the cacert.pem file."""
if hasattr(sys, "_MEIPASS"):
ca_certs = os.path.join(sys._MEIPASS, 'cacert.pem')
else:
ca_certs = 'cacert.pem'
return ca_certs
def get_pool_manager():
"""Return a urllib3.PoolManager object."""
return urllib3.PoolManager(ca_certs=get_cacert_file())
def checksum_ok(data, what):
"""Check whether the checksum of the 'data' argument is correct."""
code = hashlib.sha256()
@@ -62,10 +79,13 @@ def checksum_ok(data, what):
else:
raise ValueError("Wrong entry name.")
try:
reference = read_csv(
# The downloaded file is a csv file with columns (last version == last line):
# data.zip_SHA256 | db.csv_SHA256 | Version | Creation_date
reference = get_pool_manager().request(
'GET',
Database.LINK_REF,
delimiter=Database.DELIMITER
).iat[-1, n]
timeout=4.0
).data.decode("utf-8").splitlines()[-1].split(Database.DELIMITER)[n]
except Exception:
raise
return code.hexdigest() == reference