From c9a0bd50c4e0404efadbdcbb1d90767456ad48d7 Mon Sep 17 00:00:00 2001 From: Thomas Jacquin Date: Mon, 1 May 2023 09:21:23 -0700 Subject: [PATCH] Website configuration improvements (#135) * index.php: allow customizations of home page * Replaced config.js and virtualsky.json with configuration.json, which has a section for home page customizations. * allsky.css: add for home page customizations * allsky.css: removed Eric's changes * Delete config.js Replaced by configuration.json * controller.js: support home page customizations * "loading.jpg" is now defined in the configuration file. * Removed unneeded comment * Delete virtualsky.json Replaced by configuration.json * controller.js: support customized home page * Load "configuration.json" instead of old "virtualsky.json". * Only load "configuration.json" once - on subsequent attempts (normally from resize) use the cached data. This means if a user updates "configuration.json" they'll need to reload the browser manually. * Removed unneeded code that checks for new virtualsky package (which we're now using). * Resolved merge conflict - restored newer version * index.php: misc changes * Add some comments. * Automatically determine "og_image_type" based on the extension of "og_image". * Improved handling of unspecified background image. * index.php: rename variable * "showOverlayIcon" is a better description of what the variable does - if true, the Overlay Icon is shown. * controller.js: needToUpdate * Make "XX_NEED_TO_UPDATE_XX" a variable since it's used in a couple places. * Fix: "config.js" should be "configuration.json". * index.php: add $title Add $title from the "homePage" variable to the "config" javascript array since it's used in both "homePage" variable and "config" variable. * controller.js: delete overlaySize and others * Use overlayWidth and overlayHeight instead of overlaySize. * data.virtualSky is no longer the name of the json variable; it's data.config. * Put message styles in allsky.css as classes. * Commented out or remove a couple console.log()'s that weren't needed anymore. * allsky.css: Add some classes They were styles in controller.js. * Create configuration.json This file combines the old "config.js" and "virtualsky.json" files, plus adds additional settings to customize the website home page. This file will likely change as more testing is done. * configuration.json: fix JSON format * Fix two cases of incorrect JSON format. * Remove space before ":" to be consistent with everything else. * Delete allsky-logo.png Will replace with smaller version that doesn't have to be scaled down in size by the browser. * add smaller allsky-logo.png * functions.php: use can_make_video_thumbnails() * functions.php: additional checks * allsky.css: add thumbnailError class * controller.js: use correct number for average * controller.js update Kp values Update the meanings of the Kp values based on NOAA and mostly described in https://auroraforecast.is/kp-index/. * controller.js: fix Kp values The names must be CSS classes so can't have spaces in them. * allsky.css: updated classes for Kp values * configuration.json: reorder * Put "config" options first since that's what people had to edit in the past. * Put sidebar and popoutIcons fields on one line to significantly shorten the file. Few people will edit them. * Rename "localLink" to "personalLink" to better reflect what it's for. * index.php: rename localLink to personalLink Also ignore null sidebar URLs * allsky.css: rename localLink to personalLink * index.php: get homePage.onPi variable * configuration.json: set onPi * "onPi" determins whether or not the website is on a Pi, in which case we know we can produce thumbnails. Some remote servers can also produce them but most can't. There doesn't appear to be any good way to determine if they can be produced on remote servers. * functions.php: use $onPi * If included from index.php, $onPi will not be set so functions.php will read the configuration file. * When clicking on the link for keogram, startrails, or timelapse files, $onPi WILL be set so the configuration file isn't read. * Checking for "arm" in the uname to determine if we're on a Pi doesn't always work - some NAS are arm but not Pi's, so we add a configuration variable "onPi" that needs to be set manually. Default is "true" so remote servers need to set to "false". * index.php: include "functions.php" * functions.php will read the configuration file when called from index.php as well as called from other scripts, if needed. * Pass the "onPi" configuration variable to keogram, startrails, and timelapse archive pages. * show_thumbnails.php: set "$configFilePrefix" $configFilePrefix is set so functions.php knows where the configuration file is when called from the archive pages. * functions.php: fix $onPi setting * Fix $onPi setting - the ".['onPi']" shouldn't have been there. * Improve the message when it appears the software hasn't been configured to take into account remote machines. * index.php: Add sidebarStyle to allow people to move the left sidebar (or apply any other style they want) so it doesn't cover text on the image. * configuration.json: add sidebarStyle * Added version file * index.php: misc changes * Added and * Moved items from style="xxx" to class="xxx". * Removed some type="text/javascript" since that's the default and to make those lines consistent with similar lines. * Combined a few statements into one block for ease of reading. * allsky-font.css: add mini-timelapse icon * Add mini-timelapse font * configuration.json: add mini-timelapse Use "no_url" so it doesn't display by default. * Delete configuration.json The source for this file is now stored in ~/allsky/config.repo. When installing the Allsky Website on the Pi, the file will be copied to the correct location. When installing the Allsky Website on a remote server, users should first execute "cd allsky; website/install.sh --remote" to have this file copied to remote server, THEN install the code on the server. * allsky.css: temporarily restore to original Will put back after merging master into this branch. Right now there are conflicts that need the GitHub desktop to resolve, and I don't have that. * allsky.css: put back to prior version The changes from master have been merged into this branch, so restore the branch's file * allsky.css: save in UNIX format * controller.js: misc changes * Use constants for "data.json" and "configuration.json". * Allow latitude and longitude with, or without N, S, E, W. * Change wording of auroraforecast scales 0 and 1 to match auroraforcast.is/kp-index. * Fix some indenting problems. * allsky.css: make sure info box is above all else * controller.js: improve reading data.json * Bug fix: data.json wasn't re-read if the browser window is hidden, which means the next day the data.json file may be marked as "old". Fix that by checking the status of the file every 5 intervals. Not sure if 5 is the best number, but it works. * Updated some comments. * Only call getHiddenProperty() once since it never changes. * Removed some unneeded, commented out code. * controller.js: latitude and longitude bug fixes * Was calculating substr() wrong - it starts at 0. * The web page displays $scope.latitude, not config.latitude. Also applies to longitude. * Since virtualsky.js, which uses $scope.latitude, requires numbers, set $scope.latitude to a number, but $scope.s_latitude to a string with N, S, E, W. This requires a change to the configuration.json file to prepend "s_" to the latitude. * controller.js: set imageHeight Allow the image height to be set the configuration.json, rather than allsky.css. * allsky.css: allow easier changing of values * Added comment at the top describing how users can change the imageHeight. * No longer encourage users to change allsky.css - it will be overwritten at the next upgrade. * Support using variable name instead of URL * This is consistent with what the pop out does. Initially this will be used to display an icon to view the current image full-size using the "imageName" variable. Also: * Change spaces to tabs. * Check for "false" values, which return "" from v(). * controller.js: get resize working * Resize in virtualsky.js doesn't work, so we let controller.js do most of the work. It sets the size of some containers and tells virtualsky.js the new size so it can scale the overlay canvas. A hack, but it works well. * * virtualsky.js: fix resize, plus others * Added cardinalpoints_fontsize. * Added the ability for users to specify colors of all the overlay objects. * Fix resize so it works. * Only create the objects for position and date if the user wants to see them. * virtualsky.js: remove test color * During testing I replaced the color for "cardinal". This restores it. * index.php: Handle double quotes in values * index.php: make user specify ALL fa classes This gives them more flexibility since they can use "fab" instead "fa" primary class. Or other changes. The configuration.json.repo file has been updated to include all the classes. * try to support PHP 5.3 and earlier They don't support [] initialization. Also, fix typo bug in variable name * virtualsky.js: Allow changing colors Also, don't use outerWidth/outerHeight since they never change * show_thumbnails.php: use jquery3.6.0 * use jquery3.6.0 Also, remove camera-info class - it's not needed anymore * index.php: use bootstrap 5.2.0 Version 3.6.0 isn't supported by bootstrap 3.3.6, so upgrade to bootstrap 5.2.0. * index.php: change icon for camera info * index.php: make more generic * Added "display" field to left and right sections to determine whether or not an item is displayed. * Added "style" to left and right. * Added "other" on left so ALL icons can be displayed via configuration.json. * allsky.css: minor change to right-size popout * controller.js: add versions, and improve msg * Add AllskyVersion and AllskyWebsiteVersion. * Improve the message displayed with the sunset data is old. * controller.js: s/at/on/ * index.php: 2 bug fixes * Need to check if $val is an array, since we can't print it. * Need to set $style before using it. * created viewSettings.php * functions.php: bug fix: use array(), not $array() * allsky.css: s/sidebar/leftSidebar * index.php: s/sidebar/leftSidebar * virtualsky-planets.js: jupiter bug fix Jupiter didn't always appear, and when it did, it sometimes jumped around. This fix isn't perfect though - going backward 6 days by pressing "=" make it disappear, then reappear at 7 days. Don't know if a formula is bad or the Jupiter data is bad. * Add new language files * master.json: updates from Stuartg * translate.js: newer version * index.html: update version * en.json: updated version * Add gl.json * es: updated version * en.json: restore correct version Accidently put Spanish version in this file; this commit restores the English version * en-US.json: not needed - same as en.json * index.php: don't check for onPi Let other pages check if it's needed * Always read config file onPi is no longer passed on the URL * functions.php: return 0 if boolean is false For whatever reason, reading a "false" boolean from a JSON array return "", not 0. However, reading a "true" value returns a 1. We want the v() function to return 0 if the value (or default) is false. * show_thumbnails.php: read config file Instead of checking if the analyticsTracking.js file is > 50 characters big, read the config file to determine if the file should be included * functions.php: bug fix: need isset() first * allsky.css: #starmap_container change index.php now sets the size of the starmap_container. Also, fixed how images are centered. * controller.js: major changes * controller.js now resizes everything. I couldn't get it to work where virtualsky.js would resize some things and controller.js would resize others. If you're better at javascript and css, perhaps you can get it to work. * Renamed some variables to be more descriptive. * virtualsky.js: do resize overlay It's now done in controller.js * index.php: set width of image * Also, pass in imageBorder. * viewSettings.php: support two ways * Support displaying settings in WebUI-like mode or basic mode, depending on whether or not the viewSettings/allskySettings.php file exists (it displays in WebUI mode). * viewSettings.php: make bootstrap.min.css a link so it's one less file to upload. * Create README.txt * index.php: create directories if needed The "?check" option is used when called from "allsky/website/install.sh --remote" * Update version * Delete NoThumbnail.psd moved to allsky package * controller.js: POST_END_OF_NIGHT_DATA gone Remove references to it. * viewSettings.php: Make panel header easier to read This also makes it look like the WebUI. * Update version, still in dev * Upscaled logo to fix low res issue * functions.php: fix typo * controller.js: fix latitude and longitude $scope.latitude and $scope.longitude were set to numeric values, but not the values passed to function that creates the overlay. * functions.php: add get_decoded_json_file() * Update version * Update version to official 2023.05.01 * README.md: Mention new Allsky release * Update README.md * Update README.md --------- Co-authored-by: EricClaeys <83164203+EricClaeys@users.noreply.github.com> Co-authored-by: Thomas Jacquin --- NoThumbnail.psd | Bin 75304 -> 0 bytes README.md | 8 +- allsky-font.css | 30 ++ allsky-logo.png | Bin 14114 -> 2774 bytes allsky.css | 114 +++++-- config.js | 21 -- controller.js | 426 +++++++++++++++++------- fonts/mini-timelapse.eot | Bin 0 -> 1404 bytes fonts/mini-timelapse.svg | 11 + fonts/mini-timelapse.ttf | Bin 0 -> 1240 bytes fonts/mini-timelapse.woff | Bin 0 -> 1316 bytes functions.php | 116 ++++++- index.php | 263 ++++++++++++--- show_thumbnails.php | 15 +- version | 2 +- viewSettings.php | 212 ++++++++++++ viewSettings/README.txt | 1 + virtualsky.json | 30 -- virtualsky/lang/de.json | 174 ++++++++++ virtualsky/lang/en-US.json | 174 ---------- virtualsky/lang/en.json | 2 +- virtualsky/lang/es.json | 347 ++++++++++--------- virtualsky/lang/gl.json | 194 +++++++++++ virtualsky/lang/index.html | 118 ++++--- virtualsky/lang/master.json | 182 +++++----- virtualsky/lang/nl.json | 174 ++++++++++ virtualsky/lang/pl.json | 174 ++++++++++ virtualsky/lang/translate.js | 550 ++++++++++++++++++++----------- virtualsky/virtualsky-planets.js | 2 +- virtualsky/virtualsky.js | 64 +++- 30 files changed, 2478 insertions(+), 926 deletions(-) delete mode 100644 NoThumbnail.psd delete mode 100644 config.js create mode 100644 fonts/mini-timelapse.eot create mode 100644 fonts/mini-timelapse.svg create mode 100644 fonts/mini-timelapse.ttf create mode 100644 fonts/mini-timelapse.woff create mode 100644 viewSettings.php create mode 100644 viewSettings/README.txt delete mode 100755 virtualsky.json create mode 100644 virtualsky/lang/de.json delete mode 100755 virtualsky/lang/en-US.json create mode 100644 virtualsky/lang/gl.json create mode 100644 virtualsky/lang/nl.json create mode 100644 virtualsky/lang/pl.json diff --git a/NoThumbnail.psd b/NoThumbnail.psd deleted file mode 100644 index 5329b310bb0b86f16268cf483c10b86bb51dd030..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 75304 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 Allsky Website. diff --git a/allsky-font.css b/allsky-font.css index b2a92d2..cb0edae 100755 --- a/allsky-font.css +++ b/allsky-font.css @@ -28,3 +28,33 @@ content: "\e900"; } +@font-face { + font-family: 'mini-timelapse'; + src: url('fonts/mini-timelapse.eot?dynh3c'); + src: url('fonts/mini-timelapse.eot?dynh3c#iefix') format('embedded-opentype'), + url('fonts/mini-timelapse.ttf?dynh3c') format('truetype'), + url('fonts/mini-timelapse.woff?dynh3c') format('woff'), + url('fonts/mini-timelapse.svg?dynh3c#mini-timelapse') format('svg'); + font-weight: normal; + font-style: normal; + font-display: block; +} + +[class^="icon-"], [class*=" icon-"] { + /* use !important to prevent issues with browser extensions that change fonts */ + font-family: 'mini-timelapse' !important; + speak: never; + font-style: normal; + font-weight: normal; + font-variant: normal; + text-transform: none; + line-height: 1; + + /* Better Font Rendering =========== */ + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} + +.icon-mini-timelapse:before { + content: "\ea15"; +} diff --git a/allsky-logo.png b/allsky-logo.png index dcb202e741efaef2b0a62dd0e4a8f11a0d19fb1b..c9f9ac720a0a199a265bfc02ae40416935c918d7 100644 GIT binary patch literal 2774 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 literal 14114 zcmZ{Lby!u~7wth51qDPxIh4}fASGN$4=EkeEg&r^p@Px~NGK&BA>EB2jUXvq(jeUp zZytZ|zxO@Ad#{(n-g~XR)?9OrImS4FPZecwagaC&1OgZJL{bHTz}SQTpTB_x|Fv}; zN{7F$I*FsyZor>cH%tTIXKec?+D`CSBKltpV&PBR@FA(Ql$Nuqow>8Ck)s*H)zy{# zxvjO6iIKe-yPcy&{Due;fw+%ANj_F{OIV-u)cvh~A+|Maaqsrkk59K{nFB39Ka^}@ z`NQ_|={VndO<7s`>Y{nfWUaxLzV`YF&$_<(Xv26LSHT0RaJBYFEEp{V$Lfb=OS0`^pEp&K(Esn8Oz%g)?u)Fi=(^wDk0?!_(6~ zH+;P#XciY%9n+{@7~xMUI(tm>NTDYX!feTPReCKvgY0TFWb zwrQIM0Re$v4mB!r2%%NxeSVUNF!dB^Uc~n5P7wV3`}gmZV%DBW+HW~|)5!q=?dqsV zXRVk8I&W`pgIw*BjQ)(x7oCSe;o+BJ+A$V$txtdu4F{*LJFg zG?+3&NpW$Q){c1aoodC*c*GwsgpQoP3|wHodu1zjYirATbab?a%{@YUc5dzx*N{{# zn;m{V|AQ74i6t#5Nn~MWw$8P5&75vetS8pz2E7wCH8mfu&1Cidx7^&^X-NuyY#~um z@B6-zlya~FjsZ9b2}!aABEpkonSuTvlWQXR$Kny~moWN2qx7lcMaSh#eW``y7??VGa8+uPedQD%Y~(S@*B?bOAr zhonNz%ge$(-p|B+<|AZkFKT-d;8zJBX;CFhU7wtu;nlC>r>CcfBP{c*)LF%$SQQ+l$BcYX9({4#U|&@+tcBqOhiSxU0(h@8hxc z()!LOxwc`qBlwtESnL*Uu@T0`#;-81TSzKKFxFK0}0~wl8Zz2J!PHo*@Jb{12lhRpCzBFQwek-K9pe~Zv@~MfP z-R3j}1q?@^Eya%vRp8ahn`+zUMVNiUPJ{>eqauk? zB4`84#$ow%<7iO?NW_CMJU@7NE<>jyCay0+=DIk%9N(QRjN8l0jObB4B5AK#A&!KF zZo{OClUO@3kO=+%-DK4)N3$UT*LR2gdp<5_3LybO6$ZUCT>7xV554JFalJ6u1cFcq zW=Ccy&Hzz^DZdOi+4}zfZz>JL^A%Cb(a0kj-`(9+*452b;mz>(_kWzmb)H!9__(R3vN8d?!S`HaNy&1$6=$K*zQ-Rdj$nEd9Orq1=XBBwgzI|hsl1!4#8JwN++?0x+1XPa9h|hj8}Lt^K7O5k`0T7P5edm`qyNoH`X7CW!=^w1v&I zN6;{Ga8x{QmUL#IcVYpG2?Pxd?To ze&EsJ#M`VaMoB3t3`D*`eOOnQ{Mu;A_3;Y3r6MtEGGlSqJCoHfB@7L}6edfjJ(ich z_5E~1m^hW%mFV8R8;OeVkB;0*E`E(hR#ZHM6X%OZA!N8VQuIVgNk&EGj*6=4gHDmh za%zO~%ZjN6_1+}=X5tKTgW2jgX=K8h0|;pTtgfyu+kfe^yiH0P*xvpmLD&^<`qeIO zx$Wf7W<^uF4M*22FIR`8V%hb&HmH!upsg)?VQI+?dLbbsi$-okTDa(6qK-2~g?Rp! zuc)X(=M|N!*RBZ)kyFPu6I2rh1O^tlofpH%?cLqws*>~UuU@^{3imm~gp3h}*TPCn zOkC-)pPklp-w_3KY=~SrVD>uM`yoT+<+nOqF#dqr@jCk1U7vXRN}sFd=o>tJ>RVeY zGQY5pQdoE!_8==OtI}Qf*YNONojj7)uV3H5!4bE&=lsn3{Ehjq&kqCyMzSrucRCmn z92tu55LUm1FiwGhB&lcTGQYjdevXx5kdQ>7!$A93AEp1PyU#los}NFSE5f&d!c^waToBUDig74xeu{Hj3vO)KkJT%2--5Itx+29BplT$G>|C z!)(@(m=QH|?5@{?LP8`V#uUo!Caa0Z%U|$}ZY(VLfA=~aqv3UYyuUi!wzo2%oTI_k z;w_yQb40($1hkj>I zZEaHYo9^s5>Q>rggd+K}%OM)h3vDNbJpG@ri>LMdNsraPLlVTq#PlPQPA(z!RiS=C z+fuSmnBDhdEQpUVy!Y)34t^W=VRM&<^5Q!VCTm>Na&vDLv(nJfwV2k&usx$@W$mJT z5P7q2#o2QDdz~>A9Pw|enL<+B^~6zv5ij6eKbijSMLaAR6&00pzB#CjT!}ipdE*8; zfU`%IPWD%yJbBUpx2OdL1^jM>(PUATSy?x(<5SiiFQEf&em-u^PQeK2NJS$Za$B*? z=WM%8!27IH77{BBJl{9V*;-Z>Cq#Pgg_!CXxn_l}o}{$&7^|ow1q9|>EL@efsOV__ zuU~1SAwA0&iM#qOb5k;EhcGXhvA-^I5kO^98;Jga0rjAF0py|BdQuk`7t2$1H5~^bA-Cq2mf~&dUDlEP{r&Rg z@87>qlL{u`!;a8xuREN|8L{QOr==L({+2T(C(CtnYHNF&Ym{Bc&Q>vbWJK#`8nq@} zHOc;LOEBlXTg*}tl3}fW`PAtvE^mMMCJMXaOq;+?F)}f6jZ)sdd!2)WBWIRoSOt=L zi;Mo4#Jo1VT|cCP(&q!Mrk++-%zGYnTVBk}%!L*`lu_%CA3t9H{VhtJE7F=kuTe!q zBSVE&a{dCK91ZwY1Phz^L|nx^UL>C}52`xDvwf&snJsz{9c=^zm$C%5` zLZvUpH7buIvT!yhN=u-;{1_e{HuZFLEFMf3tave=;fC*`t4pqtr(-tg8MWKl*-3b? zGFek$ENJ8?iq5CC?z_G4B*cGaW^_9{JN7&CCml#8T4I)U>pcMOPjOh8Grcb|nfQmPdZq*Vnh~OTDI3YU$v_w7#>@>2|yjtNiq- zeTf0O+OC!KFn{-{^Vr{Nxoa@O;1=D|)@JfMOF76ZhQlCVg}3{)>V^yaOjBw-+--Ua z6Sh+OygO0l1Vx5_RKMQaYi5CBz8Yp=e|F^1B8m)^-j<^h3@?8%ZamZI-*|F%?b@|C zQLmF19ps3E&FOF`?M&ZYw*LGGGC=70Yvi;vyv8IxUEcSw87-Dd4@kfytfpvbX?Yw; z8?{~@hogW(5w!ldA-7U05e;V;khr+NWxEcAkaGh}!oN*{L%%ivW~C8dX{Oy8E_RW1 zbW;6tHPvqVJ73Ts>E7BXA%tm=7r*U<+i#Az;JR?9O6V`PRiJD3r2D_(Ylv zev*uf2|xkO+SmA%+jb6(e%Q8L+)gr&JP#zr#ox^8lOY7WPI&db_SGS|{xD7c760%i ziy|JCsIJ4885}Hp%3SnWEHrAuicWQ)lwWq~&({-facX#vN71;@8Ebu(05t;A#)zqB zo=#bBiA4`m?0rI1)j$xNPH6+Ad9{E5RxZN^MD5AnoL;Nw3LY~H3zNUUzcI41s;z12 z>xYGsJ!C$3K2=*K$I((|*(dJ6L|Dn?WER|`soCUb%aH2yXDH#(L#fiDuz`(@^_tD^ z5@u%Ug$6b@tVwRO*u>P-P9gWWuJk-QB5AiO%B`V9+-G7!30U*II&tVz((M^4uI+p&YWFTqA}e_1MZP8_p@4yQ7!EtL+xOnk0qePJ@d# zD+8G~hiy6zXi<%o4s%^X?&y5f75}g&J5*2XZ0jv2o+f#ETWc#02i?x^KEVb*+qF~P8x}fgehYz=fWu(<>YiqX}Z*oA_sXyYn zI+UkX>sDm{cjDv3gf6*=+tVT?Sk5b$n0X#PGNjz50mi2-!FP!ZVqIM2m-*58qQx;D zqW6iMT*Rb3p$jEX8 z?o0v5xP|rhSF&|?wFrlegU_`0Dcewift`zwfq_8?g)oU-{W-r*nUz^vyGU$70f%{a z0u!q$4k9oxQ0x1vDurxeN&)--v?$${ds7-I4!Xs8g)Zm9#kN)p>a&SLos7jR9ykqU zTdVw4m)x6z12JFy?fTJH6FytM!)+3hcMqrBFbNqH=donTaBkgd24K_&713yVFh_F^ zYE+5#H*@V6|Fpe7e+*+Qt&WpCHV4X2y+;T=&7yXD`JI5;?sZ?4_+Q$I1)ZiVd(fo`XN zkqeT@HFU$YHir{GhlPv$DiCGJi~J?JGSeN``=ULeuj&zpY=jvp`lPQlJ$LQ7-^nd{ z^au0R!KejE0h4T`A0+shMAxYwECsc10O8w9r2C7Di*EtqN<-t&a~Mu|v-U02rZKuO zz7MHsc~yl^ocB)K%%u zMpISKXFYWP!Gj-bsk9YP7Q~Z9y$TI~T&X>r^1R1qMfB$F+x6S&p4hm!EwB$^t)XNr z2RXU9&GB~M1EH#n@+AShX%Qm!bqeoKOHK7l)=qk*wypug?fiL*&#a&OAu*Ay7Q2H4 zuuRGkxpJtxquBH3&*M0a-WcayiGb(LZTegai(VYf#goTq*&s|B@Iaixq0SXNI`TJ$Io{JOfg zIvlQ=MVSE&17!M^{&YELX>ImT-Q3+%o>kaFB@hxl-%|}C<-vj%Ex@IDskc5}(FR-j zG*gkH#oNrxEKb;!9k4)-is?h?LfK9)WN2&d?zWY6|5t3Gmw&&GwDs3fZ-ih^V!;v- zyB29^Xy6Q&zd-H1s6|E5TMlG|%JzLI`Cvv`f3|Zo$$gO&2&Rr}BE2K=iyMoK^YY%z<9ih}$F0lE1LE4)~Nz;FNgQ)R75r7%gZVA!N3h}aFns_5ma zMm*6h5DX0^J)*&|n8p*84vkC}uKm!o%E$97xIJ2jaN_hlurW0^&n6mOmt5^a=f__b zRy*6<1h%sZ^75r}dia_xFs9X1t~q-jV;#VrTB`A;#7CYac6IwCNj?|uvUUhJAx?SbeNU&d-rbazRJ=*yzb0GtO3ae0~D0z`Hm zhq3YT!4Icj5ni4xi50o5>*TmJPj`%ulc5hR`lLW{Mz;)D5kj%`7yAWAhxM0i6XB7` z$>B_@8GoSJWR}u+^~)btg8VUmYM{G_@*V6#iI7UP4OBFle=-){9x4cy#&VdaeJ<8BA4577g+u z=bF@);$5GDe3rzLQKMV$O#x*I9mK66q;Hi(kFN>}3i5gMWEZz@em`Y@cZ+nkIFl91 z($V%Dm*e~sqiJ9_jDCJ(GB>c!c^4FfLrX`;bnqNvw6Hp{E>L<2PNab6L9T3HB_1p@ zy5*WhDghY&Tcd4P=6Pt_^5zaQ^qoaNst=Ih*7@P|-0@O!8$5j*_HrmI=?$dw)^Muu z(GrWAiC9#gMsTdY2P)16@dvJn zghDwit9t`AI8tGkY)lpNhRz8cPdSd!9txVY-NIn>#Tii&umz*C{iRYCnlwR%kjCMG7A`;KV{mDtp` zO_Rgj-KGRVr`yEDbZa%xIKYtCp)Y)o6QQl7X4%@=c~dA+u_eIv11-u;riRf)X|c9m zN|BwOUV1z0CoGQx;0$7#Y<++f_Fo&6g|u_BE&Dq;>O(XQyohUD){BptT!8h2y{%T& zUnjeFFW}lul0UDnQ{Fz9EHb%H!mi7h(Cvcd?(Po7U3HDeviJVrr6MFGKYE4FaW?h9 ztS~P)>JbxGM@yof{!%HBy@iG8vObnR0*OR)>)=3xiP}-~)2B~brIrNxuePOvt*rrI z;HqZGJACHpZ3q>vyvwd@Idn_I(UCibReM%NN>OsP7u^a@*VoJTP2A5Ox9vWuX8;5% zuB8<>TNY5vDm+;6r0=&6P*&Olfs%`8jtpSL8#s;wseA{pX=kU?m*pm=i`EmBTvKjy zxTSy_M;>x<5ukGhoac3_I9v)5x7$@!RY6|waLF>p0{x(DGJ50bL9CPU+dQQsL8qN- zeaGv-m+98JDW^m4MJ`BvX1Gu)JQ~T``9x8%70psWw3Zk=wEy$p`{Y{7saio24*d{# zBF?FXn%W851W4)))T5cV_@bPiLMO?WXPHeGY~@yiI5+RI^PWCQ3=hX& z>`n{@@INNVeL7P9f(+;8P2$rm2S0_JL7dh0k`E#GIC#sS0)8bHvoY0{h7yM4v-)bR zW(>RHb~N)|pzbSM&i5&EQc=4~QxVZi~Pfx24LA&M`ug=lPSw9?gmf(oa6beo9CwD=ryl#AE* z8bk4l50=$>k+ikv2jk3ACePrYI0gA_FsnBw9A`!I2)#PuH1A0YJ>Ffq$$=FV9NYv^ znr;NZy9c`m2QKY`mZ|_C?Gw*_T&HRtDKb$H zYIoW5cvNmPn))w#U2@ijYu%k%I8^H|FKP<^Bbfxy_8M?{_4)fs9^H{y=1VH!0Rk4y zV)tG18D-f&t();YT|?+}8GM(c_3vPgzt`N{9C2)ULUfi^utpAF&U_x9P2O1slSm2>qu7d9; zI8fn(xA>GE?SJh2Seoa!F(LRhBZK*XRK%^&{#&yO)X<%QGZv5)c9yo7yw&0Zx&mY>BxWLzLt`b;u6wd-ZhG{T@~k% zjh}(z`RnAN_+^t4Ee~MI=H_O`gDOZf0|xC+>F(c0{Nwg>^8E)__W^e1(8_8C4yY%J zxZgQGKE8pC%{AIaaOh}I=RwS4-o^Q;R8CGV;=>1D$PKCvXPf>U9%q@o;TF>skF%`43yUS(vlgNm>ATlcI?XZE5o>o(xdX7e%hwraeU_oRWS#oJ!1gFuFD=3|p@OkQVTxnrn0NcZ=eh3^@&f?F;g1 zY-+MTld}$DOkq(EQHffX3omJ2`Pp?$ovR@ZCHDs$YBmoAVAH0&4)u)cf$%XtJK7$4 zmyr#)o~fJuNu=7GVL0(wG6LR)SyGM1qfXyVjg_B&=r2bp@G}md766u$ z=q*cJHu3UdmQ&v6dTfHm(xM#;yg+PC(2zD~3XA1f z>9?(s5SFm+*Oz*B-)KQ6U|;f;N-J(?_%AanialrmbgdPc@NUHzvl)MSS-#dpf7VX7 z)Afo?p+y%4R3sY5I>{3z9UB@;;X zHN%Uu<0AlA#HY{UJSGYe11d|v(XxyDGJQbC zc<0Zbg|3_W(WynrA3qY!e9Xvmty$gom^mrsk(UADPtT416Ly_BG-3WUwZLt`g^2(W zYWIhpHPYpgu<00{?5!xO%C9I2yR6;5$p7r=mj{6H#;setqu)W22sTcu;Y!hL0yU|x zuP?~!U~P2nPIR&)6ds_uiB5rbCHeK4uVlrkq@;v+{C~;%9S3E8Ek-%1F*99Wo`96kvx4<3VLS_HhFQ9aO@ ze~Q{DRUc4y2HJ{5(P9JS+s zgZl3ZJ>BN!<~R?9LAmHK? z#9Ujr4B#X6fS=rA7e{Hv825oeiZYM}6hRzb0S=bOZUlEey~jSsTLd9%d;IHIx*;wW zCh#O*M>3&o@OvhenQD{JM?((C)V*|e!52OHVqev$XWj@pAE)bv?hF_% z+87E=#EsZBG>Gj=7Mo^brq}4`>LSvAE@a#sFn$3PwgvC=emLcQg09842v69$n4JFN zwV29tS&U7_q#N#o;KF+8i-Aclny3dG3d))3`2RUI9xp?Voj z=c6qnXw&2cI4uG1XDB8z=YGwk@6+A}Kg{^|ET+(Id`gi3pfaENOB;&UcO>*J0hKy= zLiOhpkA+Qk>8GY2W*N%PR)PcxF9P-QWE0a6v(((MQ*$aY``I zbZJw$EcLk)_hq#wcwxmrLq+Hv=(g72EGB`jNCEyInkxyEGQu z%ekSW-rJluDC&V`SR~bI1b`*LgXO`TyGb5@nTVO3qf+?jJojfbWtR|3Sg1kT`^drmqy#=H&WBEh7DRQ6l zRRi@vI*{H$3~DJh>(n(jH-xn8HXF!5blP4V0&9c4`lSX_JEjPP_?hSU2y_cUKt)v` zu4XKDdB!6vC#O(u&5INPaCJ|>{!52w>giAiRC5I6`uigIp75eGYEi;yI_4j#kqI<0 zKU+pIXoEA1=Yb4K_D8?WS5{U8Jod7Tll#(Sa#U_x%(q7%Y!kKt=5eDNgx=n#HDbd^ z;76ecXo}-9@iVyUb2M{399czr3yW2!^og4V0)cL-(I*i{nTaQ}w+nEsf<9X=2*_rg zB%XeY+i|@PX}RB)-?kD;FRA~YB4_C2Myo$Zp_33{K;ykUQceO5gJt9C!NEZ*bm2Do zrxzLksH#`xBp?9LD{!`IaOoJ7=B+L+A%Ui2;`pjXpoSj?ezx78?LjMpNJvqU46A^~a;Aj`_*9~y znu=yLLg6b|9n5(T-QWWtmdty~ena@8$q|+VNOO23Q13)y%<{7PjuT6D*g%XIJ=>B% z)B4bsR_P_#h57m-&;%qTEWVs4vd{-E_9Sm=5Z_~q09ML}5rn zXJ@aBUUvMwcMEIAjKlO%0U(MV2j|;izsp}do2jkd}UDU)7NWeXzq~7b*JiI{1MJB^V$lHKer^nn~c$T3+t_ z{rdH*;qKxum!JR<(G+M_bp+lV{mm(uIH}Zm3H##zFc(^Z@eFID=;&y)-vvYvtHEru z;$(3ARJ*JPRaOeX>VQ<8bMnKS7wG_!<=*?-iIyj?3(4G-6g_zeb)?c0%$W7U8 zGSen1E)_k)^#VuCs6{f zYr1m#EWuoW#m&PL0Zb?8cBx;#UZta>JA&KS4qijCIW(H8bq_+#Y8121LH7*jl@Yv{ zZ^0&@TjPQYkuRaG{mH&s80yr(%V>=&2k=+RA3ibvY3(2X$fVl!H$EcbHH6u?Aa&2;(alVX z_Jqy{&{nTHbdXnWzfK01#8C=0>W;CAiGN!aYxJj2fzS~HNsa+bHOaxSB`e!Sen7Bl)Rcb**UAj#n`{%sj*bpABTg)56$A|} zFw;V&7H5!HwhzYbgkSNlb%~xV(*O^AAFLTg2EhArL8#Q8ZqzVKxzs=c_yY;wJUVON zZ|q9gVqg4h7t@DXRL%IN=?1RN0pp1yWK^_zDgZbmbgFGi2G_~aaqA~b!EZNIYoq`^ zg^=G;k|!RO_fd+Ro{h4$b|5Ypzac2S@{3oX5OhS+HIA(`gwhyW4T@E&f_SRkb_?WX z#@f74t8NoQ53o83xo+f+$P^5F{{A!~3`tnUO|%@CP_*ixm*fLHXYJ8!Fkf~4&`>AF z;4!46?VV1JIq0&Bs}p>_Cj6}aYEA>|?c*{@O;C-YR2qYdtf6=Od|h4~8m6IK?Y9u*f69jSn`WBc zCuUrU{hyrzUA4PD^L5Vg$BZ=sjSFl6qE5eHLlaQt#XyM}H9&=!GJJ`hYaywvRXmX+l{^I{j&9U$Q- z{qhI}=Mk09nR40^ux1dbnBZDO7qG3F_f)gXeQ9{84IoZifmZR@m1_+oWKawLk(dDN zG|+u&wO02k9ZpQ37-mm0AOZ?xuG#9^d{twPv1vIa;rn zwg;>XgAZkFDm{eEc9)}Wum6Ro1~79GF){Cc|5gKvC=ED=!8j0CzqzG-hAa-!w3_w_ zHU9L1Vm=EC%S~-6c% z@7_%VKNT1+7#SHW-4i**atDhbpT!GLc!fZ{=%mi%$(*bY<1O=(A!ARy8r%wrF zz^rOo1WS&Dv{KmN0-XVr+c`)qnq161i$&Jx-&25>XQu7|#5^-@O;WVkRonDvYbJ>J zPN*~u1Xr4|;Sm_c4v9_U2vgTxhjNde1?bZyl7)BcPH90=2iyX6W8~n*_*^Psn593PktKD|AG?;_!iM* zuLDx+ec{{aX)x^oIB5&wJxslxy6NCoz`%QVpJPwUG9@KV};4t^~{ zjK1j;5vV^P3o;%Y?++XNs;)^~3r3rDvlo_@-rqHNMF9R8`ctTEb1)YbE@p0j^lvvH zHPS041OPkrX^p0n`vPcoC<~G;?d?S9nOAp0-1OyWarhWqxpq zAB|66WQ;6t6m2b7v zgg1)@>jUfHpdhp+ zu3tH8j9#IM5XDS%j`%XDb3xz(AOl3c%O9YquH7abCHyyxpwnVVOGhnO7Qs^82wp?? zf~sI+@M1gikdl&u)$MhCeZBViAvlqsa^Hon(j_cpEf76}UjSjgrl+R>OAvGpuFY)- z2$&EBvy}8fGX(GaJMb^rai>rTIo|+2x(Re)!MY9UQUo(bTz<2Xq$E27A0ILJHj%$V z<@j#iyjcXsO&jQo0024KJDXmQ)RHlzNQ6ixnDyryX;IZ*Bg_Ol`(C5X@L+xy z%?H1Gi^o5|J8NefUok5WY%W0+Cn~a-7wfH&7(#>OKE#khai8Tx!6xKBq(Qf#6eU@j$;L(Tn?gb5E${b#IUMC0~ znDl>o{E`w9bg>LWCH}ej<-E`uk0X4HhbU$(aMTq6sBil1nNx+c^;^YEVZ@iWlJ-y41WSJhmit;Csd!Hr5VI=C{Cy~5V6~7~@*ivMqrM+1?9pC*`Mqf|IO+!O7 zJavM((oG3XnU`ARSB}A8c;5il2c0`vfMLh^OQxfHG5*UOc!700Q}*AN5dsYe2??)H z97`y?d=x4@=Z08t!T)!U@&i=A(;%Ol`eD=B+FIw#%*<3I?S7e^E_%AJ-J!{zRv&)4 zeuDyGHJtzGF2cGN)=KdG3xMgn3Va$h@AS<;FAU{HDhT;X^Wz7@Ji4L_`YeSm0U6fE z|21@k1po!D67k0YL0lddg1$h7y>ll`wu79r=$$t-tGTK$ECVg-VRk5T+IuRM`0V^|Yw|-p_6DwG~P8&mZIBj*0{+e#tH)z~YfO27=cW1paH9 zmvFx)$Y$PjOiU{;oD2*djE7d7@iDb<8;1Lb@4x~+1y)swo{rATtRpxV`MeGObQGTv z`(pjyFWyAs8#=?6If~Oc)Fu{ef5PFZ0KTds*6jGMwLWaPr0XbHWQCqZbz$5b>fHoJ zwkQ%T_j&yHZgKlk^0{-s4DdDBQT-xfV)aFk_}I!16l{vC6fy_=F^_x@SfjJ&um~cr zX;IJkkiYz(y%{|E>lnYGF}&iOhS7!5+ZwYe2Z5z%s@?s8_PL9(@oYu8hf>Z^uL4S5 z{;V1vxsJGnSvVcDsQ{N@;bFKHL&>JF`P7ARn#2$b$z`a?l2;VZkjU3iSQNITU7Hxb zPgMrNE5gL|JhqN9RrYlpK$Kx{+#nfI{Rr)tImAT4Pzi*D8a<`}j$tq@svazF7q#ZU zkTuhRvmd?+K~Z{F%ql|~+Ir*ve&OrN{XadIR|T2*;f*m!8;B9Z7iT?EaL_`eO-OuA kL`6kU0rtlixIDe28m1ON5S>Mr!uQz_DA08C#SP#5AFgS}1poj5 diff --git a/allsky.css b/allsky.css index f978ae2..4478b58 100755 --- a/allsky.css +++ b/allsky.css @@ -2,9 +2,19 @@ body { color:white; font-family: Arial, 'Helvetica Neue', Helvetica, sans-serif; background-color: black; - max-width: 960px; /* Optionally change to change size of image */ + max-width: 960px; margin: auto; } +img.current { + width: 100%; + max-width: 960px; +} + +#starmap_container { + position: absolute; + overflow: hidden; +} + .header { display:block; @@ -27,7 +37,13 @@ body { height: 35px; } +.personalLink { + text-align: center; + font-size: 150%; +} + .info { + font-size: 90%; padding: 8px; position: fixed; top: 150px; @@ -37,11 +53,12 @@ body { background-color: #333; border: 2px solid #888; border-right: none; + z-index: 1; } .info ul { list-style: none; - padding-left: 10px; + padding-left: 2px; margin-bottom: 0; } @@ -49,11 +66,10 @@ body { margin-right: 3px; } -#sidebar { +#leftSidebar { position: fixed; left: 0; top: 150px; - padding: 0; padding: 5px; border-top-right-radius: 5px; border-bottom-right-radius: 5px; @@ -63,39 +79,27 @@ body { z-index: 2; } -#sidebar li { +#leftSidebar li { list-style: none; padding: 2px 0 } -#sidebar li i { +#leftSidebar li i { cursor: pointer; color: #888; margin: 2px 0; } -#sidebar li i:hover, -#sidebar li i.active { +#leftSidebar li i:hover, +#leftSidebar li i.active { color: orange; } -.notification { - margin-left: 10px; -} - #imageContainer { - text-align: center; + margin: auto; } - -img.current { - width: 100%; - max-width: 960px; /* Optionally change to change size of image */ -} - -#starmap_container { - position: absolute; - overflow: hidden; - height: 720px; /* Optionally change or delete to change size of image */ +.imageContainer { + border: 1px solid #5a5a5a; } .starmap_credit { @@ -106,16 +110,25 @@ img.current { position: fixed; bottom: 10px; right: 10px; + opacity: 0.5; +} + +.diy:hover { + opacity: 1; } .diy a { color: white; } +.diy i { + margin-right: 5px; +} + .noImages { text-align: center; font-size: 200%; - color: yellow; + color: #ffc107; border: 2px solid gray; margin: 4px; } @@ -199,24 +212,29 @@ img.current { margin: 0 3px; } -.forecast .Low { +.forecast .Very_Quite, +.forecast .Quiet { color: green; } +.forecast .Unsettled, .forecast .Active { - color: yellow; + color: #ffc107; } -.forecast .High { +.forecast .Minor_Storm, +.forecast .Moderate_Storm { color: darkorange; } -.forecast .Extreme { - color: red; +.forecast .Strong_Storm, +.forecast .Severe_Storm, +.forecast .Extreme_Storm { + color: #dc3545; } .forecast .WARNING { /* for Aurora activity */ - color: yellow; + color: #ffc107; font-weight: bold; font-size: 125%; } @@ -227,6 +245,40 @@ img.current { margin-top: 30px; } +.virtualsky_help { + color: black; +} + .thumbnailError { - color: red; + color: #dc3545; } + +/* Messages on the home page */ +.msg { + background-color: #222; + text-align: center; + font-size: 145%; + font-weight: bold; + margin: 10px 0 20px 0; + padding: 20px 0 20px 0; + border-radius: 10px; +} +.error-msg { + color: #dc3545; + border: 3px dashed #dc3545; +} +.warning-msg { + color: #ffc107; + border: 3px dashed #ffc107; +} +.notice-msg { + color: white; + border: 3px solid white; +} + +@media screen and (max-width: 480px) { + .msg { + font-size: 100%; + } +} + diff --git a/config.js b/config.js deleted file mode 100644 index f711ad2..0000000 --- a/config.js +++ /dev/null @@ -1,21 +0,0 @@ -var config = { - comment: "See https://github.com/thomasjacquin/allsky/wiki/allsky-website-Settings for a description of these settings", - title: "XX_need_to_update_XX", - imageName: "/current/tmp/image.jpg", - location: "XX_need_to_update_XX", - latitude_longitude_comment: "latitude and longitude must be decimal numbers with OUT the trailing N, S, E, and W.", - latitude: 0, - longitude: 0, - az: 0, - camera: "XX_need_to_update_XX", - lens: "XX_need_to_update_XX", - computer: "XX_need_to_update_XX", - owner: "XX_need_to_update_XX", - overlaySize: 875, - overlayOffsetLeft: 0, - overlayOffsetTop: 0, - showOverlayAtStartup: false, - auroraForecast: false, - auroraMap: "XX_need_to_update_XX", - intervalSeconds: 5, -} diff --git a/controller.js b/controller.js index 4661d99..b619c50 100755 --- a/controller.js +++ b/controller.js @@ -1,43 +1,175 @@ -var usingNewVirtualSky = typeof S != "undefined" && typeof S.virtualsky == "function"; -console.log("usingNewVirtualSky=" + usingNewVirtualSky); - var app = angular.module('allsky', ['ngLodash']); +var overlayBuilt = false; // has the overlay been built yet? + +var virtualSkyData = null; +var sunData = "data.json"; // contains sunrise/sunset times and related data +var configData = "configuration.json" // contains web configuration data + +// This returns the height INCLUDING the border: $("#imageContainer").css('height') +// This returns the height NOT including the border: $("#imageContainer").height() + +// These two are used by virtualsky.js to set the overlay width and height, +// if there was a difference. +var overlayWidth = 0, overlayHeight = 0; +var overlayWidthMax = 0, overlayHeightMax = 0; +var starmapWidth = 0, starmapHeight = 0; +var wasDiff = true; +var last_s_iW = 0, last_s_iH = 0; +var icWidth = 0; +var icHeight = 0; +var icImageAspectRatio = 0; +var overlayAspectRatio = 0; +var myLatitude = 0, myLongitude = 0; + $(window).resize(function () { - buildOverlay(); + if (overlayBuilt) { // only rebuild if already built once + var newW = $("#imageContainer").width(); + var newH = $("#imageContainer").height() +// console.log("#imageContainer newW=" + newW + ", newH=" + newH); + + $("#starmap_container").css("width", newW + "px").css("height", newH + "px"); + + var diffW = newW - icWidth; + // Scale the height based on the aspect ratio of the image. +// console.log("newW=" + newW + ", icWidth=" + icWidth); +//x var diffH = (newH - icHeight) * overlayAspectRatio; + var diffH = (newH - icHeight); + icWidth = newW; + icHeight = newH; + + if (diffW == 0 && diffH == 0) { + wasDiff = false; +// console.log(">>> No change in image size."); + return; + } + + wasDiff = true; + + // TODO: probably also need to adjust #stamap's margin-left and margin-right. + + // This holds the starmap button, so needs to resize + starmapWidth += diffW; + starmapHeight += diffH; + $("#starmap").css("width", starmapWidth + "px").css("height", starmapHeight + "px"); + + // Shrinking the window makes the overlay shrink too fast for some reason. + // Got the fudge factor by trial and error. + if (diffW < 0) { + var fudge = 0.95; + diffW *= fudge; +// console.log("diffH=" + diffH + ", overlayAspectRatio=" + overlayAspectRatio); + diffH = (diffH / overlayAspectRatio) * fudge; + } + +// console.log("== diffW= " + diffW + ", diffH= " + diffH); + overlayWidth += diffW; + if (overlayWidth > overlayWidthMax) overlayWidth = overlayWidthMax; + overlayHeight += diffH; + if (overlayHeight > overlayHeightMax) overlayHeight = overlayHeightMax; +// console.log("== setting overlayWidth= " + overlayWidth + ", overlayHeight= " + overlayHeight); + $("#starmap_inner") + .css("width", overlayWidth + "px") + .css("height", overlayHeight + "px"); + } }); function buildOverlay(){ - var planetarium; - $.ajax({ - url: "virtualsky.json" + '?_ts=' + new Date().getTime(), - cache: false - }).done( - function (data) { - // This is to scale the overlay when the window is resized - // Newer versions support both width and height. - var width; - if (config.overlayWidth) { - width = config.overlayWidth; - } else { - width = config.overlaySize; + if (overlayBuilt) { + S.virtualsky(virtualSkyData); + } else { + $.ajax({ + // No need for ?_ts= since $.ajax adds one + url: configData, + cache: false + }).done( + function (data) { + var c = data.config; + // "config" was defined in index.php to include ALL the variables we need, + // including ones not in the "config" section of the configuration file. + // However, "array" types like "colour" aren't handled in index.php. + + // TODO: I tried not doing the ajax call, but the overlay wouldn't show. + // It's a shame - there's no reason to re-read the file. + + virtualSkyData = c; + virtualSkyData.latitude = myLatitude; + virtualSkyData.longitude = myLongitude; + + // These variables have different names in virtualsky.js and our config file. + virtualSkyData.width = c.overlayWidth; + virtualSkyData.height = c.overlayHeight; + + S.virtualsky(virtualSkyData); // Creates overlay + overlayBuilt = true; + + // Offset of overlay + $("#starmap") + .css("margin-top", c.overlayOffsetTop + "px") + .css("margin-left", c.overlayOffsetLeft + "px"); + + // max-width of #imageContainer set in index.php based on width user specified (imageWidth) + icWidth = $("#imageContainer").width(); + icHeight = $("#imageContainer").height(); + icImageAspectRatio = icWidth / icHeight; + + $("#starmap_container").css("width", icWidth + "px").css("height", icHeight + "px"); + + overlayWidth = c.overlayWidth; + overlayHeight = c.overlayHeight; + overlayAspectRatio = overlayWidth / overlayHeight; +// console.log("overlay aspect ratio=" + overlayAspectRatio); + + overlayHeightMax = overlayHeight; // never go larger than what user specified + overlayWidthMax = overlayWidth; + + starmapWidth = $("#starmap").width(); + starmapHeight = $("#starmap").height(); + + // TODO: this assumes the border is 1px on each side. + var imageWidth = c.imageWidth - (config.imageBorder ? 2 : 0); + if (icWidth < imageWidth) { + // The actual image on the screen is smaller than the imageWidth requested by the user. + // Determine the percent smaller, then make the overlay that percent smaller. +console.log("icWidth=" + icWidth + ", imageWidth=" + imageWidth); + var percentSmaller = icWidth / c.imageWidth; + + // #starmap holds the starmap button, so needs to resize it as well. + var w = starmapWidth * percentSmaller; + var h = w / overlayAspectRatio; + $("#starmap") + .css("width", Math.round(w, 0) + "px") + .css("height", Math.round(h, 0) + "px"); + starmapWidth = w; + starmapHeight = h; + + // TODO: probably also need to adjust #stamap's margin-left and margin-right if + + // percentSmaller makes the overlay TOO small, so change it. + percentSmaller *= 1.04; +console.log("== Decreasing overlay by " + percentSmaller*100 + " percent" + " (overlayWidth was " + overlayWidth + ")"); + overlayWidth = overlayWidth * percentSmaller; + overlayHeight = overlayWidth / overlayAspectRatio; + $("#starmap_inner") + .css("width", Math.round(overlayWidth, 0) + "px") + .css("height", Math.round(overlayHeight, 0) + "px"); + + } + + // id="live_container" is where the image goes. + var image_w = c.imageWidth; + var image_h = Math.round((image_w / icImageAspectRatio), 0); +// console.log("icHeight=" + icHeight + ", icWidth=" + icWidth); +// console.log("overlayHeight=" + overlayHeight + ", overlayWidth=" + overlayWidth); +// console.log("image_h=" + image_h + ", image_w=" + image_w); + + // Keep track of the sizes. virtualsky.js seems to change them, + // so we need to change them based on our last known sizes. + last_s_iW = $("#starmap_inner").width(); + last_s_iH = $("#starmap_inner").height(); } - data.width = window.innerWidth < width ? window.innerWidth : width; - if (config.overlayHeight) - data.height = config.overlayHeight; - else - data.height = data.width; // default is square - data.latitude = config.latitude; - data.longitude = config.longitude; - data.az = config.az; - if (usingNewVirtualSky) - planetarium = S.virtualsky(data); - else - planetarium = typeof $.virtualsky == "undefined" ? undefined : $.virtualsky(data); - $("#starmap").css("margin-top", config.overlayOffsetTop + "px"); - $("#starmap").css("margin-left", config.overlayOffsetLeft + "px"); - } - ); + ); + } }; function compile($compile) { @@ -63,40 +195,109 @@ function compile($compile) { }; } -var configNotSet = false; // Has the config.js file been updated by the user? +var configNotSet = false; // Has the configuration file been updated by the user? +var needToUpdate = "XX_NEED_TO_UPDATE_XX"; // must match what's in configData + +function convertLatitude(sc, lat) { // sc == scope + var convertToString = false; + var len, direction; + + if (typeof lat === "string") { + sc.s_latitude = lat; // string version + + len = lat.length; + direction = lat.substr(len-1, 1).toUpperCase(); + if (direction == "N") + sc.latitude = lat.substr(0, len-2) * 1; + else if (direction == "S") + sc.latitude = lat.substr(0, len-2) * -1; + else { + // a number with quotes around it which is treated as a string + sc.latitude = lat * 1; + convertToString = true; + } + } else { + sc.latitude = lat; + convertToString = true; + } + + if (convertToString) { + if (lat >= 0) + sc.s_latitude = lat + "N"; + else + sc.s_latitude = -lat + "S"; + } + + return sc.latitude; +} + +function convertLongitude(sc, lon) { + var convertToString = false; + var len, direction; + + if (typeof lon === "string") { + sc.s_longitude = lon; + + len = config.longitude.length; + direction = lon.substr(len-1, 1).toUpperCase(); + if (direction == "E") + sc.longitude = lon.substr(0, len-2) * 1; + else if (direction == "W") + sc.longitude = lon.substr(0, len-2) * -1; + else { + // a number with quotes around it which is treated as a string + sc.longitude = lon * 1; + convertToString = true; + } + } else { + sc.longitude = lon; + convertToString = true; + } + + if (convertToString) { + if (config.longitude >= 0) + sc.s_longitude = lon + "E"; + else + sc.s_longitude = -lon + "W"; + } + + return sc.longitude; +} function AppCtrl($scope, $timeout, $http, _) { - var overlayBuilt = false; // has the overlay been built yet? - if (! usingNewVirtualSky) { - overlayBuilt = true; - buildOverlay(); - } + // Allow latitude and longitude to have or not have N, S, E, W, + // but in the popout, always use the letters for consistency. + // virtualsky.js expects decimal numbers so we need both. + // Need to convert them before building the overlay. + $scope.latitude = convertLatitude($scope, config.latitude); + myLatitude = $scope.latitude; + $scope.longitude = convertLongitude($scope, config.longitude); + myLongitude = $scope.longitude; - $scope.imageURL = "loading.jpg"; + $scope.imageURL = config.loadingImage; $scope.showInfo = false; $scope.showOverlay = config.showOverlayAtStartup; - if ($scope.showOverlay && usingNewVirtualSky) { - overlayBuilt = true; - console.log("@@ Building overlay..."); + if ($scope.showOverlay) { + console.log("@@ Building overlay at startup for showOverlay..."); buildOverlay(); } $scope.notification = ""; - $scope.title = config.title; - if ($scope.title == "XX_need_to_update_XX") { - // Could (or should?) check other variables for not being set. - // Or assume if the title is set, everything else is too. + if (config.title == needToUpdate) { + // Assume if the title isn't set, nothing else is either. configNotSet = true; + $scope.notification = formatMessage("Please update the '" + configData + "' file.
Replace the '" + needToUpdate + "' entries and check all other entries.
Refresh your browser when done.", msgType="error"); + return; } $scope.location = config.location; - $scope.latitude = config.latitude; - $scope.longitude = config.longitude; $scope.camera = config.camera; $scope.lens = config.lens; $scope.computer = config.computer; $scope.owner = config.owner; $scope.auroraForecast = config.auroraForecast; $scope.imageName = config.imageName; + $scope.AllskyVersion = config.AllskyVersion; + $scope.AllskyWebsiteVersion = config.AllskyWebsiteVersion; function getHiddenProp() { var prefixes = ['webkit', 'moz', 'ms', 'o']; @@ -113,34 +314,19 @@ function AppCtrl($scope, $timeout, $http, _) { // otherwise it's not supported return null; } + var hiddenProperty = getHiddenProp(); function isHidden() { - var prop = getHiddenProp(); - if (!prop) return false; -//return false; // xxxxxxxxx for testing, uncomment to make never hidden - - return document[prop]; + if (! hiddenProperty) return false; + return document[hiddenProperty]; } - // If the data.json file wasn't found, or for some reason "sunset" isn't in it, - // the routine that reads data.json will set "dataMissingMessage" so display it. + // If the "sunData" file wasn't found, or for some reason "sunset" isn't in it, + // the routine that reads "sunData" will set "dataMissingMessage" so display it. var dataMissingMessage = ""; function formatMessage(msg, msgType) { - if (msgType === "error") { - textColor = "red"; - borderColor = "red"; - borderStyle = "dashed"; - } else if (msgType === "warning") { - textColor = "yellow"; - borderColor = "yellow"; - borderStyle = "dashed"; - } else { - textColor = "white"; - borderColor = "white"; - borderStyle = "solid"; - } - return("
" + msg + "
"); + return("
" + msg + "
"); } // How old should the data file be, or the sunset time be, in order to warn the user? @@ -150,9 +336,7 @@ function AppCtrl($scope, $timeout, $http, _) { // The defaultInterval should ideally be based on the time between day and night images - why // check every 5 seconds if new images only appear once a minute? - var defaultInterval = (5 * 1000); // Time to wait between normal images. - if (config.intervalSeconds) defaultInterval = config.intervalSeconds * 1000; - + var defaultInterval = (config.intervalSeconds * 1000); // Time to wait between normal images. var intervalTimer = defaultInterval; // Amount of time we're currently waiting // If we're not taking pictures during the day, we don't need to check for updated images as often. @@ -161,7 +345,7 @@ function AppCtrl($scope, $timeout, $http, _) { // there's no need to check until nightfall. // However, in case the image DOES change, check every minute. Seems like a good compromise. // Also, in both cases, if we wait too long, when the user returns to the web page after - // it being hidden, they'll have to wait a long time for the page to update. + // it's been hidden, they'll have to wait a long time for the page to update. var auroraIntervalTimer = (60 * 1000); // seconds var auroraIntervalTimerShortened = (15 * 1000); // seconds var nonAuroraIntervalTimer = (60 * 1000); // seconds @@ -173,12 +357,16 @@ function AppCtrl($scope, $timeout, $http, _) { var lastType = ""; var loggedTimes = false; var numImagesRead = 0; + var numCalls = 0; $scope.getImage = function () { var url= ""; var imageClass= ""; - if (! isHidden()) { + // Go through the loop occassionally even when hidden so we re-read the sunData file + // if needed. + if (! isHidden() || ++numCalls % 5 == 0) { if (configNotSet) { - $scope.notification = formatMessage("Please update the 'config.js' file.
Replace the 'XX_need_to_update_XX' entries and check all other entries.
Refresh your browser when done.", msgType="error"); +// xxxxxxxxx test deleting the "if" portion + $scope.notification = formatMessage("Please update the '" + configData + "' file.
Replace the '" + needToUpdate + "' entries and check all other entries.
Refresh your browser when done.", msgType="error"); } else if (dataMissingMessage !== "") { $scope.notification = formatMessage(dataMissingMessage, msgType = dataFileIsOld ? "warning": "error"); } else { @@ -208,8 +396,8 @@ function AppCtrl($scope, $timeout, $http, _) { if (! dataFileIsOld) { //console.log("DEBUG: sunset daysOld=" + daysOld); if (daysOld > oldDataLimit) { - var oldMsg = "WARNING: sunset is " + daysOld + " days old."; - $scope.notification = formatMessage(oldMsg + "
Check Allsky log file if 'postData.sh' has been running successfully at the end of nighttime.", msgType="warning"); + var oldMsg = "WARNING: sunset data is " + daysOld + " days old."; + $scope.notification = formatMessage(oldMsg + "
See the 'Troubleshooting > Allsky Website' documentation page for how to resolve this.", msgType="warning"); } } @@ -229,7 +417,7 @@ function AppCtrl($scope, $timeout, $http, _) { } // The sunrise and sunset times change every day, and the user may have changed - // streamDaytime, so re-read the data.json file when something changes. + // streamDaytime, so re-read the "sunData" file when something changes. if (is_nighttime) { // Only add to the console log once per message type if (lastType !== "nighttime") { @@ -314,13 +502,15 @@ function AppCtrl($scope, $timeout, $http, _) { console.log(" m_now = " + m_now.format("YYYY-MM-DD HH:mm:ss")); if (oldMsg !== "") console.log(" > " + oldMsg); - console.log(" Times:"); console.log(" m_now="+m_nowTime + ", m_sunrise="+m_sunriseTime + ", m_sunset="+m_sunsetTime); console.log(" beforeSunriseTime = " + beforeSunriseTime); console.log(" afterSunsetTime = " + afterSunsetTime); } - var img = $("").attr('src', url + '?_ts=' + new Date().getTime()).addClass(imageClass) +// TODO: Is there a way to specify not to cache this without using "?_ts" ? + var img = $("") + .attr('src', url + '?_ts=' + new Date().getTime()) + .addClass(imageClass) .on('load', function() { if (!this.complete || typeof this.naturalWidth === "undefined" || this.naturalWidth === 0) { alert('broken image!'); @@ -334,22 +524,17 @@ function AppCtrl($scope, $timeout, $http, _) { // Don't re-read after the 1st image of this period since we read it right before the image. if (rereadSunriseSunset && numImagesRead > 1) { - // console.log("XXX Re-reading data.json"); $scope.getSunRiseSet(); - } else if (rereadSunriseSunset) { - console.log("XXX Not rereading data.json, numImagesRead=" + numImagesRead); - } else { - // console.log("XXX rereadSunriseSunset=" + rereadSunriseSunset); } - } + } // if (! isHidden())) }; - // Set a default sunrise if we can't get it from data.json. + // Set a default sunrise if we can't get it from "sunData". var usingDefaultSunrise = false; function getDefaultSunrise(today) { return(moment(new Date(today.getFullYear(), today.getMonth(), today.getDate(), 6, 0, 0))); } - // Set a default sunset if we can't get it from data.json. + // Set a default sunset if we can't get it from "sunData". var usingDefaultSunset = false; function getDefaultSunset(today) { return(moment(new Date(today.getFullYear(), today.getMonth(), today.getDate(), 18, 0, 0))); @@ -368,8 +553,10 @@ function AppCtrl($scope, $timeout, $http, _) { $scope.getSunRiseSet = function () { dataFileIsOld = false; now = new Date(); - console.log("Read data.json at " + moment(now).format("MM-DD h:mm:ss a") + ":"); - var url = "data.json" + '?_ts=' + now.getTime(); + var url = sunData; +// TODO: is ?_ts needed if we are not cache'ing ? + url += '?_ts=' + now.getTime(); + console.log("Read " + sunData + " on " + moment(now).format("MM-DD h:mm:ss a") + ":"); $http.get(url, { cache: false }).then( @@ -378,26 +565,29 @@ function AppCtrl($scope, $timeout, $http, _) { $scope.sunrise = moment(data.data.sunrise); usingDefaultSunrise = false; } else if (! usingDefaultSunrise) { +// TODO: Is this needed with the new Allsky Website, given that it only works with the new Allsky? // Older versions of allsky/scripts/postData.sh didn't include sunrise. $scope.sunrise = getDefaultSunrise(now); usingDefaultSunrise = true; - console.log(" ********** WARNING: 'sunrise' not defined in data.json"); + console.log(" ********** WARNING: 'sunrise' not defined in " + sunData); } if (data.data.sunset) { $scope.sunset = moment(data.data.sunset); usingDefaultSunset = false; dataMissingMessage = ""; } else if (! usingDefaultSunset) { +// TODO: Is this needed with the new Allsky Website, given that it only works with the new Allsky? $scope.sunset = getDefaultSunset(now); usingDefaultSunset = true; - dataMissingMessage = "ERROR: 'sunset' not defined in 'data.json', using " + $scope.sunset.format("h:mm a") + ".
Run 'allsky/scripts/postData.sh'.
Refresh your browser when done."; - console.log(" ********** WARNING: 'sunset' not defined in data.json"); + dataMissingMessage = "ERROR: 'sunset' not defined in '" + sunData + "', using " + $scope.sunset.format("h:mm a") + ".
Run 'allsky/scripts/postData.sh'.
Refresh your browser when done."; + console.log(" ********** ERROR: 'sunset' not defined in " + sunData); } if (data.data.streamDaytime) { $scope.streamDaytime = data.data.streamDaytime === "true"; } else { +// TODO: Is this needed with the new Allsky Website, given that it only works with the new Allsky? $scope.streamDaytime = true; - console.log(" ********** WARNING: 'streamDaytime' not defined in data.json"); + console.log(" ********** WARNING: 'streamDaytime' not defined in " + sunData); } // Get when the file was last modified so we can warn if it's old @@ -419,16 +609,16 @@ function AppCtrl($scope, $timeout, $http, _) { if (typeof x === "object") { // success - "x" is a Date object lastModifiedSunriseSunsetFile = moment(x); var duration = moment.duration(moment(now).diff(lastModifiedSunriseSunsetFile)); -// console.log("DEBUG: data.json is " + duration.days() + " days old"); +// console.log("DEBUG: " + sunData + " is " + duration.days() + " days old"); if (duration.days() > oldDataLimit) { dataFileIsOld = true; - var msg = "WARNING: data.json is " + duration.days() + " days old."; + var msg = "WARNING: " + sunData + " is " + duration.days() + " days old."; console.log(msg); dataMissingMessage = msg + "
Check Allsky log file if 'postData.sh' has been running successfully at the end of nighttime."; } } else { - console.log("fetchHeader(" + url + ") returned " + x); + console.log("fetchHeader(" + sunData + ") returned " + x); } writeSunriseSunsetToConsole(); @@ -442,8 +632,8 @@ function AppCtrl($scope, $timeout, $http, _) { usingDefaultSunset = true; $scope.streamDaytime = true; - dataMissingMessage = "ERROR: 'data.json' file not found, using " + $scope.sunset.format("h:mm a") + " for sunset.
Set 'POST_END_OF_NIGHT_DATA=true' in config.sh then run 'allsky/scripts/postData.sh'.
Refresh your browser when done."; - console.log(" *** Unable to read file"); + dataMissingMessage = "ERROR: '" + sunData + " file not found, using " + $scope.sunset.format("h:mm a") + " for sunset.
Run 'allsky/scripts/postData.sh'.
Refresh your browser when done."; + console.log(" *** Unable to read '" + sunData + "' file"); writeSunriseSunsetToConsole(); $scope.getImage() @@ -467,29 +657,28 @@ function AppCtrl($scope, $timeout, $http, _) { $scope.toggleOverlay = function () { $scope.showOverlay = !$scope.showOverlay; - if (usingNewVirtualSky && ! overlayBuilt && $scope.showOverlay) { - console.log("@@@@ Building overlay..."); - overlayBuilt = true; - // The new 0.7.7 version of VirtualSky doesn't show the overlay unless buildOverlay() is called here. - buildOverlay(); - } + if (! overlayBuilt && $scope.showOverlay) { + console.log("@@@@ Building overlay from toggle..."); + // Version 0.7.7 of VirtualSky doesn't show the overlay unless buildOverlay() is called. + buildOverlay(); + } $('.options').fadeToggle(); $('#starmap_container').fadeToggle(); }; - $scope.getScale = function (index) { + $scope.getScale = function (index) { // based mostly on https://auroraforecast.is/kp-index/ var scale = { - 0: "Low", - 1: "Low", - 2: "Low", - 3: "Active", - 4: "High", - 5: "Extreme", - 6: "Extreme", - 7: "Extreme", - 8: "Extreme", - 9: "Extreme", + 0: "Extremely_Quiet", + 1: "Very_Quiet", + 2: "Quiet", + 3: "Unsettled", + 4: "Active", + 5: "Minor_storm", + 6: "Moderate_storm", + 7: "Strong_storm", + 8: "Severe_storm", + 9: "Extreme_storm", 100: "WARNING" }; return scale[index]; @@ -502,7 +691,7 @@ function AppCtrl($scope, $timeout, $http, _) { var total = _.sumBy(data, function (row) { return parseInt(row[field]); }); - return Math.round(total / 7); + return Math.round(total / data.length); // return average } function getDay(number) { @@ -537,3 +726,4 @@ angular .directive('compile', ['$compile', compile]) .controller("AppCtrl", ['$scope', '$timeout', '$http', 'lodash', AppCtrl]) ; + diff --git a/fonts/mini-timelapse.eot b/fonts/mini-timelapse.eot new file mode 100644 index 0000000000000000000000000000000000000000..9ab213bfb332901263e23cbf2ea852b73fac5667 GIT binary patch literal 1404 zcmb7EO-vI(7=6=SS}3>}LxCtE3o*i}7AQ0d7`Tw2B`U_A1X;>jAZ@p_C4q!PFLDqQ zIe6jD*?9Eep)n?2JR0Lg19~xd@#0CbzMWnB1C5DaGBfXc-}`oE=jYpM06wUIfCsfE zuq$jPdaIVVwT>N*?oXbK0UA~ihlLcIg){{kW?>?MbtGXROQsz$GFjxPwKX~h5JX67 zPiB*}Cu~Lm3PLyUTpnya=Y2}%CEG$gWn_+S<1a+;PhHZt&I zoIdA(o;FhE-u0%R^tpVoow0IxN2J~SA)CL$xl z;l7~gyQK8WVK^+wp+PALw8;eJjPPJ}ZhohqwlhDsT8(4T=$hWsqpwAyu`2vt6n+a@f&^{gO&nu(*cf5b)XT|-J=g5PwjeTVY zB?GS$aU5={RF*kE+R%-DY%^eIdNJzUv+@j1qSI@An}6BE5su%R*BbL z+`yL>aIu&C4Hx@y9*^uBqBfDy7;&(NIN@T2c-+M*@s^7l_~7{xWUiO|tc(2!V}B)X zr7SC5TQy>4Hn(D>^?_iheyOONRhOJK6YEJMTU&$bDyOV;UQd{5Gi&6{C4F&IpN?BI qTw4%RvP|Xq7YP=wv@Bi*@*J1QEn<`Xv@ClwZrKZR*X`H%5Bmebwa!xj literal 0 HcmV?d00001 diff --git a/fonts/mini-timelapse.svg b/fonts/mini-timelapse.svg new file mode 100644 index 0000000..40cec60 --- /dev/null +++ b/fonts/mini-timelapse.svg @@ -0,0 +1,11 @@ + + + +Generated by IcoMoon + + + + + + + diff --git a/fonts/mini-timelapse.ttf b/fonts/mini-timelapse.ttf new file mode 100644 index 0000000000000000000000000000000000000000..dfb5c8ae301c1d8addc676ba8102eebc2ddc6f6f GIT binary patch literal 1240 zcmb7DJxmi}7=FIH;|c|fF%*arau6d-wLqa!z~DlHmKZU1667dnfwXs}EeRwJU1Sgw z9bDL%jiZA@V@zBejhhB_F}S!mDc0w{?<_U2_$J@I&-=W;-_Jn+Xhj7&;x}$x9Bw~j zJ|**#YcZ3z3kNsx84x|R?_}*#f%-J!vxrz63N?}1%xq4n>}E;cHY^&*7B2fob|U0 zUa71?jTgQjx_(nhGuBQg44tgqP4?XP39e0qV}csF8ZC>jn(~Lg0bxltOg`6$)Kai z|K~Vmt!jWfI)@}Kvr&I2B0^@gqpMeRb&d=tuZZN>Xks8H1}^CRQjI1gIWjCmq8&0p zKP5D*%`fZ>Qg#;R*BWs;m0Gv@`mFU-D&2tJi^}hcUOgVKa(^uz%LuZy%Km=+{IBkf zf4bW~@dK@fJj{=W)^i^y9qf+pk0-B$=Oyov7vT%PM<=KvOyyCApXS?jE{qQJVi4OT z{Y(?%>Ydd)kgQ9DZ&uY82$5A-BVG)!PCOQ1gLosrP5jfM0XE5B4{#V~@z8%EMhlq; zJql~Y*#PUrlL0n}?+3UEo#3A!b4~Jd0S+U9z157D_dFM?$iPFM%Y&PCiltT0wT5DG zq~V~55(DU9ogu^!KQZe>a?Z(a_VvUi!?vn=DviENaqm&q+*i{BZ!fmyWy&Zz#%`js39e*j&2y)*y- literal 0 HcmV?d00001 diff --git a/fonts/mini-timelapse.woff b/fonts/mini-timelapse.woff new file mode 100644 index 0000000000000000000000000000000000000000..100de7bea04ad63be04d4828e157275fa6ca4133 GIT binary patch literal 1316 zcmb7DzfV(96#i~s`zi$sF%*ar@*qT*DnAO10tS~RXbBNwCqW+N*+SYrXiJ2Ifkg)y zbZ}v3HvRz)jWKa?G{!}Py5ZvDq*%Xu-wiFHizhkfe&;*qymRi4_h>GWfB+@Xk7l|0 zKS|q2<`%Av0OA5;%Tik}nJ?0LdxKn-{(Y&(ckwM_mn8R=zRZ={mdWirB=?@$A~j|% zyv{oID&Uj-#-;XlJ^q{}2^ekk`=tio81J(A@;12`{Vu6tnw*=Kc}YU)hVc@Ud3&3E z4LOIUG=!;wop;FXvgZ@22e+GkZ@8s0_v=5+Gl&f1o_LM`=Q;3kN<8yc@dKlxiGIBZ zIo=tW296^}rCPzXL1j#xsm`&~s=5$$GbV92t<36%Usbg5qAETpfUo2xvh0QeL(!W8lg7F|8tzOTJeKBx`H@va8rH3un3xw_Rb#B*)cj2 zzbWG5W3hp#7`STmsbwst$k7p%5@}Zj#zo=7`r^|5AZ34PalIa=lF3c0x7XTCCR26z zquBeqXH?GTd$oU-&sFGZ-`>&D>G|I}ocQ{nb@CUQ<#hvJPOMk8Rqsx|QJ#(xo|n2u zUW63d+6gKKrWf%XStk8cE`)aUU=Vz5s?x-Sx@|rzui}iA@7DXiKu}l6%pjIEZxD}b z>?hvRIKaO(qOnQ-j>aKe##8x1{7q!SjCj~boYB}Ip3>M)ysL2l9k4Vu$1*{-gKi-Q z8^wm13Aa$TGETuM+GS_eTG_E?((Wv0iz1"; + echo "ERROR: Missing configuration file '$configuration_file'. Cannot continue."; + echo "

"; + exit; +} +$settings_str = file_get_contents($configuration_file, true); +$settings_array = json_decode($settings_str, true); +if ($settings_array == null) { + echo "

"; + echo "ERROR: Bad configuration file '$configurationFileName'. Cannot continue."; + echo "
Check for missing quotes or commas at the end of every line (except the last one)."; + echo "

"; + echo "
$settings_str
"; + exit; +} +$onPi = v("onPi", true, $settings_array['homePage']); + +// If on a Pi, check that the placeholder was replaced. +if ($onPi && ALLSKY_CONFIG == "XX_ALLSKY_CONFIG" . "_XX") { // This file hasn't been updated yet after installation. echo "
"; echo ""; - echo "Please run the following from the 'allsky' directory before using the Website:"; + echo "If this Website is running on a Pi, please run the following:"; + echo ""; + echo "
"; + echo "        cd ~/allsky"; + echo "
        website/install.sh --update"; + echo "
"; + + echo ""; + echo "

If instead, this Website is being run on a remote server, change the onPi variable in the '$configurationFileName' configuration file to false."; echo "
"; - echo "

website/install.sh --update"; echo "
"; exit; } @@ -88,9 +131,14 @@ function get_variable($file, $searchfor, $default) // Format: [stuff]$searchfor=$value or [stuff]$searchfor="$value" // Need to delete [stuff]$searchfor= and optional double quotes - $last = $matches[0][$num_matches - 1]; // get the last one - $last = explode( '=', $last)[1]; // get everything after equal sign - $last = str_replace($double_quote, "", $last); + $last = $matches[0][$num_matches - 1]; // get the last one + $both = explode( '=', $last); + if (isset($both[1])) { + $last = $both[1]; // everything after equal sign + $last = str_replace($double_quote, "", $last); + } else { + return($default); // nothing after "=" + } return($last); } else { return($default); @@ -198,6 +246,7 @@ function make_thumb_from_video($src, $dest, $desired_width, $attempts) else $sec = "00"; $command = "ffmpeg -loglevel warning -ss 00:00:$sec -i '$src' -filter:v scale='$desired_width:-1' -frames:v 1 '$dest' 2>&1"; + $output = array(); exec($command, $output); if (file_exists($dest)) { if (filesize($dest) === 0) { @@ -264,7 +313,7 @@ function display_thumbnails($dir, $file_prefix, $title) echo "
$back_button $title
"; echo "
\n"; - $thumbnailSizeX = get_variable(ALLSKY_CONFIG .'/config.sh', 'THUMBNAILSIZE_X=', '100'); + $thumbnailSizeX = get_variable(ALLSKY_CONFIG .'/config.sh', 'THUMBNAIL_SIZE_X=', '100'); foreach ($files as $file) { // The thumbnail should be a .jpg. $thumbnail = preg_replace($ext, ".jpg", "$dir/thumbnails/$file"); @@ -295,4 +344,39 @@ function display_thumbnails($dir, $file_prefix, $title) echo "
"; // clears "float" from archived-files echo "

"; } + +// Read and decode a json file, returning the decoded results or null. +// On error, display the specified error message +function get_decoded_json_file($file, $associative, $errorMsg) { + if (! file_exists($file)) { + echo "
"; + echo "$errorMsg:"; + echo "
File '$file' missing!"; + echo "
"; + return null; + } + + $str = file_get_contents($file, true); + if ($str === "") { + echo "
"; + echo "$errorMsg:"; + echo "
File '$file' is empty!"; + echo "
"; + return null; + } + + $str_array = json_decode($str, $associative); + if ($str_array == null) { + echo "
"; + echo "$errorMsg:"; + echo "
" . json_last_error_msg(); + $cmd = "json_pp < $file 2>&1"; + exec($cmd, $output); + echo "
" . implode("
", $output); + echo "
"; + return null; + } + return $str_array; +} + ?> diff --git a/index.php b/index.php index 1dfdc81..58b20e0 100644 --- a/index.php +++ b/index.php @@ -1,81 +1,254 @@ - + Making"; + if (! mkdir($thumb_dir, 0775, true)) { // true == recursive + $ok = false; + $last_error = error_get_last(); + echo "\nUnable to make '$thumb_dir' directory: " . $last_error["message"]; + } + } + } + + // TODO: add other checks here + + if (! $ok) exit; + + if ($debug) echo "\n"; // ends any lines already output + echo "SUCCESS\n"; + exit; + } +?> - Allsky - {{title}} + + + config = {\n"; + foreach ($config as $var => $val) { // ok to have comma after last entry + echo "\t\t$var: "; + if ($val === true || $val === false || $val === null || is_numeric($val)) { + echo var_export($val, true) . ",\n"; + } else if (is_array($val)) { + echo '"[array]",' . "\n"; + } else { + echo '"' . str_replace('"', '\"', $val) . '",' . "\n"; + } + } + // Add additional variable(s) from $homePage that are needed in controller.js. + echo "\t\timageBorder: $imageBorder,\n"; + echo "\t\ttitle: " . '"' . $title . '",' . "\n"; + echo "\t\tloadingImage: " . '"' . $loadingImage . '"'; + + echo "\n\t}"; + echo "\n\t\n"; + ?> + + <?php echo $title ?> + - - - - + + + + + + - + + - - + + - - - + + + - + + - +>
-
{{title}}
-
+
+
Aurora activity: {{key}}: {{getScale(val)}}
-
-
-
-
    -
  •   Location: {{location}}
  • -
  • Latitude: {{latitude < 0 ? latitude * -1 + 'S' : latitude + 'N'}}
  • -
  • Longitude: {{longitude < 0 ? longitude * -1 + 'W' : longitude + 'E'}}
  • -
  •   Camera: {{camera}}
  • -
  •   Lens: {{lens}}
  • -
  •   Computer: {{computer}}
  • -
  •   Owner: {{owner}}
  • -
+
+"; + if ($personalLink_prelink !== "") echo "$personalLink_prelink"; + echo "$personalLink_message"; + echo "
"; + } +?> +
+ 0) { + echo "\t
\n"; + echo "\t\t
    \n"; + foreach ($popoutIcons as $popout) { + $display = v("display", false, $popout); + if (! $display) continue; + + $label = v("label", "", $popout); + $icon = v("icon", "", $popout); + $js_variable = v("variable", "", $popout); + $value = v("value", "", $popout); + $style = v("style", "", $popout); + if ($style != "") $style = "style='$style'"; + echo "\t\t\t
  •   $label:  "; + if ($js_variable != "") + echo "{{ $js_variable }}"; + else + echo "$value"; + echo "
  • \n"; + } + echo "\t\t
\n"; + echo "\t
\n"; + } +?> -