diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..cd2946ad --- /dev/null +++ b/.gitignore @@ -0,0 +1,47 @@ +# Windows image file caches +Thumbs.db +ehthumbs.db + +# Folder config file +Desktop.ini + +# Recycle Bin used on file shares +$RECYCLE.BIN/ + +# Windows Installer files +*.cab +*.msi +*.msm +*.msp + +# Windows shortcuts +*.lnk + +# ========================= +# Operating System Files +# ========================= + +# OSX +# ========================= + +.DS_Store +.AppleDouble +.LSOverride + +# Thumbnails +._* + +# Files that might appear in the root of a volume +.DocumentRevisions-V100 +.fseventsd +.Spotlight-V100 +.TemporaryItems +.Trashes +.VolumeIcon.icns + +# Directories potentially created on remote AFP share +.AppleDB +.AppleDesktop +Network Trash Folder +Temporary Items +.apdisk diff --git a/archive/community.applications-2016.10.12.txz b/archive/community.applications-2016.10.12.txz new file mode 100644 index 00000000..01d4b6b9 Binary files /dev/null and b/archive/community.applications-2016.10.12.txz differ diff --git a/archive/community.applications-2016.10.13.txz b/archive/community.applications-2016.10.13.txz new file mode 100644 index 00000000..b5be0148 Binary files /dev/null and b/archive/community.applications-2016.10.13.txz differ diff --git a/archive/community.applications-2016.10.26.txz b/archive/community.applications-2016.10.26.txz new file mode 100644 index 00000000..cc25b204 Binary files /dev/null and b/archive/community.applications-2016.10.26.txz differ diff --git a/archive/community.applications-2016.10.30.txz b/archive/community.applications-2016.10.30.txz new file mode 100644 index 00000000..ead595d4 Binary files /dev/null and b/archive/community.applications-2016.10.30.txz differ diff --git a/archive/community.applications-2016.11.05.txz b/archive/community.applications-2016.11.05.txz new file mode 100644 index 00000000..311aafb6 Binary files /dev/null and b/archive/community.applications-2016.11.05.txz differ diff --git a/archive/community.applications-2016.11.06.txz b/archive/community.applications-2016.11.06.txz new file mode 100644 index 00000000..718e206d Binary files /dev/null and b/archive/community.applications-2016.11.06.txz differ diff --git a/archive/community.applications-2016.11.10a.txz b/archive/community.applications-2016.11.10a.txz new file mode 100644 index 00000000..c3f41730 Binary files /dev/null and b/archive/community.applications-2016.11.10a.txz differ diff --git a/archive/community.applications-2016.11.11a.txz b/archive/community.applications-2016.11.11a.txz new file mode 100644 index 00000000..d8d38147 Binary files /dev/null and b/archive/community.applications-2016.11.11a.txz differ diff --git a/archive/community.applications-2016.11.13.txz b/archive/community.applications-2016.11.13.txz new file mode 100644 index 00000000..15ba0237 Binary files /dev/null and b/archive/community.applications-2016.11.13.txz differ diff --git a/archive/community.applications-2016.12.03.txz b/archive/community.applications-2016.12.03.txz new file mode 100644 index 00000000..63167e21 Binary files /dev/null and b/archive/community.applications-2016.12.03.txz differ diff --git a/archive/community.applications-2016.12.05.txz b/archive/community.applications-2016.12.05.txz new file mode 100644 index 00000000..f3121aad Binary files /dev/null and b/archive/community.applications-2016.12.05.txz differ diff --git a/archive/community.applications-2016.12.30.txz b/archive/community.applications-2016.12.30.txz new file mode 100644 index 00000000..aefb8dde Binary files /dev/null and b/archive/community.applications-2016.12.30.txz differ diff --git a/archive/community.applications-2016.12.31.txz b/archive/community.applications-2016.12.31.txz new file mode 100644 index 00000000..5031e8a4 Binary files /dev/null and b/archive/community.applications-2016.12.31.txz differ diff --git a/archive/community.applications-2017.01.22.txz b/archive/community.applications-2017.01.22.txz new file mode 100644 index 00000000..ab050346 Binary files /dev/null and b/archive/community.applications-2017.01.22.txz differ diff --git a/archive/community.applications-2017.01.23.txz b/archive/community.applications-2017.01.23.txz new file mode 100644 index 00000000..b05673cd Binary files /dev/null and b/archive/community.applications-2017.01.23.txz differ diff --git a/archive/community.applications-2017.01.24.txz b/archive/community.applications-2017.01.24.txz new file mode 100644 index 00000000..338a6c4d Binary files /dev/null and b/archive/community.applications-2017.01.24.txz differ diff --git a/archive/community.applications-2017.01.29.txz b/archive/community.applications-2017.01.29.txz new file mode 100644 index 00000000..5c8faa25 Binary files /dev/null and b/archive/community.applications-2017.01.29.txz differ diff --git a/archive/community.applications-2017.02.12.txz b/archive/community.applications-2017.02.12.txz new file mode 100644 index 00000000..bde68fec Binary files /dev/null and b/archive/community.applications-2017.02.12.txz differ diff --git a/archive/community.applications-2017.02.25.txz b/archive/community.applications-2017.02.25.txz new file mode 100644 index 00000000..85df52cb Binary files /dev/null and b/archive/community.applications-2017.02.25.txz differ diff --git a/archive/community.applications-2017.03.18.txz b/archive/community.applications-2017.03.18.txz new file mode 100644 index 00000000..2b603e12 Binary files /dev/null and b/archive/community.applications-2017.03.18.txz differ diff --git a/archive/community.applications-2017.03.19a.txz b/archive/community.applications-2017.03.19a.txz new file mode 100644 index 00000000..aeede651 Binary files /dev/null and b/archive/community.applications-2017.03.19a.txz differ diff --git a/archive/community.applications-2017.03.21.txz b/archive/community.applications-2017.03.21.txz new file mode 100644 index 00000000..ad9ea994 Binary files /dev/null and b/archive/community.applications-2017.03.21.txz differ diff --git a/archive/community.applications-2017.03.22.txz b/archive/community.applications-2017.03.22.txz new file mode 100644 index 00000000..dc375be6 Binary files /dev/null and b/archive/community.applications-2017.03.22.txz differ diff --git a/archive/community.applications-2017.04.02a.txz b/archive/community.applications-2017.04.02a.txz new file mode 100644 index 00000000..db6ad6f5 Binary files /dev/null and b/archive/community.applications-2017.04.02a.txz differ diff --git a/archive/community.applications-2017.04.02b.txz b/archive/community.applications-2017.04.02b.txz new file mode 100644 index 00000000..68cfdd5b Binary files /dev/null and b/archive/community.applications-2017.04.02b.txz differ diff --git a/archive/community.applications-2017.04.04.txz b/archive/community.applications-2017.04.04.txz new file mode 100644 index 00000000..2c414455 Binary files /dev/null and b/archive/community.applications-2017.04.04.txz differ diff --git a/archive/community.applications-2017.04.08.txz b/archive/community.applications-2017.04.08.txz new file mode 100644 index 00000000..306578c7 Binary files /dev/null and b/archive/community.applications-2017.04.08.txz differ diff --git a/archive/community.applications-2017.04.09.txz b/archive/community.applications-2017.04.09.txz new file mode 100644 index 00000000..67cfad67 Binary files /dev/null and b/archive/community.applications-2017.04.09.txz differ diff --git a/archive/community.applications-2017.04.10.txz b/archive/community.applications-2017.04.10.txz new file mode 100644 index 00000000..b5cde92d Binary files /dev/null and b/archive/community.applications-2017.04.10.txz differ diff --git a/archive/community.applications-2017.04.11.txz b/archive/community.applications-2017.04.11.txz new file mode 100644 index 00000000..6d6ca9d4 Binary files /dev/null and b/archive/community.applications-2017.04.11.txz differ diff --git a/archive/community.applications-2017.04.13.txz b/archive/community.applications-2017.04.13.txz new file mode 100644 index 00000000..9cdcf8f8 Binary files /dev/null and b/archive/community.applications-2017.04.13.txz differ diff --git a/archive/community.applications-2017.04.18.txz b/archive/community.applications-2017.04.18.txz new file mode 100644 index 00000000..451ce0ff Binary files /dev/null and b/archive/community.applications-2017.04.18.txz differ diff --git a/archive/community.applications-2017.04.19.txz b/archive/community.applications-2017.04.19.txz new file mode 100644 index 00000000..bc94672c Binary files /dev/null and b/archive/community.applications-2017.04.19.txz differ diff --git a/archive/community.applications-2017.04.22.txz b/archive/community.applications-2017.04.22.txz new file mode 100644 index 00000000..32b7123d Binary files /dev/null and b/archive/community.applications-2017.04.22.txz differ diff --git a/archive/community.applications-2017.04.22.txz_last_ver_to_support_legacy_UI b/archive/community.applications-2017.04.22.txz_last_ver_to_support_legacy_UI new file mode 100644 index 00000000..f1cb5542 Binary files /dev/null and b/archive/community.applications-2017.04.22.txz_last_ver_to_support_legacy_UI differ diff --git a/archive/community.applications-2017.04.23.txz b/archive/community.applications-2017.04.23.txz new file mode 100644 index 00000000..4ba7d66d Binary files /dev/null and b/archive/community.applications-2017.04.23.txz differ diff --git a/archive/community.applications-2017.04.24a.txz b/archive/community.applications-2017.04.24a.txz new file mode 100644 index 00000000..44c246ad Binary files /dev/null and b/archive/community.applications-2017.04.24a.txz differ diff --git a/archive/community.applications-2017.04.25.txz b/archive/community.applications-2017.04.25.txz new file mode 100644 index 00000000..0d16aa7b Binary files /dev/null and b/archive/community.applications-2017.04.25.txz differ diff --git a/archive/community.applications-2017.04.29a.txz b/archive/community.applications-2017.04.29a.txz new file mode 100644 index 00000000..5af822a2 Binary files /dev/null and b/archive/community.applications-2017.04.29a.txz differ diff --git a/archive/community.applications-2017.04.29b.txz b/archive/community.applications-2017.04.29b.txz new file mode 100644 index 00000000..f8f60d9a Binary files /dev/null and b/archive/community.applications-2017.04.29b.txz differ diff --git a/archive/community.applications-2017.04.30.txz b/archive/community.applications-2017.04.30.txz new file mode 100644 index 00000000..0125ab20 Binary files /dev/null and b/archive/community.applications-2017.04.30.txz differ diff --git a/archive/community.applications-2017.05.04a.txz b/archive/community.applications-2017.05.04a.txz new file mode 100644 index 00000000..dac54f2e Binary files /dev/null and b/archive/community.applications-2017.05.04a.txz differ diff --git a/archive/community.applications-2017.05.07.txz b/archive/community.applications-2017.05.07.txz new file mode 100644 index 00000000..2fecd8b8 Binary files /dev/null and b/archive/community.applications-2017.05.07.txz differ diff --git a/archive/community.applications-2017.05.08.txz b/archive/community.applications-2017.05.08.txz new file mode 100644 index 00000000..e7b13789 Binary files /dev/null and b/archive/community.applications-2017.05.08.txz differ diff --git a/archive/community.applications-2017.05.14.txz b/archive/community.applications-2017.05.14.txz new file mode 100644 index 00000000..edf0c2c7 Binary files /dev/null and b/archive/community.applications-2017.05.14.txz differ diff --git a/archive/community.applications-2017.05.16.txz b/archive/community.applications-2017.05.16.txz new file mode 100644 index 00000000..a9f0fccc Binary files /dev/null and b/archive/community.applications-2017.05.16.txz differ diff --git a/archive/community.applications-2017.05.18.txz b/archive/community.applications-2017.05.18.txz new file mode 100644 index 00000000..fb8467f2 Binary files /dev/null and b/archive/community.applications-2017.05.18.txz differ diff --git a/archive/community.applications-2017.05.19.txz b/archive/community.applications-2017.05.19.txz new file mode 100644 index 00000000..c773fae7 Binary files /dev/null and b/archive/community.applications-2017.05.19.txz differ diff --git a/archive/community.applications-2017.05.20.txz b/archive/community.applications-2017.05.20.txz new file mode 100644 index 00000000..04ec28e5 Binary files /dev/null and b/archive/community.applications-2017.05.20.txz differ diff --git a/archive/community.applications-2017.05.20a.txz b/archive/community.applications-2017.05.20a.txz new file mode 100644 index 00000000..11d19f6e Binary files /dev/null and b/archive/community.applications-2017.05.20a.txz differ diff --git a/archive/community.applications-2017.05.21.txz b/archive/community.applications-2017.05.21.txz new file mode 100644 index 00000000..43805d60 Binary files /dev/null and b/archive/community.applications-2017.05.21.txz differ diff --git a/archive/community.applications-2017.05.22.txz b/archive/community.applications-2017.05.22.txz new file mode 100644 index 00000000..99897b81 Binary files /dev/null and b/archive/community.applications-2017.05.22.txz differ diff --git a/archive/community.applications-2017.05.23.txz b/archive/community.applications-2017.05.23.txz new file mode 100644 index 00000000..4453ddf4 Binary files /dev/null and b/archive/community.applications-2017.05.23.txz differ diff --git a/archive/community.applications-2017.05.24.txz b/archive/community.applications-2017.05.24.txz new file mode 100644 index 00000000..1c949b01 Binary files /dev/null and b/archive/community.applications-2017.05.24.txz differ diff --git a/archive/community.applications-2017.05.25.txz b/archive/community.applications-2017.05.25.txz new file mode 100644 index 00000000..1311176f Binary files /dev/null and b/archive/community.applications-2017.05.25.txz differ diff --git a/archive/community.applications-2017.05.26.txz b/archive/community.applications-2017.05.26.txz new file mode 100644 index 00000000..39a47475 Binary files /dev/null and b/archive/community.applications-2017.05.26.txz differ diff --git a/archive/community.applications-2017.05.27.txz b/archive/community.applications-2017.05.27.txz new file mode 100644 index 00000000..f299b1a2 Binary files /dev/null and b/archive/community.applications-2017.05.27.txz differ diff --git a/archive/community.applications-2017.05.29.txz b/archive/community.applications-2017.05.29.txz new file mode 100644 index 00000000..79c5c457 Binary files /dev/null and b/archive/community.applications-2017.05.29.txz differ diff --git a/archive/community.applications-2017.05.30.txz b/archive/community.applications-2017.05.30.txz new file mode 100644 index 00000000..e584d9f9 Binary files /dev/null and b/archive/community.applications-2017.05.30.txz differ diff --git a/archive/community.applications-2017.06.05.txz b/archive/community.applications-2017.06.05.txz new file mode 100644 index 00000000..9addaa02 Binary files /dev/null and b/archive/community.applications-2017.06.05.txz differ diff --git a/archive/community.applications-2017.06.08.txz b/archive/community.applications-2017.06.08.txz new file mode 100644 index 00000000..ee1f609b Binary files /dev/null and b/archive/community.applications-2017.06.08.txz differ diff --git a/archive/community.applications-2017.06.10.txz b/archive/community.applications-2017.06.10.txz new file mode 100644 index 00000000..574164ef Binary files /dev/null and b/archive/community.applications-2017.06.10.txz differ diff --git a/archive/community.applications-2017.06.15.txz b/archive/community.applications-2017.06.15.txz new file mode 100644 index 00000000..32c3809c Binary files /dev/null and b/archive/community.applications-2017.06.15.txz differ diff --git a/archive/community.applications-2017.06.16.txz b/archive/community.applications-2017.06.16.txz new file mode 100644 index 00000000..085f814e Binary files /dev/null and b/archive/community.applications-2017.06.16.txz differ diff --git a/archive/community.applications-2017.06.18a.txz b/archive/community.applications-2017.06.18a.txz new file mode 100644 index 00000000..95a686a8 Binary files /dev/null and b/archive/community.applications-2017.06.18a.txz differ diff --git a/archive/community.applications-2017.06.21.txz b/archive/community.applications-2017.06.21.txz new file mode 100644 index 00000000..79c9a81d Binary files /dev/null and b/archive/community.applications-2017.06.21.txz differ diff --git a/archive/community.applications-2017.06.25.txz b/archive/community.applications-2017.06.25.txz new file mode 100644 index 00000000..88639d0c Binary files /dev/null and b/archive/community.applications-2017.06.25.txz differ diff --git a/archive/community.applications-2017.06.30.txz b/archive/community.applications-2017.06.30.txz new file mode 100644 index 00000000..3d827650 Binary files /dev/null and b/archive/community.applications-2017.06.30.txz differ diff --git a/archive/community.applications-2017.07.01.txz b/archive/community.applications-2017.07.01.txz new file mode 100644 index 00000000..13653ad6 Binary files /dev/null and b/archive/community.applications-2017.07.01.txz differ diff --git a/archive/community.applications-2017.07.01a.txz b/archive/community.applications-2017.07.01a.txz new file mode 100644 index 00000000..aa6c79bb Binary files /dev/null and b/archive/community.applications-2017.07.01a.txz differ diff --git a/archive/community.applications-2017.07.02.txz b/archive/community.applications-2017.07.02.txz new file mode 100644 index 00000000..c97a2d09 Binary files /dev/null and b/archive/community.applications-2017.07.02.txz differ diff --git a/archive/community.applications-2017.07.02a.txz b/archive/community.applications-2017.07.02a.txz new file mode 100644 index 00000000..0c90460f Binary files /dev/null and b/archive/community.applications-2017.07.02a.txz differ diff --git a/archive/community.applications-2017.07.08.txz b/archive/community.applications-2017.07.08.txz new file mode 100644 index 00000000..2fd5c61b Binary files /dev/null and b/archive/community.applications-2017.07.08.txz differ diff --git a/archive/community.applications-2017.07.12.txz b/archive/community.applications-2017.07.12.txz new file mode 100644 index 00000000..b18c39b9 Binary files /dev/null and b/archive/community.applications-2017.07.12.txz differ diff --git a/archive/community.applications-2017.07.13.txz b/archive/community.applications-2017.07.13.txz new file mode 100644 index 00000000..776319b9 Binary files /dev/null and b/archive/community.applications-2017.07.13.txz differ diff --git a/archive/community.applications-2017.07.14.txz b/archive/community.applications-2017.07.14.txz new file mode 100644 index 00000000..b0c58c96 Binary files /dev/null and b/archive/community.applications-2017.07.14.txz differ diff --git a/archive/community.applications-2017.07.15.txz b/archive/community.applications-2017.07.15.txz new file mode 100644 index 00000000..e05160e2 Binary files /dev/null and b/archive/community.applications-2017.07.15.txz differ diff --git a/archive/community.applications-2017.07.16.txz b/archive/community.applications-2017.07.16.txz new file mode 100644 index 00000000..4e1443cf Binary files /dev/null and b/archive/community.applications-2017.07.16.txz differ diff --git a/archive/community.applications-2017.07.19.txz b/archive/community.applications-2017.07.19.txz new file mode 100644 index 00000000..a1fa721e Binary files /dev/null and b/archive/community.applications-2017.07.19.txz differ diff --git a/archive/community.applications-2017.07.20a.txz b/archive/community.applications-2017.07.20a.txz new file mode 100644 index 00000000..ca1b4680 Binary files /dev/null and b/archive/community.applications-2017.07.20a.txz differ diff --git a/archive/community.applications-2017.07.22.txz b/archive/community.applications-2017.07.22.txz new file mode 100644 index 00000000..c604da01 Binary files /dev/null and b/archive/community.applications-2017.07.22.txz differ diff --git a/archive/community.applications-2017.07.23.txz b/archive/community.applications-2017.07.23.txz new file mode 100644 index 00000000..5822ab55 Binary files /dev/null and b/archive/community.applications-2017.07.23.txz differ diff --git a/archive/community.applications-2017.07.24.txz b/archive/community.applications-2017.07.24.txz new file mode 100644 index 00000000..723ab2ba Binary files /dev/null and b/archive/community.applications-2017.07.24.txz differ diff --git a/archive/community.applications-2017.07.31.txz b/archive/community.applications-2017.07.31.txz new file mode 100644 index 00000000..895a7c8b Binary files /dev/null and b/archive/community.applications-2017.07.31.txz differ diff --git a/community.applications-2017.07.13.txz b/community.applications-2017.07.13.txz new file mode 100644 index 00000000..776319b9 Binary files /dev/null and b/community.applications-2017.07.13.txz differ diff --git a/copy_to_git.sh b/copy_to_git.sh new file mode 100644 index 00000000..fe1c8439 --- /dev/null +++ b/copy_to_git.sh @@ -0,0 +1,7 @@ +#!/bin/bash + +mkdir -p "/tmp/GitHub/community.applications/source/community.applications/usr/local/emhttp/plugins/community.applications/" + +cp /usr/local/emhttp/plugins/community.applications/* /tmp/GitHub/community.applications/source/community.applications/usr/local/emhttp/plugins/community.applications -R -v -p + + diff --git a/pkg_build.sh b/pkg_build.sh new file mode 100644 index 00000000..f7359cd7 --- /dev/null +++ b/pkg_build.sh @@ -0,0 +1,4 @@ +#!/bin/bash +cd source/community.applications +pkg_build.sh + diff --git a/plugins/community.applications.plg b/plugins/community.applications.plg new file mode 100644 index 00000000..ef23ce3b --- /dev/null +++ b/plugins/community.applications.plg @@ -0,0 +1,819 @@ + + + + + + + + + +]> + + + + +###2017.07.31 +- Update URL for application feed + +###2017.07.24 +- Better enforcement of fatal errors in application templates +- Code cleanup +- Fixed: Edge case of being able to search dockerhub if docker is not enabled +- Fixed: Edge case of app of the day no longer valid app after an update + +###2017.07.20 +- Multiple Installation of Previous Apps + - Fixed: Clicking outside of the install button would attempt to install + - Fixed: Selected Apps would not stay selected following a view or page change + - Added: Ability to select apps from different pages and have them all install + +###2017.07.16 +- Enhanced: Search box has focus when page loaded (Just start typing instead of clicking within) +- Enhanced: After installing / editing a docker application, pressing DONE will return to the Apps page (previously blank template would appear) +- Added: Ability to install multiple applications (docker / plugin) simultaneously from the Previous Apps section without confirming the already filled out template. +- Changed: Default for Displayed results per page from 10 to 25 +- Removed: Option to open install / edit pages in a new tab + +###2017.07.08 +- Minor changes to appfeed statistics displays + +###2017.07.02 +- Don't revert to legacy mode automatically if appfeed fails (probably due to DNS failure. Previously could take an hour to time out in this circumstance. New method will time out in 2-3 minutes) +- Fixed: Under certain circumstances with docker service disabled, app pop ups could display errors + +###2017.07.01a +- Fix regression error when updating CA from within CA would not reload the page after installation finished + +###2017.07.01 +- Added in sort by date when in New Apps section +- Fixed Categories not resetting after a search performed + +###2017.06.25 +- Remove sort by date and do not display except on plugins (rarely do docker maintainers update it which makes for a lot of confusion) +- Fixed: Under certain circumstances, app info popups in previous apps would display the incorrect information +- Add a comment if an app is deprecated +- Fixed: Prevent apps not in appfeed from displaying a pop up +- Remove some excess code and files +- Fix CSS on statistics displays + +###2017.06.18 +- Expanded details on statistics +- Removed resource monitor (see thread for details) + +###2017.06.10 +- Adjustable Disappear time on app popups + +###2017.06.05 +- Fixed: Regression error in Resource Monitor if no applications running + +###2017.05.30 +- Fixed: Display Aberration in Table Mode under certain conditions +- Enhanced: View Mode and Results per Page saved between instances +- Enhanced: Increased compatibility with older browsers +- Added: Statistics Display for appfeed +- Code cleanup + +###2017.05.21 +- Enhanced: Update plugins now refreshes page instead of reloading +- Enhanced: Install plugins now refreshes page instead of reloading +- Enhanced: Increase search speed on installed apps +- Added: Paging when utilizing favourite repositories +- Code cleanup + +###2017.05.19 +- Fixed: Display anomalies introduced by unRaid 6.3.4 +- Fixed: Minor issues with category / subcategory buttons + +###2017.05.16 +- Fixed: Under certain circumstances the popup would disappear immediately when moving the mouse +- Added: More fixes for common template author's mistakes +- Minor skin changes in Icon Details mode + +###2017.05.08 +- Enhanced: Speed up generation of displays +- Enhanced: Properly handle edge cases of multiple browser tabs open and stale CA sessions displaying popups +- Added / Restored: Ability to install / edit from Icon mode without hitting popup. + +###2017.05.07 +- Fixed: Regression error on apppop up for previous apps + +###2017.05.04 +- Add Install / Edit / WebUI icons to icon details mode + +###2017.04.30 +- Added: Ability to jump directly to an author / maintainer's profile (to help with selecting whether to install or not) + +###2017.04.29a +- Added: Adjustable setting for "hover time" before a popup appears + +###2017.04.29 +- Fix Compatibility with Internet Explorer and Opera +- Fix Button incorrectly displaying on an installed application utilizing Branches +- Fix Changelog not displaying for CA when update is available + +###2017.04.24a +- Don't display webUI link if docker app is not running + +###2017.04.24 +- Remove legacy UI +- Revamp GUI +- All installs / edits / etc handled via hovering over (or clicking on the icon for the app) +- Fixed: Minor issues with paging + +###2017.04.09### +- Introduce new UI to remove less commonly used buttons from screen. + +###2017.04.04### +- Fix 6.2.x compatibility + +###2017.04.02### +- Implement new features made available by 6.3.3+ (Still fully compatible with older versions of unRaid) + - Hovering over app's icon opens up the full description + - Hovering over changes icon opens up the change log + - Use tooltipster exclusively (tooltips will open after 1.5 seconds, and automaticaly close after 15 seconds) + +###2017.03.22### +- Misc Display Fixes + +###2017.03.21### +- Maintenance update: Prevent Deprecated apps from appearing on available apps lists + +###2017.03.19a### +- Ability to switch max per page on the fly +- Unify docker search navigation with appstore navigation + +###2017.03.19### +- Misc improvements to paging + +###2017.03.18### +- Added limit results to "x" per page + +###2017.02.25### +- Update links within plugin screens + +###2017.02.12### +- Maintenance update. Add more fixes for template errors from authors + +###2017.01.29### +- Added: Automatic Blacklisting if a template poses a security risk + +###2017.01.24### +- Security fix on full description popups +- Fixed: Show stats on full description popups if app name has been changed + +###2016.12.31### +- Fix permission issues resulting from a migration of development machines + +###2016.12.30### +- Suppress invalid cron job email + +###2016.12.05### +- Fixed: Stopping array would hang until any calculations of appdata size was completed if CA Backup was not installed + +###2016.12.03### +- Fix pop up descriptions in Previous Apps +- Don't process blacklisted apps + +###2016.11.13### +- Fixed: CA Modules displaying incompatible add-ons + +###2016.11.11### +- Allow separate installs / removal of included modules + +###2016.11.05### +- Infrastructure changes to ultimately allow separate module installation / deinstallation + +###2016.10.30### +- Fixed: Dynamix Bleeding Edge 2016.10.29c compatibility + +###2016.10.26### +- Allow appdata backup source to be any folder on system +- Updated routines to handle potential incompatibility with PHP and unRaid's generated comments + +###2016.10.12### +- Handle edge case template creation by dockerMan + +###2016.09.28### +- Force redirection of additional backup scripts output console + +###2016.09.25a### +- Speed up appfeed download + +###2016.09.25### +- Added: Selectable delay in days before autoupdating a plugin +- Added: Backup of old .plg files prior to backup to support edge-case rollbacks if needed +- Updated: Manual + +###2016.09.23### +- NOTE: All auto update settings will be reset back to defaults with this update. IE: Only CA and FCP will autoupdate +- Fixed: CA under certain circumstances would show as not autoupdating in settings when in fact it would +- Fixed: Under very specific circumstances, some plugins set to not autoupdate could in fact auto update +- Fixed: PhAzE plugins would not show up as installed if they were + +###2016.09.21### +- Extra security tests on auto updates +- Implement autoupdate kill switch + +###2016.09.17### +- Compatibility fix for dynamix.bleeding.edge.plg + +###2016.09.15### +- Fixed minor compatibilty issues with 6.2 Final +- Changed: Only log maximum 10 rsync errors in backup module +- Fixed: disallow faster rsync option if days to keep backup sets is disabled (or set to 0) +- Fixed: backup to flashdrive setting (entry could have been possibly corrupted under 2016.09.03) +- Added: Script to delete old dated backups in addition to ALL backups and error backups only +- Changed: Update Apps now called Legacy Mode. Selecting again goes back to appFeed mode +- Removed: Private Repositories via a GitHub repo. +- Added: Selectable notifications on autoupdates of plugins +- Added: XML Branch support while in Legacy Mode +- Fixed: Display aberrations while in legacy mode if some repositories didn't download +- Added: Legacy mode will now display any XML's which failed to parse + +###2016.09.07### +- Fixed VM XML's not backing up under certain circumstances +- Do not delete XML backups if source is no longer available +- Added Dynamic adjustment of templates based upon user input + +###2016.09.06### +- Fixed Backup/Restore settings module not working +- Added Selectable display for Random App Of Day + +###2016.09.04### +- Under certain cirumstances, app of the day could crash CA +- Download compressed version of appfeed + +###2016.09.03### +- Added in VM XML backups +- Major rewrite of display engine (faster, far smaller) +- Fix app of day to not possibly display moderated apps if app feed happened to change during the day +- Fix various buttons not properly getting disabled when forcing update under certain circumstances +- Fixed search on author where apps would always display as being installed +- Far too many coding changes to list + +###2016.08.13### +- Maintenance Update +- Added Apps of the day +- Fixed display abnormalities in Table Mode under certain conditions / templates +- Fixed displayed borders on popups +- Updated manual +- Removed extraneous code +- Fixed base image display when in legacy mode + +###2016.08.07### +- Added in ability to flag / pin apps for later viewing + +###2016.08.03### +- Fixed: Restore appdata when using user shares as a destination + +###2016.07.31### +- Support user shares as source and destination for appdata backup on 6.2-rc3+ + +###2016.07.23### +- Major revamp to backup/restore appdata module (see thread for details) + +###2016.07.16### +- Better logging for CA Backup + +###2016.07.08### +- Bug fix on dockerHub searches vs recommended applications + +###2016.07.04### +- Fixed cleanup appdata if an installed app doesn't have any volume mappings + +###2016.07.01### +- Support Separate Destinations for Flash Drive Backup + +###2016.06.29### +- Backup Disk Assignments and super.dat (renamed) as part of USB backup + +###2016.06.26### +- Backup options not displaying the set value for save log to flash +- Fix improper displaying of source and destination on popup (restore) +- Suppress errors displayed when selecting a UD mount for backup purposes +- Added in backup of flash drive (sans super.dat) to docker appdata prior to backing up to array + +###2016.06.25k### +- Add directions for backups for UD mounted shares + +###2016.06.13### +- Fix typos +- Prevent appdata cleanup from deleting parent folders (due to severely misconfigured previous template) +- Add support and project links back to table mode (not sure how / when they got removed) + +###2016.06.12### +- Miscellaneous enhancements and fixes + +###2016.06.11### +- Added: New module to delete orphaned appdata folders +- Better appdata determination if running unRaid 6.2+ + +###2016.06.05### +- Fixed: Prevent invalid Support and Project URLs from displaying + +###2016.06.02### +- Add in option to speed up backups when using dated backups with automatic deletions + +###2016.05.30### +- Add in automatic deletion of old dated backup sets + +###2016.05.12### +- Add in dated backup of appdata + +###2016.05.08### +- Fixed some bugs with AutoUpdate displays + +###2016.05.05### +- Enhanced: Backup - better logging into syslog +- Added: Configurable logging options +- Fixed: Suppress errors if plugins don't have a readme + +###2016.05.01### +- Added Configurable notifications on apppdata backup +- Added Exluded folders to appdata backup +- Updated: CA manual +- Added rsync errors now logged +- Lowered memory footprint of program + +###2016.04.30### +- Better warnings on overwrites +- Added ability to set backup destinations to a subfolder +- Enhanced script selection / share selection +- Added ability to skip docker.img file on backups +- Fix autoupdate of applications would not always only display installed plugins + +###2016.04.28### +- Added: Support for manual / scheduled backups of appData + +###2016.04.17### +- Added: Ability to Auto Update Selected Plugins + +###2016.04.16### +- Fix: PHP exception when only a single Config entry is present +- Fix: Date application updated when in Legacy mode + +###2016.04.10### +- Enhanced: Further security improvements +- Enhanced: cAdvisor template is now 6.2 compliant +- Fix: Suppress error if no docker applications running when in resource monitor +- Added: Ability to install updates for docker applications +- Enhanced: Better determination of appFeed failure +- Added: Confirmation on Update Applications button +- Updated: Manual, Credits + +###2016.04.01### +- Fix: Under certain circumstances, data structures could get corrupted +- Enhanced: Further security enhancements + +###2016.03.31### +- Security Fix: Prevent arbitrary execution of code from malicious templates +- Fix: Sanitize all Overview out of specification +- Fix: Resource monitor not recognizing cAdvisor installed if name changed +- Fix: Renamed apps will not display usage stats in popup +- Added: option to show change log for CA when updating itself +- Changed: default Host port for cAdvisor to 9243 (something oddball that probably won't conflict with anything else) +- Added: if cAdvisor installed, but not running, abilty to start it within CA +- Updated: Manual + +###2016.03.28### +- Coding optimizations +- Fixed: Don't display a support link if no support link available +- Fixed: Add web-page link if repository authors have a web page +- Added: Ability to install updates for plugins +- Fixed: Resource Monitor not displaying icons for customized appFeed apps +- Fixed: Determination of appdata is now case-insensitive when looking for /config +- Fixed: dockerHub conversions now follow settings for new tab or same tab +- Changed: Default value for new tab or same tab is now same tab + +###2016.03.26### +- Fixed: Customized apps (based upon a default one in appfeed) were being tagged as incompatible +- Enhanced: Friendly reminder if CA is out of date + +###2016.03.24### +- Fixed: Installing previous apps on unRaid 6.2 +- Enhanced: Now fully generates v6.2 compliant xml files for dockerMan + +###2016.03.20### +- Fixed: readmore on searches (regression error) +- Fixed: private repositories (dockerHub searches) were being saved into wrong folder (regression error) +- Enhanced: Update Applications (or reversion to legacy mode) will not fail if a single repository fails to download +- Enhanced: Now include cAdvisor XML template so as to not rely upon smdion's repository +- Enhanced: Popup descriptions now include links to go to cAdvisor's page for running docker applications +- Enhanced: Templates passed through to dockerMan are now Moderated to allow CA to fix any errors, typos, etc in the author's template +- Enhanced: Major overhaul of the XML template generation +- Enhanced: Continuing code cleanup + +###2016.03.13### +- Properly regress to legacy mode in case of improperly formed appFeed +- Overhaul of the javascript + +###2016.03.12### +- Remove option to relocate Users menu (and relocate Apps Tab) Use webUI's display settings instead +- Remove option to set appdata share. CA now always prompts to delete appdata if it sees a /config container path +- Resource Monitor supports appdata's stored anywhere on your system (and within multiple folders) +- Fixed: Minor display aberration introduced by unRaid 6.2 beta 18 +- Fixed: If a calculation of appdata size was in progress you could not stop the array + +###2016.03.10### +- Further enhanced Resource Monitor + +###2016.03.06### +- Fixed: Private Repositories now updated every session +- Added: Resource Monitor for Docker Applications + +###2016.03.04### +- Added: Running docker applications will now dynamically display CPU and memory utilization statistics +- Various other fixes / enhancements + +###2016.02.20### +- Fixed: Under certain circumstances, the domain URL listed in a plugin might not be what the author actually specified (eg: raw.github.com vs raw.githubusercontent.com) causing some plugins to not display in the previously installed section + +###2016.02.19### +- Hot fix for special characters contained within templates + +###2016.02.18### +- Added: Support Licence (and its mispelling of License) in templates +- Fixed: Under certain circumstances, Reinstall button could show up instead of Install + +###2016.02.14### +- Code Cleanup +- Don't display dockerHub stars if not starred +- Hide search dockerHub if in previous / installed apps +- Fix error in settings if temp directory didn't exist + +###2016.02.10### +- Suppress stars.sh error message + +###2016.02.08### +- Fixed: Issue with going from dockerHub searches to installed / previously installed +- Fixed: Disallow dockerHub searches if docker not enabled +- Fixed: Disallow adding a previously installed docker app if docker not enabled +- Removed: Legacy Code +- Removed: dockerHub guess at Icons (api broken) +- Fixed: Suppress an error message due to a bad template +- Fixed: Remove some extra temp files once not needed anymore + +###2016.02.06### +- Fixed: display abnormality with Firefox +- Enhanced: More intelligent determination of d/l counts +- Enhanced: Rearrange display icons +- Enhanced: Table Mode +- Added: Ability to display installed apps within available lists + +###2016.02.04### +- Fix issue with duplicate plugin names + +###2016.02.03### +- Suppress docker error messages if docker not running +- Full information on an app now displays total downloads +- Add sort by downloads + +###2016.02.01### +- Going forward, unRaid version 6.1+ compatible only +- Fixed: Applications with 2 identical names could disappear from the lists +- Added: Uninstall any application within CA +- Added: Optional deleting of an application's appdata - see manual for details +- Added: Favourite Repositories +- Fixed: Moderator Comments Now only download once per session +- Removed: Local server caching of icons (made no sense to me) + +###2016.01.30### +- Added: Separate Installed Apps from categories +- Added: Separate Installed Apps from previously installed +- Added: Incorporate Plugins to installed / previously installed +- Updated: Manual + +###2016.01.28### +- Added: Ability to manage previously installed docker apps (my* templates) + +###2016.01.24### +- Fix: Under certain circumstances, blank templates would appear + +###2016.01.16### +- Fix: Under certain circumstances, updated moderator comments were not being downloaded +- Fix: Under certain circumstances, errors would appear on the popup descriptions + +###2016.01.13### +- Fix: Suppress extraneous message on local console during installation + +###2016.01.10b### +- Change: Appfeed now only downloaded if it has changed + +###2016.01.10### +- Add: Option to not redownload appfeed if reloading apps within a certain time period +- Fix: Alternate icon wasn't displaying properly if template's icon was unavailable +- Updated: Help / Manual + +###2016.01.02### +- Fix: Prevent malformed templates from displaying +- Fix: All private containers were being tagged as being incompatible +- Change AppStore to Apps + +###2015.12.18### +- Add support for enforcement of application OS requirements (see help thread) + +###2015.12.12a### +- Selectable add/edit/settings windows in new tab or not + +###2015.12.12### +- Fix: Minor Icon Issues +- Fix: Plugin changelogs now same format as within a .plg file +- Fix: Not all plugins would properly go to the settings page +- Fix: Plugins not sorting by Author name +- Update: Help / Manual + +###2015.12.08### +- Minor Bug Fixes +- Settings Button for already install plugins will take you to the plugin settings + +###2015.12.06a### +- Disable Update Applications button if an update is in progress NOTE: There is normally zero reason to hit this button anyways +- Fix: Allow user selectable positioning of the AppStore. (Either on the main menu, within settings, or on main menu and move Users to settings) + +###2015.12.06### +THIS IS A REQUIRED UPDATE + +- Relocate plugin from docker tab to its own tab (AppStore) +- Now able to display and install available plugins +- Docker no longer required to be enabled to browse applications + +###2015.12.05### +- Fixed: System wouldn't let you add any application if a private repository was present + +###2015.10.10### +- Suppress commands executed with /bin/sh appearing on local monitor + +###2015.09.29### +- Fixed memory leak with application feed + +###2015.09.20### +- Add in super categories for beta and private (selectable from settings) +- More tweaks to docker conversion engine +- Sanitize the input on searches + relocate temporary files to ram +- various other fixes and tweaks + +###2015.09.15### +- Remove code for unimplemented features +- Disallow installing dockerHub result if a recommended application uses the same repository +- Fix: *.xml not found was appearing on local terminal if no private repositories were found + +###2015.09.12### +- Complete rewrite of dockerHub conversion code, adding more exceptions +- Fix: Clearing search terms no longer displays all containers +- Added in support for moderator comments on a container +- Added in ability to blacklist specific containers + +###2015.09.01### +- Implement change required due to dockerHub changing website again (used in dockerHub search mode) +- Add suggested searches for dockerHub +- Numerous under the hood improvements + +###2015.08.24### +- Handle new restrictions introduced in RC6 + +###2015.08.23### +- Suppress some spurious status messages on unRaid's attached monitor +- Expanded manual +- Display dockerHub star ratings for ALL templates + +###2015.08.20### +- Better search results for icons on dockerHub +- Search for other containers from author (template mode) +- Resolved issue with spaces in search parameters +- Internal reorganization + +###2015.08.15### +- Added in BaseOS display when not in appFeed mode +- Added in Full GUI for searching and converting non-unRaid containers. (See support thread for details) +- Miscellaneous fixes + +###2015.08.12### +- Hot Fix for 6.1RC-3 + +###2015.08.09### +- Hot fix for templates with duplicate tags +- Pop up free in appfeed mode + +###2015.08.02### +- Handle blank descriptions, categories, overviews in appFeed mode +- Fix not able to show changelog on application names containing spaces +- Integrate searching (and converting) from dockerHub + +###2015.07.26a### +- Hot fix for 6.1 RC-2 + +###2015.07.25c### +- Fixed Internet Explorer crashing +- Added Icon Details view mode + +###2015.07.23### +- Unified UI between icon and table mode +- Switch between icon and table mode on the fly +- Faster sorting in icon mode +- Add sort by date updated + +###Note: you must allow your browser to display popups from your server when in appFeed mode### + +###2015.07.20### +- Code unified between tables and icons +- Added pop up descriptions to table mode, hover descriptions to icon mode +- Fix intermittent bug where a blank template could appear + +###2015.07.19### +- 6.1rc-1 Broke Community Applications - Fixed + +###2015.07.18### +- Coding Improvements +- Revamp Icon Mode Descriptions +- Add support for Project Home Page links + +###2015.07.16### +- Significantly reduce memory footprint +- Allow private repositories to be used in conjunction with application feed +- Force Update in application feed mode will temporarily revert to template mode +- Failure to download application feed will revert system to template mode + +###2015.07.15### +- Added option to automatically update the application list when entering Docker tab +- Added in support for Kode's real-time application feed update +- Remove background table lines in icon mode +- Removed option to automatically fill out template paths + +###2015.07.08### +- Clicking the repository will now open the announcement thread in a new tab + +###2015.07.04### +- Added in option to display small icons in icon mode +- Optionally overwrite ALL host paths when in experimental overwrite host path mode + +###2015.07.02### +- Fixed display abberation in table mode when searching for application with change log +###2015.07.01### +- Added an experimental option to automatically fill in host paths. See support thread for details. + +###2015.06.21### +- Table Mode: Repository was not displaying (introduced in 2015.06.14) (my bad - never noticed) + +###2015.06.18### +- Changed to a more intuitive Apply / Done buttons in settings + +###2016.06.17### +- Fixed table header sometimes displaying in Icon Mode +- Made settings default values consistent between modules +- Added help text for Icon Mode +- Icon mode now default + +###2015.06.15### +- Expanded descriptions in Icon mode +- Fixed applications in beta repositories not being flagged correctly + +###2015.06.14a### +- Fixed cursor over information icon and application icon (Icon mode) +- Fixed applications not displaying description if a space was in the name (Icon mode) + +###2015.06.14### +- Added Icon view mode (more mobile friendly!) + +###2015.06.11### +- Coding optimizations +- Add help text + +###2015.06.08### +- Added support for new / updated containers +- Expanded settings section + +###2015.06.06### +- Added a settings section + +###2015.06.03a### +- Optional local caching of application icons + +###2015.06.03### +- Initial display is now blank (faster) +- Going from subcategory to all categories no longer displays all categories + +###2015.06.02### +- Added support for Changes tag +- Added non-intrusive reminder to update applications after 14 days + +###2015.05.31### +- Renamed DNS Servers to be DNS Client / Servers + +###2015.05.30### +- Miscellaneous download fixes + +###2015.05.28### +- Initial Release + + + + + + +]]> + + + + + +# Remove old 'source' files +rm -f $(ls /boot/config/plugins/&name;/&name;*.txz 2>/dev/null|grep -v '&version;') +if [[ -d /boot/config/plugins/repo.update ]]; then rm -rf /boot/config/plugins/repo.update; fi +if [[ -d /usr/local/emhttp/plugins/repo.update ]]; then rm -rf /usr/local/emhttp/plugins/repo.update; fi +if [[ -n $(ls /boot/config/plugins/repo.update*.plg 2>/dev/null) ]]; then rm /boot/config/plugins/repo.update*.plg; fi + +if [[ -e /tmp/community.applications/tempFiles/templates.json ]]; then rm /tmp/community.applications/tempFiles/templates.json; fi + + + + + +https://raw.github.com/&github;/master/archive/&name;-&version;.txz +&md5; + + + + + +echo "Creating Directories" +mkdir -p /var/lib/docker/unraid/templates-community-apps +mkdir -p /var/lib/docker/unraid/community.applications.datastore +mkdir -p /tmp/community.applications/tempFiles +mkdir -p /boot/config/plugins/community.applications + +echo "" +echo "----------------------------------------------------" +echo " &name; has been installed." +echo " Copyright 2015-2017, Andrew Zawadzki" +echo " Version: &version;" +echo "----------------------------------------------------" +echo "" + + + + + +]]> + + + + + +removepkg &name;-&version; +rm -rf &plugdir; +rm -rf /boot/config/plugins/&name; +rm -rf /var/lib/docker/unraid/templates-community + + + diff --git a/plugins/community.applications.plg.save b/plugins/community.applications.plg.save new file mode 100644 index 00000000..ec8f097a --- /dev/null +++ b/plugins/community.applications.plg.save @@ -0,0 +1,645 @@ + + + + + + + + + +]> + + + + +###2016.11.05### +- Infrastructure changes to ultimately allow separate module installation / deinstallation + +###2016.10.30### +- Fixed: Dynamix Bleeding Edge 2016.10.29c compatibility + +###2016.10.26### +- Allow appdata backup source to be any folder on system +- Updated routines to handle potential incompatibility with PHP and unRaid's generated comments + +###2016.10.12### +- Handle edge case template creation by dockerMan + +###2016.09.28### +- Force redirection of additional backup scripts output console + +###2016.09.25a### +- Speed up appfeed download + +###2016.09.25### +- Added: Selectable delay in days before autoupdating a plugin +- Added: Backup of old .plg files prior to backup to support edge-case rollbacks if needed +- Updated: Manual + +###2016.09.23### +- NOTE: All auto update settings will be reset back to defaults with this update. IE: Only CA and FCP will autoupdate +- Fixed: CA under certain circumstances would show as not autoupdating in settings when in fact it would +- Fixed: Under very specific circumstances, some plugins set to not autoupdate could in fact auto update +- Fixed: PhAzE plugins would not show up as installed if they were + +###2016.09.21### +- Extra security tests on auto updates +- Implement autoupdate kill switch + +###2016.09.17### +- Compatibility fix for dynamix.bleeding.edge.plg + +###2016.09.15### +- Fixed minor compatibilty issues with 6.2 Final +- Changed: Only log maximum 10 rsync errors in backup module +- Fixed: disallow faster rsync option if days to keep backup sets is disabled (or set to 0) +- Fixed: backup to flashdrive setting (entry could have been possibly corrupted under 2016.09.03) +- Added: Script to delete old dated backups in addition to ALL backups and error backups only +- Changed: Update Apps now called Legacy Mode. Selecting again goes back to appFeed mode +- Removed: Private Repositories via a GitHub repo. +- Added: Selectable notifications on autoupdates of plugins +- Added: XML Branch support while in Legacy Mode +- Fixed: Display aberrations while in legacy mode if some repositories didn't download +- Added: Legacy mode will now display any XML's which failed to parse + +###2016.09.07### +- Fixed VM XML's not backing up under certain circumstances +- Do not delete XML backups if source is no longer available +- Added Dynamic adjustment of templates based upon user input + +###2016.09.06### +- Fixed Backup/Restore settings module not working +- Added Selectable display for Random App Of Day + +###2016.09.04### +- Under certain cirumstances, app of the day could crash CA +- Download compressed version of appfeed + +###2016.09.03### +- Added in VM XML backups +- Major rewrite of display engine (faster, far smaller) +- Fix app of day to not possibly display moderated apps if app feed happened to change during the day +- Fix various buttons not properly getting disabled when forcing update under certain circumstances +- Fixed search on author where apps would always display as being installed +- Far too many coding changes to list + +###2016.08.13### +- Maintenance Update +- Added Apps of the day +- Fixed display abnormalities in Table Mode under certain conditions / templates +- Fixed displayed borders on popups +- Updated manual +- Removed extraneous code +- Fixed base image display when in legacy mode + +###2016.08.07### +- Added in ability to flag / pin apps for later viewing + +###2016.08.03### +- Fixed: Restore appdata when using user shares as a destination + +###2016.07.31### +- Support user shares as source and destination for appdata backup on 6.2-rc3+ + +###2016.07.23### +- Major revamp to backup/restore appdata module (see thread for details) + +###2016.07.16### +- Better logging for CA Backup + +###2016.07.08### +- Bug fix on dockerHub searches vs recommended applications + +###2016.07.04### +- Fixed cleanup appdata if an installed app doesn't have any volume mappings + +###2016.07.01### +- Support Separate Destinations for Flash Drive Backup + +###2016.06.29### +- Backup Disk Assignments and super.dat (renamed) as part of USB backup + +###2016.06.26### +- Backup options not displaying the set value for save log to flash +- Fix improper displaying of source and destination on popup (restore) +- Suppress errors displayed when selecting a UD mount for backup purposes +- Added in backup of flash drive (sans super.dat) to docker appdata prior to backing up to array + +###2016.06.25k### +- Add directions for backups for UD mounted shares + +###2016.06.13### +- Fix typos +- Prevent appdata cleanup from deleting parent folders (due to severely misconfigured previous template) +- Add support and project links back to table mode (not sure how / when they got removed) + +###2016.06.12### +- Miscellaneous enhancements and fixes + +###2016.06.11### +- Added: New module to delete orphaned appdata folders +- Better appdata determination if running unRaid 6.2+ + +###2016.06.05### +- Fixed: Prevent invalid Support and Project URLs from displaying + +###2016.06.02### +- Add in option to speed up backups when using dated backups with automatic deletions + +###2016.05.30### +- Add in automatic deletion of old dated backup sets + +###2016.05.12### +- Add in dated backup of appdata + +###2016.05.08### +- Fixed some bugs with AutoUpdate displays + +###2016.05.05### +- Enhanced: Backup - better logging into syslog +- Added: Configurable logging options +- Fixed: Suppress errors if plugins don't have a readme + +###2016.05.01### +- Added Configurable notifications on apppdata backup +- Added Exluded folders to appdata backup +- Updated: CA manual +- Added rsync errors now logged +- Lowered memory footprint of program + +###2016.04.30### +- Better warnings on overwrites +- Added ability to set backup destinations to a subfolder +- Enhanced script selection / share selection +- Added ability to skip docker.img file on backups +- Fix autoupdate of applications would not always only display installed plugins + +###2016.04.28### +- Added: Support for manual / scheduled backups of appData + +###2016.04.17### +- Added: Ability to Auto Update Selected Plugins + +###2016.04.16### +- Fix: PHP exception when only a single Config entry is present +- Fix: Date application updated when in Legacy mode + +###2016.04.10### +- Enhanced: Further security improvements +- Enhanced: cAdvisor template is now 6.2 compliant +- Fix: Suppress error if no docker applications running when in resource monitor +- Added: Ability to install updates for docker applications +- Enhanced: Better determination of appFeed failure +- Added: Confirmation on Update Applications button +- Updated: Manual, Credits + +###2016.04.01### +- Fix: Under certain circumstances, data structures could get corrupted +- Enhanced: Further security enhancements + +###2016.03.31### +- Security Fix: Prevent arbitrary execution of code from malicious templates +- Fix: Sanitize all Overview out of specification +- Fix: Resource monitor not recognizing cAdvisor installed if name changed +- Fix: Renamed apps will not display usage stats in popup +- Added: option to show change log for CA when updating itself +- Changed: default Host port for cAdvisor to 9243 (something oddball that probably won't conflict with anything else) +- Added: if cAdvisor installed, but not running, abilty to start it within CA +- Updated: Manual + +###2016.03.28### +- Coding optimizations +- Fixed: Don't display a support link if no support link available +- Fixed: Add web-page link if repository authors have a web page +- Added: Ability to install updates for plugins +- Fixed: Resource Monitor not displaying icons for customized appFeed apps +- Fixed: Determination of appdata is now case-insensitive when looking for /config +- Fixed: dockerHub conversions now follow settings for new tab or same tab +- Changed: Default value for new tab or same tab is now same tab + +###2016.03.26### +- Fixed: Customized apps (based upon a default one in appfeed) were being tagged as incompatible +- Enhanced: Friendly reminder if CA is out of date + +###2016.03.24### +- Fixed: Installing previous apps on unRaid 6.2 +- Enhanced: Now fully generates v6.2 compliant xml files for dockerMan + +###2016.03.20### +- Fixed: readmore on searches (regression error) +- Fixed: private repositories (dockerHub searches) were being saved into wrong folder (regression error) +- Enhanced: Update Applications (or reversion to legacy mode) will not fail if a single repository fails to download +- Enhanced: Now include cAdvisor XML template so as to not rely upon smdion's repository +- Enhanced: Popup descriptions now include links to go to cAdvisor's page for running docker applications +- Enhanced: Templates passed through to dockerMan are now Moderated to allow CA to fix any errors, typos, etc in the author's template +- Enhanced: Major overhaul of the XML template generation +- Enhanced: Continuing code cleanup + +###2016.03.13### +- Properly regress to legacy mode in case of improperly formed appFeed +- Overhaul of the javascript + +###2016.03.12### +- Remove option to relocate Users menu (and relocate Apps Tab) Use webUI's display settings instead +- Remove option to set appdata share. CA now always prompts to delete appdata if it sees a /config container path +- Resource Monitor supports appdata's stored anywhere on your system (and within multiple folders) +- Fixed: Minor display aberration introduced by unRaid 6.2 beta 18 +- Fixed: If a calculation of appdata size was in progress you could not stop the array + +###2016.03.10### +- Further enhanced Resource Monitor + +###2016.03.06### +- Fixed: Private Repositories now updated every session +- Added: Resource Monitor for Docker Applications + +###2016.03.04### +- Added: Running docker applications will now dynamically display CPU and memory utilization statistics +- Various other fixes / enhancements + +###2016.02.20### +- Fixed: Under certain circumstances, the domain URL listed in a plugin might not be what the author actually specified (eg: raw.github.com vs raw.githubusercontent.com) causing some plugins to not display in the previously installed section + +###2016.02.19### +- Hot fix for special characters contained within templates + +###2016.02.18### +- Added: Support Licence (and its mispelling of License) in templates +- Fixed: Under certain circumstances, Reinstall button could show up instead of Install + +###2016.02.14### +- Code Cleanup +- Don't display dockerHub stars if not starred +- Hide search dockerHub if in previous / installed apps +- Fix error in settings if temp directory didn't exist + +###2016.02.10### +- Suppress stars.sh error message + +###2016.02.08### +- Fixed: Issue with going from dockerHub searches to installed / previously installed +- Fixed: Disallow dockerHub searches if docker not enabled +- Fixed: Disallow adding a previously installed docker app if docker not enabled +- Removed: Legacy Code +- Removed: dockerHub guess at Icons (api broken) +- Fixed: Suppress an error message due to a bad template +- Fixed: Remove some extra temp files once not needed anymore + +###2016.02.06### +- Fixed: display abnormality with Firefox +- Enhanced: More intelligent determination of d/l counts +- Enhanced: Rearrange display icons +- Enhanced: Table Mode +- Added: Ability to display installed apps within available lists + +###2016.02.04### +- Fix issue with duplicate plugin names + +###2016.02.03### +- Suppress docker error messages if docker not running +- Full information on an app now displays total downloads +- Add sort by downloads + +###2016.02.01### +- Going forward, unRaid version 6.1+ compatible only +- Fixed: Applications with 2 identical names could disappear from the lists +- Added: Uninstall any application within CA +- Added: Optional deleting of an application's appdata - see manual for details +- Added: Favourite Repositories +- Fixed: Moderator Comments Now only download once per session +- Removed: Local server caching of icons (made no sense to me) + +###2016.01.30### +- Added: Separate Installed Apps from categories +- Added: Separate Installed Apps from previously installed +- Added: Incorporate Plugins to installed / previously installed +- Updated: Manual + +###2016.01.28### +- Added: Ability to manage previously installed docker apps (my* templates) + +###2016.01.24### +- Fix: Under certain circumstances, blank templates would appear + +###2016.01.16### +- Fix: Under certain circumstances, updated moderator comments were not being downloaded +- Fix: Under certain circumstances, errors would appear on the popup descriptions + +###2016.01.13### +- Fix: Suppress extraneous message on local console during installation + +###2016.01.10b### +- Change: Appfeed now only downloaded if it has changed + +###2016.01.10### +- Add: Option to not redownload appfeed if reloading apps within a certain time period +- Fix: Alternate icon wasn't displaying properly if template's icon was unavailable +- Updated: Help / Manual + +###2016.01.02### +- Fix: Prevent malformed templates from displaying +- Fix: All private containers were being tagged as being incompatible +- Change AppStore to Apps + +###2015.12.18### +- Add support for enforcement of application OS requirements (see help thread) + +###2015.12.12a### +- Selectable add/edit/settings windows in new tab or not + +###2015.12.12### +- Fix: Minor Icon Issues +- Fix: Plugin changelogs now same format as within a .plg file +- Fix: Not all plugins would properly go to the settings page +- Fix: Plugins not sorting by Author name +- Update: Help / Manual + +###2015.12.08### +- Minor Bug Fixes +- Settings Button for already install plugins will take you to the plugin settings + +###2015.12.06a### +- Disable Update Applications button if an update is in progress NOTE: There is normally zero reason to hit this button anyways +- Fix: Allow user selectable positioning of the AppStore. (Either on the main menu, within settings, or on main menu and move Users to settings) + +###2015.12.06### +THIS IS A REQUIRED UPDATE + +- Relocate plugin from docker tab to its own tab (AppStore) +- Now able to display and install available plugins +- Docker no longer required to be enabled to browse applications + +###2015.12.05### +- Fixed: System wouldn't let you add any application if a private repository was present + +###2015.10.10### +- Suppress commands executed with /bin/sh appearing on local monitor + +###2015.09.29### +- Fixed memory leak with application feed + +###2015.09.20### +- Add in super categories for beta and private (selectable from settings) +- More tweaks to docker conversion engine +- Sanitize the input on searches + relocate temporary files to ram +- various other fixes and tweaks + +###2015.09.15### +- Remove code for unimplemented features +- Disallow installing dockerHub result if a recommended application uses the same repository +- Fix: *.xml not found was appearing on local terminal if no private repositories were found + +###2015.09.12### +- Complete rewrite of dockerHub conversion code, adding more exceptions +- Fix: Clearing search terms no longer displays all containers +- Added in support for moderator comments on a container +- Added in ability to blacklist specific containers + +###2015.09.01### +- Implement change required due to dockerHub changing website again (used in dockerHub search mode) +- Add suggested searches for dockerHub +- Numerous under the hood improvements + +###2015.08.24### +- Handle new restrictions introduced in RC6 + +###2015.08.23### +- Suppress some spurious status messages on unRaid's attached monitor +- Expanded manual +- Display dockerHub star ratings for ALL templates + +###2015.08.20### +- Better search results for icons on dockerHub +- Search for other containers from author (template mode) +- Resolved issue with spaces in search parameters +- Internal reorganization + +###2015.08.15### +- Added in BaseOS display when not in appFeed mode +- Added in Full GUI for searching and converting non-unRaid containers. (See support thread for details) +- Miscellaneous fixes + +###2015.08.12### +- Hot Fix for 6.1RC-3 + +###2015.08.09### +- Hot fix for templates with duplicate tags +- Pop up free in appfeed mode + +###2015.08.02### +- Handle blank descriptions, categories, overviews in appFeed mode +- Fix not able to show changelog on application names containing spaces +- Integrate searching (and converting) from dockerHub + +###2015.07.26a### +- Hot fix for 6.1 RC-2 + +###2015.07.25c### +- Fixed Internet Explorer crashing +- Added Icon Details view mode + +###2015.07.23### +- Unified UI between icon and table mode +- Switch between icon and table mode on the fly +- Faster sorting in icon mode +- Add sort by date updated + +###Note: you must allow your browser to display popups from your server when in appFeed mode### + +###2015.07.20### +- Code unified between tables and icons +- Added pop up descriptions to table mode, hover descriptions to icon mode +- Fix intermittent bug where a blank template could appear + +###2015.07.19### +- 6.1rc-1 Broke Community Applications - Fixed + +###2015.07.18### +- Coding Improvements +- Revamp Icon Mode Descriptions +- Add support for Project Home Page links + +###2015.07.16### +- Significantly reduce memory footprint +- Allow private repositories to be used in conjunction with application feed +- Force Update in application feed mode will temporarily revert to template mode +- Failure to download application feed will revert system to template mode + +###2015.07.15### +- Added option to automatically update the application list when entering Docker tab +- Added in support for Kode's real-time application feed update +- Remove background table lines in icon mode +- Removed option to automatically fill out template paths + +###2015.07.08### +- Clicking the repository will now open the announcement thread in a new tab + +###2015.07.04### +- Added in option to display small icons in icon mode +- Optionally overwrite ALL host paths when in experimental overwrite host path mode + +###2015.07.02### +- Fixed display abberation in table mode when searching for application with change log +###2015.07.01### +- Added an experimental option to automatically fill in host paths. See support thread for details. + +###2015.06.21### +- Table Mode: Repository was not displaying (introduced in 2015.06.14) (my bad - never noticed) + +###2015.06.18### +- Changed to a more intuitive Apply / Done buttons in settings + +###2016.06.17### +- Fixed table header sometimes displaying in Icon Mode +- Made settings default values consistent between modules +- Added help text for Icon Mode +- Icon mode now default + +###2015.06.15### +- Expanded descriptions in Icon mode +- Fixed applications in beta repositories not being flagged correctly + +###2015.06.14a### +- Fixed cursor over information icon and application icon (Icon mode) +- Fixed applications not displaying description if a space was in the name (Icon mode) + +###2015.06.14### +- Added Icon view mode (more mobile friendly!) + +###2015.06.11### +- Coding optimizations +- Add help text + +###2015.06.08### +- Added support for new / updated containers +- Expanded settings section + +###2015.06.06### +- Added a settings section + +###2015.06.03a### +- Optional local caching of application icons + +###2015.06.03### +- Initial display is now blank (faster) +- Going from subcategory to all categories no longer displays all categories + +###2015.06.02### +- Added support for Changes tag +- Added non-intrusive reminder to update applications after 14 days + +###2015.05.31### +- Renamed DNS Servers to be DNS Client / Servers + +###2015.05.30### +- Miscellaneous download fixes + +###2015.05.28### +- Initial Release + + + + + + +]]> + + + + + +# Remove old 'source' files +rm -f $(ls /boot/config/plugins/&name;/&name;*.txz 2>/dev/null|grep -v '&version;') +if [[ -d /boot/config/plugins/repo.update ]]; then rm -rf /boot/config/plugins/repo.update; fi +if [[ -d /usr/local/emhttp/plugins/repo.update ]]; then rm -rf /usr/local/emhttp/plugins/repo.update; fi +if [[ -n $(ls /boot/config/plugins/repo.update*.plg 2>/dev/null) ]]; then rm /boot/config/plugins/repo.update*.plg; fi + +if [[ -e /tmp/community.applications/tempFiles/templates.json ]]; then rm /tmp/community.applications/tempFiles/templates.json; fi + + + + + +https://raw.github.com/&github;/master/archive/&name;-&version;.txz +&md5; + + + + + +echo "Creating Directories" +mkdir -p /var/lib/docker/unraid/templates-community-apps +mkdir -p /var/lib/docker/unraid/community.applications.datastore +mkdir -p /tmp/community.applications/tempFiles +mkdir -p /boot/config/plugins/community.applications + +echo "" +echo "----------------------------------------------------" +echo " &name; has been installed." +echo " Copyright 2015-2016, Andrew Zawadzki" +echo " Version: &version;" +echo "----------------------------------------------------" +echo "" + + + + + + +/usr/local/emhttp/plugins/community.applications/scripts/removeCron.php +removepkg &name;-&version; +rm -rf &plugdir; +rm -rf /boot/config/plugins/&name; +rm -rf /var/lib/docker/unraid/templates-community + + + diff --git a/source/community.applications/pkg_build.sh b/source/community.applications/pkg_build.sh new file mode 100644 index 00000000..2dc85fc1 --- /dev/null +++ b/source/community.applications/pkg_build.sh @@ -0,0 +1,16 @@ +#!/bin/bash +DIR="$(dirname "$(readlink -f ${BASH_SOURCE[0]})")" +tmpdir=/tmp/tmp.$(( $RANDOM * 19318203981230 + 40 )) +plugin=$(basename ${DIR}) +archive="$(dirname $(dirname ${DIR}))/archive" +version=$(date +"%Y.%m.%d")$1 + +mkdir -p $tmpdir + +cp --parents -f $(find . -type f ! \( -iname "pkg_build.sh" -o -iname "sftp-config.json" \) ) $tmpdir/ +cd $tmpdir +makepkg -l y -c y ${archive}/${plugin}-${version}.txz +rm -rf $tmpdir +echo "MD5:" +md5sum ${archive}/${plugin}-${version}.txz + diff --git a/source/community.applications/usr/local/emhttp/plugins/community.applications/Apps.page b/source/community.applications/usr/local/emhttp/plugins/community.applications/Apps.page new file mode 100644 index 00000000..56599c65 --- /dev/null +++ b/source/community.applications/usr/local/emhttp/plugins/community.applications/Apps.page @@ -0,0 +1,4 @@ +Menu="Tasks:80" +Name="Apps" +Type="xmenu" +Tabs="true" diff --git a/source/community.applications/usr/local/emhttp/plugins/community.applications/CA.page b/source/community.applications/usr/local/emhttp/plugins/community.applications/CA.page new file mode 100644 index 00000000..a347f2ba --- /dev/null +++ b/source/community.applications/usr/local/emhttp/plugins/community.applications/CA.page @@ -0,0 +1,4 @@ +Menu="Settings" +Title="Community Applications" +Icon="CA.png" +Type="menu" diff --git a/source/community.applications/usr/local/emhttp/plugins/community.applications/CommunityApps.page b/source/community.applications/usr/local/emhttp/plugins/community.applications/CommunityApps.page new file mode 100644 index 00000000..a54764d9 --- /dev/null +++ b/source/community.applications/usr/local/emhttp/plugins/community.applications/CommunityApps.page @@ -0,0 +1,1459 @@ +Menu="Apps" +Icon="community.applications.png" +Title="Community Applications" +--- +=") ? "true" : "false"; +$unRaid64 = (version_compare($vars['version'],"6.4.0-rc0",">=")) ? "true" : "false"; +$unRaid635 = (version_compare($vars['version'],"6.3.5",">=")) ? "true" : "false"; + +$tabMode = "_self"; +$line_color = $display['theme']=='black' ? '#202020' : '#E8E8E8'; + +$timeNew = str_replace("-","",$cfg['timeNew']); +$categoryTitle = "Recommended Applications"; +$viewMode = $cfg['viewMode']; +$execPath = "/plugins/$plugin/scripts"; + +$dockerRunning = (is_dir("/var/lib/docker/containers")) ? "true" : "false"; + +$template = json_decode(file_get_contents($communityPaths['defaultSkin']),true); + +$pluginInstallPending = @file_get_contents($communityPaths['PluginInstallPending']); +@unlink($communityPaths['PluginInstallPending']); + +?> + + + + + + + +
+ + +CA Manual     Statistics     Credits +
+> For help with this plugin, click here (a new tab will open with the help file) HELP
+> - This chooses which "section" to display (Available Apps, Installed Apps, Previously Installed Apps, Pinned Apps, additional CA Modules
+> - This chooses how to display the results
+> - This selects a category of apps to display
+> - When available, this selects a subcategory of apps to display
+> - These icons respectively will Install, Edit, or Update an application
+> - Clicking this icon will take you to an application's GUI
+> Hovering over an application's icon (or clicking it) will display more information about the application
+>
For support for this plugin, visit here: http://lime-technology.com/forum/index.php?topic=40262.0
+>
+ + + + + +Current Section: Available Apps +Total Found:   Results/page: +
+ + +
An update to Community Applications is Available. Click HERE to install the update
+ + + + + +
+ + + + + +
Docker FAQ

+
Community Applications Version:
+ + + +
+
+ +
+ + + + + + + + + + + + +     + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + +
+ diff --git a/source/community.applications/usr/local/emhttp/plugins/community.applications/PluginSettings.page b/source/community.applications/usr/local/emhttp/plugins/community.applications/PluginSettings.page new file mode 100644 index 00000000..5f79c89d --- /dev/null +++ b/source/community.applications/usr/local/emhttp/plugins/community.applications/PluginSettings.page @@ -0,0 +1,130 @@ +Menu="CA" +Title="General Settings" +Icon="settings.png" +--- +/dev/null 2>&1 &" : "2>/dev/null"), $out, $exit_code ); + return ($exit_code === 0 ) ? implode("\n", $out) : false; +} + +$vars = parse_ini_file("/var/local/emhttp/var.ini"); +$toolTipsterAllowed = version_compare($vars['version'],"6.3.3",">=") ? "true" : "false"; + +$plugin = "community.applications"; +$cfg = parse_plugin_cfg($plugin); + +# Get the available repositories and setup the display for favourites + +if ( ! is_dir("/tmp/community.applications/tempFiles") ) { + exec('mkdir -p "/tmp/community.applications/tempFiles"'); +} + +$Repositories = "/tmp/community.applications/tempFiles/Repositories.json"; +download_url("https://raw.githubusercontent.com/Squidly271/Community-Applications-Moderators/master/Repositories.json",$Repositories); +$Repos = json_decode(@file_get_contents($Repositories),true); + +if ( ! $Repos ) { + $Repos = array(); +} + +$repoName = array(); + +foreach ($Repos as $Repo) { + $repoName[] = $Repo['name']; +} +natcasesort($repoName); + +$displayOptions = mk_option($cfg['favourite'], "None", "None (default)"); + +foreach ($repoName as $display) { + $optionName = str_replace("'","*",$display); + $displayOptions .= mk_option($cfg['favourite'], $optionName, $display); +} + +$unRaid64 = (version_compare($vars['version'],"6.4.0-rc0",">=")) || (is_file("/usr/local/emhttp/plugins/dynamix/styles/dynamix-gray.css")) ? "true" : "false"; +?> + +
+ + +> For help with this plugin, click here (a new tab will open with the help file) HELP + +Time to display applications as new / updated: +: + +> This setting determines how long an application will be displayed as "new" + +Hover Time delay (miliseconds): +: + +> This setting determines how long you have to hover over any element prior to the pop up appearing + +Favourite Repository: +: + +> Set this option to your favourite repository, so that it's applications will display first + +Show already installed apps within available apps: +: + +> This setting determines if already installed applications will also appear when displaying available apps + +Hide Deprecated Applications: +: + +> This setting hides deprecated applications from the list of available apps. Deprecated apps will still however display within the installed and previous apps sections. + +Hide Incompatible Applications: +: + +> This setting will hide applications that are listed as being incompatible with your version of unRaid + +Display Random App Of The Day: +: + +> This setting chooses whether to display or not a random "app of the day" + +Docker Hub Searching + +Enable additional search results from dockerHub? +: + +> This setting enables CA to retrieve additional search results from dockerHub. Note that docker must be enabled for this to be operational + + +  +: + + +
For support for this plugin, visit here: HERE
+ +
+
+ + diff --git a/source/community.applications/usr/local/emhttp/plugins/community.applications/README.md b/source/community.applications/usr/local/emhttp/plugins/community.applications/README.md new file mode 100644 index 00000000..4da02dc6 --- /dev/null +++ b/source/community.applications/usr/local/emhttp/plugins/community.applications/README.md @@ -0,0 +1,3 @@ +####Community Applications#### +A Plugin to keep your docker application lists up to date and easily sort them by category and add them to your running containers. unRaid v6.1+ only. + diff --git a/source/community.applications/usr/local/emhttp/plugins/community.applications/caHelp.page b/source/community.applications/usr/local/emhttp/plugins/community.applications/caHelp.page new file mode 100644 index 00000000..5770f32f --- /dev/null +++ b/source/community.applications/usr/local/emhttp/plugins/community.applications/caHelp.page @@ -0,0 +1,22 @@ +Menu="CA" +Title="Manual" +Icon="help.png" +--- + + + diff --git a/source/community.applications/usr/local/emhttp/plugins/community.applications/default.cfg b/source/community.applications/usr/local/emhttp/plugins/community.applications/default.cfg new file mode 100644 index 00000000..29002091 --- /dev/null +++ b/source/community.applications/usr/local/emhttp/plugins/community.applications/default.cfg @@ -0,0 +1,16 @@ +timeNew="-3 Months" +viewMode="detail" +favourite="None" +iconSize="96" +maxColumn="5" +superCategory="true" +separateInstalled="true" +newWindow="_self" +hideIncompatible="true" +dockerSearch="no" +appOfTheDay="yes" +maxPerPage="25" +hideDeprecated="true" +tooltipster="true" +hoverTime="1000" + diff --git a/source/community.applications/usr/local/emhttp/plugins/community.applications/event/stopping_svcs b/source/community.applications/usr/local/emhttp/plugins/community.applications/event/stopping_svcs new file mode 100644 index 00000000..060aef8a --- /dev/null +++ b/source/community.applications/usr/local/emhttp/plugins/community.applications/event/stopping_svcs @@ -0,0 +1,9 @@ +#!/bin/bash +if [[ -e /tmp/community.applications/tempFiles/appdata/inprogress ]] + then + logger "Community Applications Calculations of Appdata in progress" + PID=`cat /tmp/community.applications/tempFiles/appdata/inprogress` + logger "Terminating $PID" + kill $PID +fi + diff --git a/source/community.applications/usr/local/emhttp/plugins/community.applications/icons/CA.png b/source/community.applications/usr/local/emhttp/plugins/community.applications/icons/CA.png new file mode 100644 index 00000000..3218e144 Binary files /dev/null and b/source/community.applications/usr/local/emhttp/plugins/community.applications/icons/CA.png differ diff --git a/source/community.applications/usr/local/emhttp/plugins/community.applications/icons/communityapplications.png b/source/community.applications/usr/local/emhttp/plugins/community.applications/icons/communityapplications.png new file mode 100644 index 00000000..3218e144 Binary files /dev/null and b/source/community.applications/usr/local/emhttp/plugins/community.applications/icons/communityapplications.png differ diff --git a/source/community.applications/usr/local/emhttp/plugins/community.applications/images/CA.png b/source/community.applications/usr/local/emhttp/plugins/community.applications/images/CA.png new file mode 100644 index 00000000..093ea56f Binary files /dev/null and b/source/community.applications/usr/local/emhttp/plugins/community.applications/images/CA.png differ diff --git a/source/community.applications/usr/local/emhttp/plugins/community.applications/images/CategoryIcon.png b/source/community.applications/usr/local/emhttp/plugins/community.applications/images/CategoryIcon.png new file mode 100644 index 00000000..4aae279a Binary files /dev/null and b/source/community.applications/usr/local/emhttp/plugins/community.applications/images/CategoryIcon.png differ diff --git a/source/community.applications/usr/local/emhttp/plugins/community.applications/images/CategoryIconDisabled.png b/source/community.applications/usr/local/emhttp/plugins/community.applications/images/CategoryIconDisabled.png new file mode 100644 index 00000000..c0d2371c Binary files /dev/null and b/source/community.applications/usr/local/emhttp/plugins/community.applications/images/CategoryIconDisabled.png differ diff --git a/source/community.applications/usr/local/emhttp/plugins/community.applications/images/SectionIcon.png b/source/community.applications/usr/local/emhttp/plugins/community.applications/images/SectionIcon.png new file mode 100644 index 00000000..a278a099 Binary files /dev/null and b/source/community.applications/usr/local/emhttp/plugins/community.applications/images/SectionIcon.png differ diff --git a/source/community.applications/usr/local/emhttp/plugins/community.applications/images/SectionIconDisabled.png b/source/community.applications/usr/local/emhttp/plugins/community.applications/images/SectionIconDisabled.png new file mode 100644 index 00000000..6fd13d58 Binary files /dev/null and b/source/community.applications/usr/local/emhttp/plugins/community.applications/images/SectionIconDisabled.png differ diff --git a/source/community.applications/usr/local/emhttp/plugins/community.applications/images/SubCategoryIcon.png b/source/community.applications/usr/local/emhttp/plugins/community.applications/images/SubCategoryIcon.png new file mode 100644 index 00000000..2f307114 Binary files /dev/null and b/source/community.applications/usr/local/emhttp/plugins/community.applications/images/SubCategoryIcon.png differ diff --git a/source/community.applications/usr/local/emhttp/plugins/community.applications/images/SubCategoryIconDisabled.png b/source/community.applications/usr/local/emhttp/plugins/community.applications/images/SubCategoryIconDisabled.png new file mode 100644 index 00000000..26258fed Binary files /dev/null and b/source/community.applications/usr/local/emhttp/plugins/community.applications/images/SubCategoryIconDisabled.png differ diff --git a/source/community.applications/usr/local/emhttp/plugins/community.applications/images/ViewIcon.png b/source/community.applications/usr/local/emhttp/plugins/community.applications/images/ViewIcon.png new file mode 100644 index 00000000..4e838165 Binary files /dev/null and b/source/community.applications/usr/local/emhttp/plugins/community.applications/images/ViewIcon.png differ diff --git a/source/community.applications/usr/local/emhttp/plugins/community.applications/images/ViewIconDisabled.png b/source/community.applications/usr/local/emhttp/plugins/community.applications/images/ViewIconDisabled.png new file mode 100644 index 00000000..819bd3c2 Binary files /dev/null and b/source/community.applications/usr/local/emhttp/plugins/community.applications/images/ViewIconDisabled.png differ diff --git a/source/community.applications/usr/local/emhttp/plugins/community.applications/images/WebPage.png b/source/community.applications/usr/local/emhttp/plugins/community.applications/images/WebPage.png new file mode 100644 index 00000000..ad5bebf3 Binary files /dev/null and b/source/community.applications/usr/local/emhttp/plugins/community.applications/images/WebPage.png differ diff --git a/source/community.applications/usr/local/emhttp/plugins/community.applications/images/community.applications.png b/source/community.applications/usr/local/emhttp/plugins/community.applications/images/community.applications.png new file mode 100644 index 00000000..093ea56f Binary files /dev/null and b/source/community.applications/usr/local/emhttp/plugins/community.applications/images/community.applications.png differ diff --git a/source/community.applications/usr/local/emhttp/plugins/community.applications/images/docker.png b/source/community.applications/usr/local/emhttp/plugins/community.applications/images/docker.png new file mode 100644 index 00000000..5d9ef4d3 Binary files /dev/null and b/source/community.applications/usr/local/emhttp/plugins/community.applications/images/docker.png differ diff --git a/source/community.applications/usr/local/emhttp/plugins/community.applications/images/edit.png b/source/community.applications/usr/local/emhttp/plugins/community.applications/images/edit.png new file mode 100644 index 00000000..186c691d Binary files /dev/null and b/source/community.applications/usr/local/emhttp/plugins/community.applications/images/edit.png differ diff --git a/source/community.applications/usr/local/emhttp/plugins/community.applications/images/greenButton.png b/source/community.applications/usr/local/emhttp/plugins/community.applications/images/greenButton.png new file mode 100644 index 00000000..fa797afe Binary files /dev/null and b/source/community.applications/usr/local/emhttp/plugins/community.applications/images/greenButton.png differ diff --git a/source/community.applications/usr/local/emhttp/plugins/community.applications/images/help.png b/source/community.applications/usr/local/emhttp/plugins/community.applications/images/help.png new file mode 100644 index 00000000..42a8f7c1 Binary files /dev/null and b/source/community.applications/usr/local/emhttp/plugins/community.applications/images/help.png differ diff --git a/source/community.applications/usr/local/emhttp/plugins/community.applications/images/install.png b/source/community.applications/usr/local/emhttp/plugins/community.applications/images/install.png new file mode 100644 index 00000000..8cd09cb7 Binary files /dev/null and b/source/community.applications/usr/local/emhttp/plugins/community.applications/images/install.png differ diff --git a/source/community.applications/usr/local/emhttp/plugins/community.applications/images/question.png b/source/community.applications/usr/local/emhttp/plugins/community.applications/images/question.png new file mode 100644 index 00000000..f3405a01 Binary files /dev/null and b/source/community.applications/usr/local/emhttp/plugins/community.applications/images/question.png differ diff --git a/source/community.applications/usr/local/emhttp/plugins/community.applications/images/red-star.png b/source/community.applications/usr/local/emhttp/plugins/community.applications/images/red-star.png new file mode 100644 index 00000000..19bf378f Binary files /dev/null and b/source/community.applications/usr/local/emhttp/plugins/community.applications/images/red-star.png differ diff --git a/source/community.applications/usr/local/emhttp/plugins/community.applications/images/redButton.png b/source/community.applications/usr/local/emhttp/plugins/community.applications/images/redButton.png new file mode 100644 index 00000000..fe275aab Binary files /dev/null and b/source/community.applications/usr/local/emhttp/plugins/community.applications/images/redButton.png differ diff --git a/source/community.applications/usr/local/emhttp/plugins/community.applications/images/settings.png b/source/community.applications/usr/local/emhttp/plugins/community.applications/images/settings.png new file mode 100644 index 00000000..7fc95fa0 Binary files /dev/null and b/source/community.applications/usr/local/emhttp/plugins/community.applications/images/settings.png differ diff --git a/source/community.applications/usr/local/emhttp/plugins/community.applications/images/spinner2.gif b/source/community.applications/usr/local/emhttp/plugins/community.applications/images/spinner2.gif new file mode 100644 index 00000000..f0ac8abd Binary files /dev/null and b/source/community.applications/usr/local/emhttp/plugins/community.applications/images/spinner2.gif differ diff --git a/source/community.applications/usr/local/emhttp/plugins/community.applications/images/star.png b/source/community.applications/usr/local/emhttp/plugins/community.applications/images/star.png new file mode 100644 index 00000000..00fc205e Binary files /dev/null and b/source/community.applications/usr/local/emhttp/plugins/community.applications/images/star.png differ diff --git a/source/community.applications/usr/local/emhttp/plugins/community.applications/images/up.png b/source/community.applications/usr/local/emhttp/plugins/community.applications/images/up.png new file mode 100644 index 00000000..e32fb66f Binary files /dev/null and b/source/community.applications/usr/local/emhttp/plugins/community.applications/images/up.png differ diff --git a/source/community.applications/usr/local/emhttp/plugins/community.applications/images/update.png b/source/community.applications/usr/local/emhttp/plugins/community.applications/images/update.png new file mode 100644 index 00000000..4d6885dd Binary files /dev/null and b/source/community.applications/usr/local/emhttp/plugins/community.applications/images/update.png differ diff --git a/source/community.applications/usr/local/emhttp/plugins/community.applications/include/caCredits.php b/source/community.applications/usr/local/emhttp/plugins/community.applications/include/caCredits.php new file mode 100644 index 00000000..be5331c4 --- /dev/null +++ b/source/community.applications/usr/local/emhttp/plugins/community.applications/include/caCredits.php @@ -0,0 +1,61 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + +
Andrew ZawadzkiMain Development
bonienlAdditional Contributions
KodeApplication Feed
CHBMBAdditional Testing
gridrunnerAdditional Testing
+
+
Copyright © 2015-2017 Andrew Zawadzki
+
+
Plugin Support Thread
+ "; + getLineCount("/usr/local/emhttp/plugins/community.applications"); + $caCredits .= "
$lineCount Lines of code and counting! ($charCount characters)
"; + $caCredits = str_replace("\n","",$caCredits); +?> \ No newline at end of file diff --git a/source/community.applications/usr/local/emhttp/plugins/community.applications/include/exec.php b/source/community.applications/usr/local/emhttp/plugins/community.applications/include/exec.php new file mode 100644 index 00000000..635cc831 --- /dev/null +++ b/source/community.applications/usr/local/emhttp/plugins/community.applications/include/exec.php @@ -0,0 +1,1974 @@ +=")); +$unRaid635 = (version_compare($unRaidVersion,"6.3.5",">=")); + +if ( ! $unRaid64 ) { + $communityPaths['defaultSkin'] = $communityPaths['legacySkin']; +} +$templateSkin = readJsonFile($communityPaths['defaultSkin']); # Global Var used in helpers ( getMaxColumns() ) + +################################################################################ +# # +# Set up any default settings (when not explicitely set by the settings module # +# # +################################################################################ + +$communitySettings = parse_plugin_cfg("$plugin"); +$communitySettings['appFeed'] = "true"; # set default for deprecated setting +$communitySettings['maxPerPage'] = getPost("maxPerPage",$communitySettings['maxPerPage']); # Global POST. Used damn near everywhere +$communitySettings['iconSize'] = 96; +$communitySettings['maxColumn'] = 5; # Pointless on 6.3 Gets overridden on 6.4 anyways +$communitySettings['newWindow'] = "_self"; + +if ( $communitySettings['favourite'] != "None" ) { + $officialRepo = str_replace("*","'",$communitySettings['favourite']); + $separateOfficial = true; +} +if ( is_dir("/var/lib/docker/containers") ) { + $communitySettings['dockerRunning'] = "true"; +} else { + $communitySettings['dockerSearch'] = "no"; + unset($communitySettings['dockerRunning']); +} + +if ( $communitySettings['dockerRunning'] ) { + $info = $DockerTemplates->getAllInfo(); + $DockerClient = new DockerClient(); + $dockerRunning = $DockerClient->getDockerContainers(); +} else { + $info = array(); + $dockerRunning = array(); +} + +exec("mkdir -p ".$communityPaths['tempFiles']); +exec("mkdir -p ".$communityPaths['persistentDataStore']); + +if ( !is_dir($communityPaths['templates-community']) ) { + exec("mkdir -p ".$communityPaths['templates-community']); + @unlink($infoFile); +} + +################################################################# +# # +# Functions used to download the templates from various sources # +# # +################################################################# +function DownloadCommunityTemplates() { + global $communityPaths, $infoFile, $plugin, $communitySettings, $statistics; + + $betaComment = "The author of this template has designated it to be a beta. You may experience issues with this application"; + $moderation = readJsonFile($communityPaths['moderation']); + if ( ! is_array($moderation) ) { $moderation = array(); } + + $DockerTemplates = new DockerTemplates(); + + if (! $download = download_url($communityPaths['community-templates-url']) ) { return false; } + $Repos = json_decode($download, true); + if ( ! is_array($Repos) ) { return false; } + $statistics['repository'] = count($Repos); + + $appCount = 0; + $myTemplates = array(); + + exec("rm -rf '{$communityPaths['templates-community']}'"); + @unlink($communityPaths['updateErrors']); + + $templates = array(); + foreach ($Repos as $downloadRepo) { + $downloadURL = randomFile(); + file_put_contents($downloadURL, $downloadRepo['url']); + $friendlyName = str_replace(" ","",$downloadRepo['name']); + $friendlyName = str_replace("'","",$friendlyName); + $friendlyName = str_replace('"',"",$friendlyName); + $friendlyName = str_replace('\\',"",$friendlyName); + $friendlyName = str_replace("/","",$friendlyName); + + if ( ! $downloaded = $DockerTemplates->downloadTemplates($communityPaths['templates-community']."/templates/$friendlyName", $downloadURL) ){ + file_put_contents($communityPaths['updateErrors'],"Failed to download ".$downloadRepo['name']." ".$downloadRepo['url']."
",FILE_APPEND); + @unlink($downloadURL); + } else { + $templates = array_merge($templates,$downloaded); + unlink($downloadURL); + } + } + + @unlink($downloadURL); + $i = $appCount; + foreach ($Repos as $Repo) { + if ( ! is_array($templates[$Repo['url']]) ) { + continue; + } + foreach ($templates[$Repo['url']] as $file) { + if (is_file($file)){ + $o = readXmlFile($file); + if ( ! $o ) { + file_put_contents($communityPaths['updateErrors'],"Failed to parse $file (errors in XML file?)
",FILE_APPEND); + } + if ( ! $o['Repository'] ) { + if ( ! $o['Plugin'] ) { + $statistics['invalidXML']++; + $invalidXML[] = $o; + continue; + } else { + $statistics['totalApplications']++; + } + } + + $o['Forum'] = $Repo['forum']; + $o['RepoName'] = $Repo['name']; + $o['ID'] = $i; + $o['Displayable'] = true; + $o['Support'] = $o['Support'] ? $o['Support'] : $o['Forum']; + $o['DonateText'] = $o['DonateText'] ? $o['DonateText'] : $Repo['donatetext']; # Some people can't read the specs correctly + $o['DonateLink'] = $o['DonateLink'] ? $o['DonateLink'] : $Repo['donatelink']; + $o['DonateImg'] = $o['DonateImg'] ? $o['DonateImg'] : $Repo['donateimg']; + $o['WebPageURL'] = $Repo['web']; + $o['Logo'] = $Repo['logo']; + $o['Profile'] = $Repo['profile']; + fixSecurity($o,$o); + $o = fixTemplates($o); + if ( ! $o ) { + continue; + } + + # Overwrite any template values with the moderated values + if ( is_array($moderation[$o['Repository']]) ) { + $o = array_merge($o, $moderation[$o['Repository']]); + } + $o['Compatible'] = versionCheck($o); + + if ( $o['Beta'] == "true" ) { + $o['ModeratorComment'] .= $o['ModeratorComment'] ? "

$betaComment" : $betaComment; + } + + if ( $o['Blacklist'] ) { + $statistics['blacklist']++; + $blacklist[] = "{$o['Repo']} - {$o['Name']} - {$o['ModeratorComment']}"; + continue; + } else { + $statistics['totalApplications']++; + } + $o['Category'] = str_replace("Status:Beta","",$o['Category']); # undo changes LT made to my xml schema for no good reason + $o['Category'] = str_replace("Status:Stable","",$o['Category']); + $myTemplates[$o['ID']] = $o; + if ( is_array($o['Branch']) ) { + if ( ! $o['Branch'][0] ) { + $tmp = $o['Branch']; + unset($o['Branch']); + $o['Branch'][] = $tmp; + } + foreach($o['Branch'] as $branch) { + $i = ++$i; + $subBranch = $o; + $masterRepository = explode(":",$subBranch['Repository']); + $o['BranchDefault'] = $masterRepository[1]; + $subBranch['Repository'] = $masterRepository[0].":".$branch['Tag']; #This takes place before any xml elements are overwritten by additional entries in the branch, so you can actually change the repo the app draws from + $subBranch['BranchName'] = $branch['Tag']; + $subBranch['BranchDescription'] = $branch['TagDescription'] ? $branch['TagDescription'] : $branch['Tag']; + $subBranch['Path'] = $communityPaths['templates-community']."/".$i.".xml"; + $subBranch['Displayable'] = false; + $subBranch['ID'] = $i; + $replaceKeys = array_diff(array_keys($branch),array("Tag","TagDescription")); + foreach ($replaceKeys as $key) { + $subBranch[$key] = $branch[$key]; + } + unset($subBranch['Branch']); + $myTemplates[$i] = $subBranch; + $o['BranchID'][] = $i; + file_put_contents($subBranch['Path'],makeXML($subBranch)); + } + unset($o['Branch']); + $o['Path'] = $communityPaths['templates-community']."/".$o['ID'].".xml"; + file_put_contents($o['Path'],makeXML($o)); + $myTemplates[$o['ID']] = $o; + } + $i = ++$i; + } + } + } + if ( $invalidXML ) { + writeJsonFile($communityPaths['invalidXML_txt'],$invalidXML); + } else { + @unlink($communityPaths['invalidXML_txt']); + } + writeJsonFile($communityPaths['blacklisted_txt'],$blacklist); + writeJsonFile($communityPaths['statistics'],$statistics); + writeJsonFile($communityPaths['community-templates-info'],$myTemplates); + file_put_contents($communityPaths['LegacyMode'],"active"); + return true; +} + +# DownloadApplicationFeed MUST BE CALLED prior to DownloadCommunityTemplates in order for private repositories to be merged correctly. + +function DownloadApplicationFeed() { + global $communityPaths, $infoFile, $plugin, $communitySettings, $statistics; + + $betaComment = "The author of this template has designated it to be a beta. You may experience issues with this application"; + $moderation = readJsonFile($communityPaths['moderation']); + if ( ! is_array($moderation) ) { + $moderation = array(); + } + $statistics['moderation'] = count($moderation); + + $Repositories = readJsonFile($communityPaths['Repositories']); + if ( ! $Repositories ) { + $Repositories = array(); + } + $statistics['repository'] = count($Repositories); + $downloadURL = randomFile(); + + if ($download = download_url($communityPaths['application-feed'],$downloadURL) ){ + return false; + } + $ApplicationFeed = readJsonFile($downloadURL); + if ( ! is_array($ApplicationFeed) ) { + return false; + } + + unlink($downloadURL); + $i = 0; + $statistics['totalApplications'] = count($ApplicationFeed['applist']); + + $myTemplates = array(); + + foreach ($ApplicationFeed['applist'] as $file) { + if ( (! $file['Repository']) && (! $file['Plugin']) ){ + $statistics['invalidXML']++; + $invalidXML[] = $file; + continue; + } + # Move the appropriate stuff over into a CA data file + $o = $file; + $o['ID'] = $i; + $o['Displayable'] = true; + $o['Author'] = preg_replace("#/.*#", "", $o['Repository']); + $o['DockerHubName'] = strtolower($file['Name']); + $o['RepoName'] = $file['Repo']; + $o['SortAuthor'] = $o['Author']; + $o['SortName'] = $o['Name']; + $o['Licence'] = $file['License']; # Support Both Spellings + $o['Licence'] = $file['Licence']; + $o['Path'] = $communityPaths['templates-community']."/".$i.".xml"; + if ( $o['Plugin'] ) { + $o['Author'] = $o['PluginAuthor']; + $o['Repository'] = $o['PluginURL']; + $o['Category'] .= " Plugins: "; + $o['SortAuthor'] = $o['Author']; + $o['SortName'] = $o['Name']; + } + $RepoIndex = searchArray($Repositories,"name",$o['RepoName']); + if ( $RepoIndex != false ) { + $o['DonateText'] = $Repositories[$RepoIndex]['donatetext']; + $o['DonateImg'] = $Repositories[$RepoIndex]['donateimg']; + $o['DonateLink'] = $Repositories[$RepoIndex]['donatelink']; + $o['WebPageURL'] = $Repositories[$RepoIndex]['web']; + $o['Logo'] = $Repositories[$RepoIndex]['logo']; + $o['Profile'] = $Repositories[$RepoIndex]['profile']; + } + $o['DonateText'] = $file['DonateText'] ? $file['DonateText'] : $o['DonateText']; + $o['DonateLink'] = $file['DonateLink'] ? $file['DonateLink'] : $o['DonateLink']; + + if ( ($file['DonateImg']) || ($file['DonateImage']) ) { #because Sparklyballs can't read the tag documentation + $o['DonateImg'] = $file['DonateImage'] ? $file['DonateImage'] : $file['DonateImg']; + } + + fixSecurity($o,$o); # Apply various fixes to the templates for CA use + $o = fixTemplates($o); + if ( ! $o ) { + continue; + } + +# Overwrite any template values with the moderated values + + if ( is_array($moderation[$o['Repository']]) ) { + $o = array_merge($o, $moderation[$o['Repository']]); + $file = array_merge($file, $moderation[$o['Repository']]); + } + + if ($o['Blacklist']) { + $statistics['blacklist']++; + $blacklist[] = "{$o['Repo']} - {$o['Name']} - {$o['ModeratorComment']}"; + continue; + } + + if ( $o['Plugin'] ) { + $statistics['plugin']++; + } else { + $statistics['docker']++; + } + + $o['Compatible'] = versionCheck($o); + + if ( $o['Beta'] == "true" ) { + $o['ModeratorComment'] .= $o['ModeratorComment'] ? "

$betaComment" : $betaComment; + } + + # Update the settings for the template + + $file['Compatible'] = $o['Compatible']; + $file['Beta'] = $o['Beta']; + $file['MinVer'] = $o['MinVer']; + $file['MaxVer'] = $o['MaxVer']; + $file['Category'] = $o['Category']; + $o['Category'] = str_replace("Status:Beta","",$o['Category']); # undo changes LT made to my xml schema for no good reason + $o['Category'] = str_replace("Status:Stable","",$o['Category']); + $myTemplates[$i] = $o; + + if ( is_array($file['Branch']) ) { + if ( ! $file['Branch'][0] ) { + $tmp = $file['Branch']; + unset($file['Branch']); + $file['Branch'][] = $tmp; + } + foreach($file['Branch'] as $branch) { + $i = ++$i; + $subBranch = $file; + $masterRepository = explode(":",$subBranch['Repository']); + $o['BranchDefault'] = $masterRepository[1]; + $subBranch['Repository'] = $masterRepository[0].":".$branch['Tag']; #This takes place before any xml elements are overwritten by additional entries in the branch, so you can actually change the repo the app draws from + $subBranch['BranchName'] = $branch['Tag']; + $subBranch['BranchDescription'] = $branch['TagDescription'] ? $branch['TagDescription'] : $branch['Tag']; + $subBranch['Path'] = $communityPaths['templates-community']."/".$i.".xml"; + $subBranch['Displayable'] = false; + $subBranch['ID'] = $i; + $replaceKeys = array_diff(array_keys($branch),array("Tag","TagDescription")); + foreach ($replaceKeys as $key) { + $subBranch[$key] = $branch[$key]; + } + unset($subBranch['Branch']); + $myTemplates[$i] = $subBranch; + $o['BranchID'][] = $i; + file_put_contents($subBranch['Path'],makeXML($subBranch)); + } + } + unset($file['Branch']); + $myTemplates[$o['ID']] = $o; + $i = ++$i; + $templateXML = makeXML($file); + file_put_contents($o['Path'],$templateXML); + } + writeJsonFile($communityPaths['blacklisted_txt'],$blacklist); + writeJsonFile($communityPaths['statistics'],$statistics); + if ( $invalidXML ) { + writeJsonFile($communityPaths['invalidXML_txt'],$invalidXML); + } else { + @unlink($communityPaths['invalidXML_txt']); + } + writeJsonFile($communityPaths['community-templates-info'],$myTemplates); + @unlink($communityPaths['LegacyMode']); + return true; +} + +function getConvertedTemplates() { + global $communityPaths, $infoFile, $plugin, $communitySettings, $statistics; + +# Start by removing any pre-existing private (converted templates) + $templates = readJsonFile($communityPaths['community-templates-info']); + $statistics = readJsonFile($communityPaths['statistics']); + unset($statistics['private']); + if ( ! is_array($templates) ) { + return false; + } + foreach ($templates as $template) { + if ( $template['Private'] ) { + continue; + } else { + $myTemplates[] = $template; + } + } + + $appCount = count($myTemplates); + + $moderation = readJsonFile($communityPaths['moderation']); + if ( ! is_array($moderation) ) { + $moderation = array(); + } + + $i = $appCount; + unset($Repos); + + if ( ! is_dir($communityPaths['convertedTemplates']) ) { + return; + } + $Repos = dirContents($communityPaths['convertedTemplates']); + + foreach ($Repos as $Repo) { + if ( ! is_dir($communityPaths['convertedTemplates'].$Repo) ) { + continue; + } + + unset($privateTemplates); + $repoPath = $communityPaths['convertedTemplates'].$Repo."/"; + + $privateTemplates = dirContents($repoPath); + if ( empty($privateTemplates) ) { + continue; + } + foreach ($privateTemplates as $template) { + if ( strpos($template,".xml") === FALSE ) { + continue; + } + if (is_file($repoPath.$template)) { + $o = readXmlFile($repoPath.$template); + $o = fixTemplates($o); + $o['RepoName'] = $Repo." Repository"; + $o['ID'] = $i; + $o['Displayable'] = true; + $o['Date'] = ( $o['Date'] ) ? strtotime( $o['Date'] ) : 0; + $o['SortAuthor'] = $o['Author']; + $o['Private'] = "true"; + $o['Forum'] = ""; + $o['Compatible'] = versionCheck($o); + $statistics['private']++; + fixSecurity($o,$o); + $myTemplates[$i] = $o; + $i = ++$i; + } + } + } + writeJsonFile($communityPaths['community-templates-info'],$myTemplates); + writeJsonFile($communityPaths['statistics'],$statistics); + return true; +} + +############################################################ +# # +# Routines that actually displays the template containers. # +# # +############################################################ +function display_apps($viewMode,$pageNumber=1,$selectedApps=false) { + global $communityPaths, $separateOfficial, $officialRepo, $communitySettings; + + $file = readJsonFile($communityPaths['community-templates-displayed']); + $officialApplications = $file['official']; + $communityApplications = $file['community']; + $totalApplications = count($officialApplications) + count($communityApplications); + $navigate = array(); + + if ( $separateOfficial ) { + if ( count($officialApplications) ) { + $navigate[] = "doesn't matter what's here -> first element gets deleted anyways"; + $display = "
"; + + $logos = readJsonFile($communityPaths['logos']); + $display .= $logos[$officialRepo] ? "  " : ""; + $display .= "$officialRepo

"; + $display .= my_display_apps($viewMode,$officialApplications,1,true,$selectedApps); + } + } + + if ( count($communityApplications) ) { + if ( $separateOfficial ) { + $navigate[] = "Community Supported Applications"; + $display .= "
Community Supported Applications

"; + } + $display .= my_display_apps($viewMode,$communityApplications,$pageNumber,false,$selectedApps); + } + unset($navigate[0]); + + if ( count($navigate) ) { + $bookmark = "Jump To: ".implode("     ",$navigate); + } + $display .= ( $totalApplications == 0 ) ? "
No Matching Content Found
" : ""; + + $totalApps = "$totalApplications"; + + $display .= ""; + echo $bookmark; + echo $display; +} + +function my_display_apps($viewMode,$file,$pageNumber=1,$officialFlag=false,$selectedApps=false) { + global $communityPaths, $info, $communitySettings, $plugin, $unRaid64, $unRaid635; + + if ( ! $selectedApps ) { + $selectedApps = array(); + } + + $templateFormatArray = array(1 => $communitySettings['windowWidth']); # this array is only used on header, sol, eol, footer + + $pinnedApps = getPinnedApps(); + $iconSize = $communitySettings['iconSize']; + $tabMode = $communitySettings['newWindow']; + $checkedOffApps = arrayEntriesToObject(@array_merge(@array_values($selectedApps['docker']),@array_values($selectedApps['plugin']))); + usort($file,"mySort"); + + $communitySettings['viewMode'] = $viewMode; + + $skin = readJsonFile($communityPaths['defaultSkin']); + if ( ! $officialFlag ) { + $ct = "
".getPageNavigation($pageNumber,count($file),false)."
"; + } + $ct .= vsprintf($skin[$viewMode]['header'],$templateFormatArray); + $displayTemplate = $skin[$viewMode]['template']; + if ( $unRaid64 ) { + $communitySettings['maxColumn'] = $communitySettings['maxIconColumns']; + } + if ( $viewMode == 'detail' ) { + $communitySettings['maxColumn'] = $unRaid64 ? $communitySettings['maxDetailColumns'] : 2; + $communitySettings['viewMode'] = "icon"; + } + + $columnNumber = 0; + $appCount = 0; + $startingApp = $officialFlag ? 1 : ($pageNumber -1) * $communitySettings['maxPerPage'] + 1; + $startingAppCounter = 0; + +# Create entries for skins + foreach ($file as $template) { + $startingAppCounter++; + if ( $startingAppCounter < $startingApp ) { + continue; + } + if ( $columnNumber == 0 ) { + $ct .= vsprintf($skin[$viewMode]['sol'],$templateFormatArray); + } + $name = $template['SortName']; + $appName = str_replace(" ","",$template['SortName']); + $t = ""; + $ID = $template['ID']; + $selected = $info[$name]['template'] && stripos($info[$name]['icon'], $template['SortAuthor']) !== false; + $selected = $template['Uninstall'] ? true : $selected; + + $appType = $template['Plugin'] ? "plugin" : "docker"; + $previousAppName = $template['Plugin'] ? $template['PluginURL'] : $template['Name']; + $checked = $checkedOffApps[$previousAppName] ? "checked" : ""; + + $RepoName = ( $template['Private'] == "true" ) ? $template['RepoName']." (Private)" : $template['RepoName']; + if ( ! $template['DonateText'] ) { + $template['DonateText'] = "Donate To Author"; + } + $template['display_DonateLink'] = $template['DonateLink'] ? "Donate To Author" : ""; + $template['display_Project'] = $template['Project'] ? "Project Home Page" : ""; + $template['display_Support'] = $template['Support'] ? "Support Thread" : ""; + $template['display_webPage'] = $template['WebPageURL'] ? "Web Page" : ""; + + if ( $template['display_Support'] && $template['display_Project'] ) { + $template['display_Project'] = "   ".$template['display_Project']; + } + if ( $template['display_webPage'] && ( $template['display_Project'] || $template['display_Support'] ) ) { + $template['display_webPage'] = "   ".$template['display_webPage']; + } + if ( $template['UpdateAvailable'] ) { + $template['display_UpdateAvailable'] = $template['Plugin'] ? "
Update Available. Click Here to Install
" : "
Update Available. Click Here to install
"; + } + if ( $template['Deprecated'] ) { + $template['ModeratorComment'] .= "
This application has been deprecated."; + } + $template['display_ModeratorComment'] .= $template['ModeratorComment'] ? "Moderator Comments: ".$template['ModeratorComment'] : ""; + $tempLogo = $template['Logo'] ? "" : ""; + $template['display_Announcement'] = $template['Forum'] ? "$RepoName $tempLogo" : "$RepoName $tempLogo"; + $template['display_Stars'] = $template['stars'] ? " ".$template['stars']."" : ""; + $template['display_Downloads'] = $template['downloads'] ? "
".$template['downloads']."
" : "
Not Available
"; + + if ( $pinnedApps[$template['Repository']] ) { + $pinned = "greenButton.png"; + $pinnedTitle = "Click to unpin this application"; + } else { + $pinned = "redButton.png"; + $pinnedTitle = "Click to pin this application"; + } + $template['display_pinButton'] = ""; + if ( $template['Uninstall'] ) { + $template['display_Uninstall'] = ""; + } else { + $template['display_Uninstall'] .= "onclick='uninstallDocker("".$template['MyPath']."","".$template['Name']."");'>"; + } + } + $template['display_removable'] = $template['Removable'] ? "" : ""; + if ( $template['Date'] > strtotime($communitySettings['timeNew'] ) ) { + $template['display_newIcon'] = ""; + } + $template['display_changes'] = $template['Changes'] ? " " : ""; + $template['display_humanDate'] = date("F j, Y",$template['Date']); + + $template['display_dateUpdated'] = ($template['Date'] && is_file($communityPaths['newFlag']) ) ? "
Date Updated: ".$template['display_humanDate']."
" : ""; + $template['display_multi_install'] = ($template['Removable'] && $unRaid635) ? "" : ""; + if (! $communitySettings['dockerRunning'] && ! $template['Plugin']) { + unset($template['display_multi_install']); + } + if ( $template['Plugin'] ) { + $pluginName = basename($template['PluginURL']); + if ( file_exists("/var/log/plugins/$pluginName") ) { + $pluginSettings = isset($template['CAlink']) ? $template['CAlink'] : getPluginLaunch($pluginName); + $tmpVar = $pluginSettings ? "" : " disabled "; + $template['display_pluginSettings'] = ""; + $template['display_pluginSettingsIcon'] = $pluginSettings ? "" : ""; + } else { + $buttonTitle = $template['MyPath'] ? "Reinstall Plugin" : "Install Plugin"; + $template['display_pluginInstall'] = ""; + $template['display_pluginInstallIcon'] = ""; + } + } else { + if ( $communitySettings['dockerRunning'] ) { + if ( $selected ) { + $template['display_dockerDefault'] = ""; + $template['display_dockerEdit'] = ""; + $template['display_dockerDefault'] = $template['BranchID'] ? "" : $template['display_dockerDefault']; + $template['display_dockerDefaultIcon'] = ""; + $template['display_dockerEditIcon'] = ""; + if ( $info[$name]['url'] && $info[$name]['running'] ) { + $template['dockerWebIcon'] = "  "; + } + } else { + if ( $template['MyPath'] ) { + $template['display_dockerReinstall'] = ""; + $template['display_dockerReinstallIcon'] = ""; + } else { + $template['display_dockerInstall'] = ""; + $template['display_dockerInstall'] = $template['BranchID'] ? "" : $template['display_dockerInstall']; + $template['display_dockerInstallIcon'] = ""; + $template['display_dockerInstallIcon'] = $template['BranchID'] ? "" : $template['display_dockerInstallIcon']; + } + } + } else { + $template['display_dockerDisable'] = "Docker Not Enabled"; + } + } + if ( ! $template['Compatible'] && ! $template['UnknownCompatible'] ) { + $template['display_compatible'] = "NOTE: This application is listed as being NOT compatible with your version of unRaid
"; + $template['display_compatibleShort'] = "Incompatible"; + } + $template['display_author'] = "".$template['Author'].""; + $displayIcon = $template['Icon']; + $displayIcon = $displayIcon ? $displayIcon : "/plugins/$plugin/images/question.png"; + $template['display_iconSmall'] = ""; + $template['display_iconSelectable'] = ""; + $template['display_popupDesc'] = ( $communitySettings['maxColumn'] > 2 ) ? "Click for a full description\n".$template['PopUpDescription'] : "Click for a full description"; + if ( isset($ID) ) { + $template['display_iconClickable'] = "".$template['display_iconSelectable'].""; + $template['display_iconSmall'] = ""; + } else { + $template['display_iconClickable'] = $template['display_iconSelectable']; + $template['display_iconSmall'] = ""; + } + + if ( $communitySettings['dockerSearch'] == "yes" && ! $template['Plugin'] ) { + $template['display_dockerName'] = "".$template['Name'].""; + } else { + $template['display_dockerName'] = $template['Name']; + } + $template['Category'] = ($template['Category'] == "UNCATEGORIZED") ? "Uncategorized" : $template['Category']; + + if ( ( $template['Beta'] == "true" ) ) { + $template['display_dockerName'] .= "(beta)"; + } +# Entries created. Now display it + $t .= vsprintf($displayTemplate,toNumericArray($template)); + + $columnNumber=++$columnNumber; + + if ( $communitySettings['viewMode'] == "icon" ) { + if ( $columnNumber == $communitySettings['maxColumn'] ) { + $columnNumber = 0; + $t .= vsprintf($skin[$viewMode]['eol'],$templateFormatArray); + } + } else { + $columnNumber = 0; + $t .= vsprintf($skin[$viewMode]['eol'],$templateFormatArray); + } + + $ct .= $t; + $count++; + if ( ! $officialFlag && ($count == $communitySettings['maxPerPage']) ) { + break; + } + } + $ct .= vsprintf($skin[$viewMode]['footer'],$templateFormatArray); + $ct .= caGetMode(); + if ( ! $officialFlag ) { + $ct .= "
".getPageNavigation($pageNumber,count($file),false)."


"; + } + + return $ct; +} + +function getPageNavigation($pageNumber,$totalApps,$dockerSearch) { + global $communitySettings; + + if ( $communitySettings['maxPerPage'] < 0 ) { return; } + + $my_function = $dockerSearch ? "dockerSearch" : "changePage"; + if ( $dockerSearch ) { + $communitySettings['maxPerPage'] = 25; + } + $totalPages = ceil($totalApps / $communitySettings['maxPerPage']); + + if ($totalPages == 1) { + return; + } + $startApp = ($pageNumber - 1) * $communitySettings['maxPerPage'] + 1; + $endApp = $pageNumber * $communitySettings['maxPerPage']; + if ( $endApp > $totalApps ) { + $endApp = $totalApps; + } + $o = "
"; + if ( ! $dockerSearch ) { + $o .= "Displaying $startApp - $endApp (of $totalApps)
"; + } + $o .= "Select Page:   "; + + $previousPage = $pageNumber - 1; + $o .= ( $pageNumber == 1 ) ? "" : ""; + $o .= "   "; + $startingPage = $pageNumber - 5; + if ($startingPage < 3 ) { + $startingPage = 1; + } else { + $o .= "1   ...   "; + } + $endingPage = $pageNumber + 5; + if ( $endingPage > $totalPages ) { + $endingPage = $totalPages; + } + for ($i = $startingPage; $i <= $endingPage; $i++) { + if ( $i == $pageNumber ) { + $o .= "$i"; + } else { + $o .= "$i"; + } + $o .= "   "; + } + if ( $endingPage != $totalPages) { + if ( ($totalPages - $pageNumber ) > 6){ + $o .= "...   "; + } + if ( ($totalPages - $pageNumber ) >5 ) { + $o .= "$totalPages   "; + } + } + $nextPage = $pageNumber + 1; + $o .= ( $pageNumber < $totalPages ) ? "" : ""; + $o .= "
"; + + return $o; +} + +############################# +# # +# Selects an app of the day # +# # +############################# +function appOfDay($file) { + global $communityPaths, $info; + + $oldAppDay = @filemtime($communityPaths['appOfTheDay']); + $oldAppDay = $oldAppDay ? $oldAppDay : 1; + $oldAppDay = intval($oldAppDay / 86400); + $currentDay = intval(time() / 86400); + if ( $oldAppDay == $currentDay ) { + $app = readJsonFile($communityPaths['appOfTheDay']); + } + if ( count($app) < 9 ) { unset($app); } # For update from old version where only 2 possible apps of day + if ( ! $app ) { + for ( $ii=0; $ii<10; $ii++ ) { + $flag = false; + if ( $app[$ii] ) { + $flag = checkRandomApp($app[$ii],$file); + } + if ( ! $flag ) { + while (true ) { + $randomApp = mt_rand(0,count($file) -1); + $flag = checkRandomApp($randomApp,$file); + if ( $flag ) { + break; + } + } + } + $app[$ii] = $randomApp; + } + } + writeJsonFile($communityPaths['appOfTheDay'],$app); + return $app; +} + +##################################################### +# Checks selected app for eligibility as app of day # +##################################################### +function checkRandomApp($randomApp,$file) { + if ( ! $file[$randomApp]['Displayable'] ) return false; + if ( ! $file[$randomApp]['Compatible'] ) return false; + if ( $file[$randomApp]['Blacklist'] ) return false; + if ( $file[$randomApp]['ModeratorComment'] ) return false; + if ( $file[$randomApp]['Deprecated'] ) return false; + return true; +} + +########################################################################## +# # +# function that comes up with alternate search suggestions for dockerHub # +# # +########################################################################## +function suggestSearch($filter,$displayFlag) { + $dockerFilter = str_replace("_","-",$filter); + $dockerFilter = str_replace("%20","",$dockerFilter); + $dockerFilter = str_replace("/","-",$dockerFilter); + $otherSearch = explode("-",$dockerFilter); + + if ( count($otherSearch) > 1 ) { + $returnSearch .= "Suggested Searches: "; + + foreach ( $otherSearch as $suggestedSearch) { + $returnSearch .= "$suggestedSearch    "; + } + } else { + $otherSearch = preg_split('/(?=[A-Z])/',$dockerFilter); + + if ( count($otherSearch) > 1 ) { + $returnSearch .= "Suggested Searches: "; + + foreach ( $otherSearch as $suggestedSearch) { + if ( strlen($suggestedSearch) > 1 ) { + $returnSearch .= "$suggestedSearch    "; + } + } + } else { + if ( $displayFlag ) { + $returnSearch .= "Suggested Searches: Unknown"; + } + } + } + return $returnSearch; +} + +######################################################################################## +# # +# function used to display the navigation (page up/down buttons) for dockerHub results # +# # +######################################################################################## +function dockerNavigate($num_pages, $pageNumber) { + return getPageNavigation($pageNumber,$num_pages * 25, true); +} + +############################################################## +# # +# function that actually displays the results from dockerHub # +# # +############################################################## +function displaySearchResults($pageNumber,$viewMode) { + global $communityPaths, $communitySettings, $plugin; + + $tempFile = readJsonFile($communityPaths['dockerSearchResults']); + $num_pages = $tempFile['num_pages']; + $file = $tempFile['results']; + $templates = readJsonFile($communityPaths['community-templates-info']); + + echo dockerNavigate($num_pages,$pageNumber); + echo "

"; + + $iconSize = $communitySettings['iconSize']; + $maxColumn = $communitySettings['maxColumn']; + + switch ($viewMode) { + case "icon": + $t = ""; + break; + case "table": + $t = "
"; + $iconSize = 48; + break; + case "detail": + $t = "
ContainerAuthorStarsDescription
"; + $viewMode = "icon"; + $maxColumn = 2; + break; + } + + $column = 0; + + $t .= ""; + + foreach ($file as $result) { + $recommended = false; + foreach ($templates as $template) { + if ( $template['Repository'] == $result['Repository'] ) { + $result['Description'] = $template['Description']; + $result['Description'] = str_replace("'","'",$result['Description']); + $result['Description'] = str_replace('"',""",$result['Description']); + $result['Icon'] = $template['IconWeb']; + } + } + $result['display_stars'] = $result['Stars'] ? "".$result['Stars']."" : ""; + $result['display_official'] = $result['Official'] ? "Official ".$result['Name']." container.

": ""; + $result['display_official_short'] = $result['Official'] ? "Official" : ""; + + if ( $viewMode == "icon" ) { + $t .= ""; + + if ( $maxColumn == 2 ) { + $t .= ""; + } + $column = ++$column; + if ( $column == $maxColumn ) { + $column = 0; + $t .= ""; + } + } + if ( $viewMode == "table" ) { + $t .= ""; + $t .= ""; + $t .= ""; + $t .= ""; + $t .= ""; + $t .= ""; + $t .= ""; + } + } + $t .= "
"; + $t .= "
".$result['display_official_short']."
"; + + $t .= "
Author: {$result['Author']}
"; + $t .= "
".$result['display_stars']."
"; + + $description = "Click to go to the dockerHub website for this container"; + if ( $result['Description'] ) { + $description = $result['Description']."

$description"; + } + $description =str_replace("'","'",$description); + $description = str_replace('"',""",$description); + + $t .= "
"; + $t .= ""; + $t .= "
".$result['Name']."
"; + $t .= "
"; + $t .= "
"; + $t .= "


"; + $t .= $result['display_official']; + + if ( $result['Description'] ) { + $t .= "".$result['Description']."

"; + } else { + $t .= "Container Overview not available.

"; + } + $t .= "Click container's icon for full description

"; + $t .= "
"; + $t .= ""; + $t .= "".$result['Name']."{$result['Author']}".$result['display_stars'].""; + $t .= $result['display_official']; + $t .= "".$result['Description']."
"; + echo $t; + echo dockerNavigate($num_pages,$pageNumber); +} + +############################################ +############################################ +## ## +## BEGIN MAIN ROUTINES CALLED BY THE HTML ## +## ## +############################################ +############################################ + +switch ($_POST['action']) { + +###################################################################################### +# # +# get_content - get the results from templates according to categories, filters, etc # +# # +###################################################################################### +case 'get_content': + $filter = getPost("filter",false); + $category = "/".getPost("category",false)."/i"; + $newApp = getPost("newApp",false); + $sortOrder = getSortOrder(getPostArray("sortOrder")); + $windowWidth = getPost("windowWidth",false); + getMaxColumns($windowWidth); + + $newAppTime = strtotime($communitySettings['timeNew']); + + if ( file_exists($communityPaths['addConverted']) ) { + @unlink($infoFile); + @unlink($communityPaths['addConverted']); + } + + if ( file_exists($communityPaths['appFeedOverride']) ) { + $communitySettings['appFeed'] = "false"; + @unlink($communityPaths['appFeedOverride']); + } + + if (!file_exists($infoFile)) { + if ( $communitySettings['appFeed'] == "true" ) { + DownloadApplicationFeed(); + if (!file_exists($infoFile)) { +# $communitySettings['appFeed'] = "false"; # Do Not automatically revert. Toss up a message instead + echo "
Download of appfeed failed.

Community Applications requires your server to have internet access. The most common cause of this failure is a failure to resolve DNS addresses. You can try and reset your modem and router to fix this issue, or set static DNS addresses (Settings - Network Settings) of 8.8.8.8 and 8.8.4.4 and try again.

Alternatively, there is also a chance that the server handling the application feed is temporarily down. Switching CA to operate in Legacy Mode might temporarily allow you to still utilize CA.
"; + exec("curl --compressed --max-time 60 --insecure --location -o ".$communityPaths['tempFiles']."/failedOutput ".$communityPaths['application-feed'],$out); + foreach ($out as $line) { + echo "$line
"; + } + $out = @file_get_contents($communityPaths['tempFiles']."/failedOutput"); + $out = str_replace("\n","
",$out); + echo "$out"; + @unlink($infoFile); + } + } + + if ($communitySettings['appFeed'] == "false" ) { + if (!DownloadCommunityTemplates()) { + echo "
Download of appfeed failed.

Community Applications requires your server to have internet access. The most common cause of this failure is a failure to resolve DNS addresses. You can try and reset your modem and router to fix this issue, or set static DNS addresses (Settings - Network Settings) of 8.8.8.8 and 8.8.4.4 and try again.

Alternatively, there is also a chance that the server handling templates (GitHub.com) is temporarily down."; + break; + } else { + $lastUpdated['last_updated_timestamp'] = time(); + writeJsonFile($communityPaths['lastUpdated-old'],$lastUpdated); + if (is_file($communityPaths['updateErrors'])) { + echo "

The following errors occurred:

"; + echo "".file_get_contents($communityPaths['updateErrors'])."
"; + echo ""; + echo caGetMode(); + break; + } + } + } + } + getConvertedTemplates(); + + $file = readJsonFile($communityPaths['community-templates-info']); + if (!is_array($file)) break; + + if ( $category === "/NONE/i" ) { + echo "
Select A Category Above
"; + if ( $communitySettings['appOfTheDay'] == "yes" ) { + $displayApplications = array(); + if ( count($file) > 200) { + $appsOfDay = appOfDay($file); + for ($i=0;$i<$communitySettings['maxDetailColumns'];$i++) { + $displayApplications['community'][] = $file[$appsOfDay[$i]]; + } + writeJsonFile($communityPaths['community-templates-displayed'],$displayApplications); + echo ""; + echo "
Random Apps Of The Day

"; + echo my_display_apps("detail",$displayApplications['community'],$runningDockers,$imagesDocker); + break; + } + } else { + break; + } + } + + $display = array(); + $official = array(); + + foreach ($file as $template) { + if ( $template['Blacklist'] ) { + continue; + } + if ( ($communitySettings['hideDeprecated'] == "true") && ($template['Deprecated']) ) { + continue; # ie: only show deprecated apps within previous apps section + } + if ( ! $template['Displayable'] ) { + continue; + } + if ( $communitySettings['hideIncompatible'] == "true" && ! $template['Compatible'] ) { + continue; + } + $name = $template['Name']; + +# Skip over installed containers + + if ( $newApp != "true" && $filter == "" && $communitySettings['separateInstalled'] == "true" ) { + if ( $template['Plugin'] ) { + $pluginName = basename($template['PluginURL']); + + if ( file_exists("/var/log/plugins/$pluginName") ) { + continue; + } + } else { + $selected = false; + foreach ($dockerRunning as $installedDocker) { + $installedImage = $installedDocker['Image']; + $installedName = $installedDocker['Name']; + + if ( startsWith($installedImage,$template['Repository']) ) { + if ( $installedName == $template['Name'] ) { + $selected = true; + break; + } + } + } + if ( $selected ) { + continue; + } + } + } + if ( $template['Plugin'] ) { + if ( file_exists("/var/log/plugins/".basename($template['PluginURL'])) ) { + $template['UpdateAvailable'] = checkPluginUpdate($template['PluginURL']); + $template['MyPath'] = $template['PluginURL']; + } + } + if ( $newApp == "true" ) { + file_put_contents($communityPaths['newFlag'],"new category is being displayed"); + } else { + @unlink($communityPaths['newFlag']); + } + if ( ($newApp == "true") && ($template['Date'] < $newAppTime) ) { continue; } + if ( $category && ! preg_match($category,$template['Category'])) { continue; } + + if ($filter) { + if (preg_match("#$filter#i", $template['Name']) || preg_match("#$filter#i", $template['Author']) || preg_match("#$filter#i", $template['Description']) || preg_match("#$filter#i", $template['Repository'])) { + $template['Description'] = highlight($filter, $template['Description']); + $template['Author'] = highlight($filter, $template['Author']); + $template['Name'] = highlight($filter, $template['Name']); + } else continue; + } + + if ( $separateOfficial ) { + if ( $template['RepoName'] == $officialRepo ) { + $official[] = $template; + } else { + $display[] = $template; + } + } else { + $display[] = $template; + } + } + + $displayApplications['official'] = $official; + $displayApplications['community'] = $display; + + writeJsonFile($communityPaths['community-templates-displayed'],$displayApplications); + display_apps($sortOrder['viewMode']); + break; + +######################################################## +# # +# force_update -> forces an update of the applications # +# # +######################################################## +case 'force_update': + download_url($communityPaths['moderationURL'],$communityPaths['moderation']); + $tmpFileName = randomFile(); + download_url($communityPaths['community-templates-url'],$tmpFileName); + $Repositories = readJsonFile($tmpFileName); + writeJsonFile($communityPaths['Repositories'],$Repositories); + $repositoriesLogo = $Repositories; + if ( ! is_array($repositoriesLogo) ) { + $repositoriesLogo = array(); + } + + foreach ($repositoriesLogo as $repositories) { + if ( $repositories['logo'] ) { + $repoLogo[$repositories['name']] = $repositories['logo']; + } + } + writeJsonFile($communityPaths['logos'],$repoLogo); + @unlink($tmpFileName); + + if ( ! file_exists($infoFile) ) { + if ( ! file_exists($communityPaths['lastUpdated-old']) ) { + $latestUpdate['last_updated_timestamp'] = time(); + writeJsonFile($communityPaths['lastUpdated-old'],$latestUpdate); + } + echo "ok"; + break; + } + + if ( file_exists($communityPaths['lastUpdated-old']) ) { + $lastUpdatedOld = readJsonFile($communityPaths['lastUpdated-old']); + } else { + $lastUpdatedOld['last_updated_timestamp'] = 0; + } + @unlink($communityPaths['lastUpdated']); + download_url($communityPaths['application-feed-last-updated'],$communityPaths['lastUpdated']); + + $latestUpdate = readJsonFile($communityPaths['lastUpdated']); + if ( ! $latestUpdate['last_updated_timestamp'] ) { + $latestUpdate['last_updated_timestamp'] = INF; + @unlink($communityPaths['lastUpdated']); + } + + if ( $latestUpdate['last_updated_timestamp'] > $lastUpdatedOld['last_updated_timestamp'] ) { + if ( $latestUpdate['last_updated_timestamp'] != INF ) { + copy($communityPaths['lastUpdated'],$communityPaths['lastUpdated-old']); + } + unlink($infoFile); + } else { + moderateTemplates(); + } + echo "ok"; + break; + +#################################################################################################### +# # +# force_update_button - forces the system temporarily to override the appFeed and forces an update # +# # +#################################################################################################### +case 'force_update_button': + if ( ! is_file($communityPaths['LegacyMode']) ) { + file_put_contents($communityPaths['appFeedOverride'],"dunno"); + } + @unlink($infoFile); + echo "ok"; + break; + +#################################################################################### +# # +# display_content - displays the templates according to view mode, sort order, etc # +# # +#################################################################################### +case 'display_content': + $sortOrder = getSortOrder(getPostArray('sortOrder')); + $windowWidth = getPost("windowWidth",false); + $pageNumber = getPost("pageNumber","1"); + $selectedApps = json_decode(getPost("selected",false),true); + getMaxColumns($windowWidth); + + if ( file_exists($communityPaths['community-templates-displayed']) ) { + display_apps($sortOrder['viewMode'],$pageNumber,$selectedApps); + } else { + echo "
Select A Category Above
"; + } + break; + +######################################################################## +# # +# change_docker_view - called when the view mode for dockerHub changes # +# # +######################################################################## +case 'change_docker_view': + $sortOrder = getSortOrder(getPostArray('sortOrder')); + + if ( ! file_exists($communityPaths['dockerSearchResults']) ) { + break; + } + + $file = readJsonFile($communityPaths['dockerSearchResults']); + $pageNumber = $file['page_number']; + displaySearchResults($pageNumber,$sortOrder['viewMode']); + break; + +####################################################################### +# # +# convert_docker - called when system adds a container from dockerHub # +# # +####################################################################### +case 'convert_docker': + $dockerID = getPost("ID",""); + + $file = readJsonFile($communityPaths['dockerSearchResults']); + + $docker = $file['results'][$dockerID]; + + $docker['Description'] = str_replace("&", "&", $docker['Description']); + + if ( ! $docker['Official'] ) { + $dockerURL = $docker['DockerHub']."~/dockerfile/"; + download_url($dockerURL,$communityPaths['dockerfilePage']); + + $mystring = file_get_contents($communityPaths['dockerfilePage']); + + @unlink($communityPaths['dockerfilePage']); + + $thisstring = strstr($mystring,'"dockerfile":"'); + $thisstring = trim($thisstring); + $thisstring = explode("}",$thisstring); + $thisstring = explode(":",$thisstring[0]); + unset($thisstring[0]); + $teststring = implode(":",$thisstring); + + $teststring = str_replace('\n',"\n",$teststring); + $teststring = str_replace("\u002F", "/", $teststring); + $teststring = trim($teststring,'"'); + $teststring = stripslashes($teststring); + $teststring = substr($teststring,2); + + $docker['Description'] = str_replace("&", "&", $docker['Description']); + + $dockerFile = explode("\n",$teststring); + + $volumes = array(); + $ports = array(); + + foreach ( $dockerFile as $dockerLine ) { + $dockerCompare = trim(strtoupper($dockerLine)); + + $dockerCmp = strpos($dockerCompare, "VOLUME"); + if ( $dockerCmp === 0 ) { + $dockerLine = str_replace("'", " ", $dockerLine); + $dockerLine = str_replace("[", " ", $dockerLine); + $dockerLine = str_replace("]", " ", $dockerLine); + $dockerLine = str_replace(",", " ", $dockerLine); + $dockerLine = str_replace('"', " ", $dockerLine); + + $volumes[] = $dockerLine; + } + + $dockerCmp = strpos($dockerCompare, "EXPOSE"); + if ( $dockerCmp === 0 ) { + $dockerLine = str_replace("'", " ", $dockerLine); + $dockerLine = str_replace("[", " ", $dockerLine); + $dockerLine = str_replace("]", " ", $dockerLine); + $dockerLine = str_replace(",", " ", $dockerLine); + $dockerLine = str_replace('"', " ", $dockerLine); + $ports[] = $dockerLine; + } + } + + $allVolumes = array(); + foreach ( $volumes as $volume ) { + $volumeList = explode(" ", $volume); + unset($volumeList[0]); + + foreach ($volumeList as $myVolume) { + $allVolumes[] = $myVolume; + } + } + + $allPorts = array(); + foreach ( $ports as $port) { + $portList = str_replace("/tcp", "", $port); + $portList = explode(" ", $portList); + unset($portList[0]); + foreach ( $portList as $myPort ) { + $allPorts[] = $myPort; + } + } + + $dockerfile['Name'] = $docker['Name']; + $dockerfile['Support'] = $docker['DockerHub']; + $dockerfile['Description'] = $docker['Description']."\n\n[b]Converted By Community Applications[/b]"; + $dockerfile['Overview'] = $dockerfile['Description']; + $dockerfile['Registry'] = $dockerURL; + $dockerfile['Repository'] = $docker['Repository']; + $dockerfile['BindTime'] = "true"; + $dockerfile['Privileged'] = "false"; + $dockerfile['Networking']['Mode'] = "bridge"; + + foreach ($allPorts as $addPort) { + if ( strpos($addPort, "/udp") === FALSE ) { + $dockerfileport['HostPort'] = $addPort; + $dockerfileport['ContainerPort'] = $addPort; + $dockerfileport['Protocol'] = "tcp"; + $webUI[] = $addPort; + $dockerfile['Networking']['Publish']['Port'][] = $dockerfileport; + } else { + $addPort = str_replace("/udp","",$addPort); + $dockerfileport['HostPort'] = $addPort; + $dockerfileport['ContainerPort'] = $addPort; + $dockerfileport['Protocol'] = "udp"; + $dockerfile['Networking']['Publish']['Port'][] = $dockerfileport; + } + } + foreach ( $allVolumes as $addVolume ) { + if ( ! $addVolume ) { continue; } + $dockervolume['HostDir'] = ""; + $dockervolume['ContainerDir'] = $addVolume; + $dockervolume['Mode'] = "rw"; + $dockerfile['Data']['Volume'][] = $dockervolume; + } + $dockerfile['Icon'] = $docker['Icon']; + + if ( count($webUI) == 1 ) { + $dockerfile['WebUI'] .= "http://[IP]:[PORT:".$webUI[0]."]"; + } + if ( count($webUI) > 1 ) { + foreach ($webUI as $web) { + if ( $web[0] == "8" ) { + $webPort = $web; + } + } + $dockerfile['WebUI'] .= "http://[IP]:[PORT:".$webPort."]"; + } + } else { +# Container is Official. Add it as such + $dockerURL = $docker['DockerHub']; + $dockerfile['Name'] = $docker['Name']; + $dockerfile['Support'] = $docker['DockerHub']; + $dockerfile['Overview'] = $docker['Description']."\n[b]Converted By Community Applications[/b]"; + $dockerfile['Description'] = $dockerfile['Overview']; + $dockerfile['Registry'] = $dockerURL; + $dockerfile['Repository'] = $docker['Repository']; + $dockerfile['BindTime'] = "true"; + $dockerfile['Privileged'] = "false"; + $dockerfile['Networking']['Mode'] = "bridge"; + $dockerfile['Icon'] = $docker['Icon']; + } + $dockerXML = makeXML($dockerfile); + + $xmlFile = $communityPaths['convertedTemplates']."DockerHub/"; + if ( ! is_dir($xmlFile) ) { + exec("mkdir -p ".$xmlFile); + } + $xmlFile .= str_replace("/","-",$docker['Repository']).".xml"; + file_put_contents($xmlFile,$dockerXML); + file_put_contents($communityPaths['addConverted'],"Dante"); + echo $xmlFile; + break; + +######################################################### +# # +# search_dockerhub - returns the results from dockerHub # +# # +######################################################### +case 'search_dockerhub': + $filter = getPost("filter",""); + $pageNumber = getPost("page","1"); + $sortOrder = getSortOrder(getPostArray('sortOrder')); + + $communityTemplates = readJsonFile($communityPaths['community-templates-info']); + $filter = str_replace(" ","%20",$filter); + $jsonPage = shell_exec("curl -s -X GET 'https://registry.hub.docker.com/v1/search?q=$filter\&page=$pageNumber'"); + $pageresults = json_decode($jsonPage,true); + $num_pages = $pageresults['num_pages']; + + echo ""; + + if ($pageresults['num_results'] == 0) { + echo "
No matching content found on dockerhub
"; + echo suggestSearch($filter,true); + echo ""; + @unlink($communityPaths['dockerSerchResults']); + break; + } + + $i = 0; + + foreach ($pageresults['results'] as $result) { + unset($o); + $o['Repository'] = $result['name']; + $details = explode("/",$result['name']); + $o['Author'] = $details[0]; + $o['Name'] = $details[1]; + $o['Description'] = $result['description']; + $o['Automated'] = $result['is_automated']; + $o['Stars'] = $result['star_count']; + $o['Official'] = $result['is_official']; + $o['Trusted'] = $result['is_trusted']; + if ( $o['Official'] ) { + $o['DockerHub'] = "https://hub.docker.com/_/".$result['name']."/"; + $o['Name'] = $o['Author']; + } else { + $o['DockerHub'] = "https://hub.docker.com/r/".$result['name']."/"; + } + $o['ID'] = $i; + $searchName = str_replace("docker-","",$o['Name']); + $searchName = str_replace("-docker","",$searchName); + + $dockerResults[$i] = $o; + $i=++$i; + } + $dockerFile['num_pages'] = $num_pages; + $dockerFile['page_number'] = $pageNumber; + $dockerFile['results'] = $dockerResults; + + writeJsonFile($communityPaths['dockerSearchResults'],$dockerFile); + echo suggestSearch($filter,false); + displaySearchResults($pageNumber, $sortOrder['viewMode']); + break; + +##################################################################### +# # +# dismiss_warning - dismisses the warning from appearing at startup # +# # +##################################################################### +case 'dismiss_warning': + file_put_contents($communityPaths['warningAccepted'],"warning dismissed"); + break; + +############################################################### +# # +# Displays the list of installed or previously installed apps # +# # +############################################################### +case 'previous_apps': + $installed = getPost("installed",""); + $dockerUpdateStatus = readJsonFile($communityPaths['dockerUpdateStatus']); + + $moderation = ( is_file($communityPaths['moderation']) ) ? readJsonFile($communityPaths['moderation']) : array(); + + $DockerClient = new DockerClient(); + $info = $DockerClient->getDockerContainers(); + $file = readJsonFile($communityPaths['community-templates-info']); + +# $info contains all installed containers + +# now correlate that to a template; +# this section handles containers that have not been renamed from the appfeed + if ( $installed == "true" ) { + foreach ($info as $installedDocker) { + $installedImage = $installedDocker['Image']; + $installedName = $installedDocker['Name']; + + foreach ($file as $template) { + if ( $installedName == $template['Name'] ) { + $template['testrepo'] = $installedImage; + if ( startsWith($installedImage,$template['Repository']) ) { + $template['Uninstall'] = true; + $template['MyPath'] = $template['Path']; + if ( $dockerUpdateStatus[$installedImage]['status'] == "false" || $dockerUpdateStatus[$template['Name']] == "false" ) { + $template['UpdateAvailable'] = true; + $template['FullRepo'] = $installedImage; + } + if ($template['Blacklist'] ) { + continue; + } + $displayed[] = $template; + break; + } + } + } + } + $all_files = dirContents("/boot/config/plugins/dockerMan/templates-user"); + +# handle renamed containers + foreach ($all_files as $xmlfile) { + if ( pathinfo($xmlfile,PATHINFO_EXTENSION) == "xml" ) { + $o = readXmlFile("/boot/config/plugins/dockerMan/templates-user/$xmlfile",$moderation); + $o['MyPath'] = "/boot/config/plugins/dockerMan/templates-user/$xmlfile"; + $o['UnknownCompatible'] = true; + + if ( is_array($moderation[$o['Repository']]) ) { + $o = array_merge($o, $moderation[$o['Repository']]); + } + $flag = false; + $containerID = false; + foreach ($file as $templateDocker) { +# use startsWith to eliminate any version tags (:latest) + if ( startsWith($templateDocker['Repository'], $o['Repository']) ) { + if ( $templateDocker['Name'] == $o['Name'] ) { + $flag = true; + $containerID = $template['ID']; + break; + } + } + } + if ( ! $flag ) { + $runningflag = false; + foreach ($info as $installedDocker) { + $installedImage = $installedDocker['Image']; + $installedName = $installedDocker['Name']; + + if ( startsWith($installedImage, $o['Repository']) ) { + if ( $installedName == $o['Name'] ) { + $runningflag = true; + $searchResult = searchArray($file,'Repository',$o['Repository']); + if ( $searchResult !== false ) { + $tempPath = $o['MyPath']; + $containerID = $file[$searchResult]['ID']; + $o = $file[$searchResult]; + $o['Name'] = $installedName; + $o['MyPath'] = $tempPath; + $o['SortName'] = $installedName; + if ( $dockerUpdateStatus[$installedImage]['status'] == "false" || $dockerUpdateStatus[$template['Name']] == "false" ) { + $o['UpdateAvailable'] = true; + $o['FullRepo'] = $installedImage; + } + } + break;; + } + } + } + if ( $runningflag ) { + $o['Uninstall'] = true; + $o['ID'] = $containerID; + if ( $o['Blacklist'] ) { + continue; + } + $displayed[] = $o; + } + } + } + } + } else { +# now get the old not installed docker apps + + $all_files = dirContents("/boot/config/plugins/dockerMan/templates-user"); + + foreach ($all_files as $xmlfile) { + if ( pathinfo($xmlfile,PATHINFO_EXTENSION) == "xml" ) { + $o = readXmlFile("/boot/config/plugins/dockerMan/templates-user/$xmlfile"); + $o['MyPath'] = "/boot/config/plugins/dockerMan/templates-user/$xmlfile"; + $o['UnknownCompatible'] = true; + $o['Removable'] = true; +# is the container running? + + $flag = false; + foreach ($info as $installedDocker) { + $installedImage = $installedDocker['Image']; + $installedName = $installedDocker['Name']; + + if ( startsWith($installedImage, $o['Repository']) ) { + if ( $installedName == $o['Name'] ) { + $flag = true; + continue; + } + } + } + if ( ! $flag ) { +# now associate the template back to a template in the appfeed + foreach ($file as $appTemplate) { + if ($appTemplate['Repository'] == $o['Repository']) { + $tempPath = $o['MyPath']; + $tempName = $o['Name']; + $o = $appTemplate; + $o['Removable'] = true; + $o['MyPath'] = $tempPath; + $o['Name'] = $tempName; + break; + } + } + if ( $moderation[$o['Repository']]['Blacklist'] ) { + continue; + } + $displayed[] = $o; + } + } + } + } + +# Now work on plugins + + if ( $installed == "true" ) { + foreach ($file as $template) { + if ( ! $template['Plugin'] ) { + continue; + } + $filename = pathinfo($template['Repository'],PATHINFO_BASENAME); + + if ( file_exists("/var/log/plugins/$filename") ) { + if ( $template['Blacklist'] ) { + continue; + } + $template['MyPath'] = "/var/log/plugins/$filename"; + $template['Uninstall'] = true; + $template['UpdateAvailable'] = checkPluginUpdate($filename); + + $displayed[] = $template; + } + } + } else { + $all_plugs = dirContents("/boot/config/plugins-removed/"); + + foreach ($all_plugs as $oldplug) { + foreach ($file as $template) { + if ( $oldplug == pathinfo($template['Repository'],PATHINFO_BASENAME) ) { + if ( ! file_exists("/boot/config/plugins/$oldplug") ) { + if ( $template['Blacklist'] ) { + continue; + } + $template['Removable'] = true; + $template['MyPath'] = "/boot/config/plugins-removed/$oldplug"; + + $displayed[] = $template; + break; + } + } + } + } + } + + $displayedApplications['community'] = $displayed; + writeJsonFile($communityPaths['community-templates-displayed'],$displayedApplications); + echo "ok"; + break; + +#################################################################################### +# # +# Removes an app from the previously installed list (ie: deletes the user template # +# # +#################################################################################### +case 'remove_application': + $application = getPost("application",""); + @unlink($application); + echo "ok"; + break; + +####################### +# # +# Uninstalls a plugin # +# # +####################### +case 'uninstall_application': + $application = getPost("application",""); + + $filename = pathinfo($application,PATHINFO_BASENAME); + shell_exec("/usr/local/emhttp/plugins/dynamix.plugin.manager/scripts/plugin remove '$filename'"); + echo "ok"; + break; + +################################################################################### +# # +# Checks for an update still available (to update display) after update installed # +# # +################################################################################### +case 'updatePLGstatus': + $filename = getPost("filename",""); + $displayed = readJsonFile($communityPaths['community-templates-displayed']); + $superCategories = array_keys($displayed); + foreach ($superCategories as $category) { + foreach ($displayed[$category] as $template) { + if ( strpos($template['PluginURL'],$filename) ) { + $template['UpdateAvailable'] = checkPluginUpdate($filename); + } + $newDisplayed[$category][] = $template; + } + } + writeJsonFile($communityPaths['community-templates-displayed'],$newDisplayed); + echo "ok"; + break; + +####################### +# # +# Uninstalls a docker # +# # +####################### +case 'uninstall_docker': + $application = getPost("application",""); + +# get the name of the container / image + $doc = new DOMDocument(); + $doc->load($application); + $containerName = stripslashes($doc->getElementsByTagName( "Name" )->item(0)->nodeValue); + + $DockerClient = new DockerClient(); + $dockerInfo = $DockerClient->getDockerContainers(); + $container = searchArray($dockerInfo,"Name",$containerName); + +# stop the container + + shell_exec("docker stop $containerName"); + shell_exec("docker rm $containerName"); + shell_exec("docker rmi ".$dockerInfo[$container]['ImageId']); + + echo "Uninstalled"; + break; + +################################## +# # +# Deletes the appdata for an app # +# # +################################## +case 'remove_appdata': + $appdata = getPost("appdata",""); + $appdata = trim($appdata); + + $commandLine = $communityPaths['deleteAppdataScript'].' "'.$appdata.'" > /dev/null | at NOW -M >/dev/null 2>&1'; + exec($commandLine); + break; + +################################################## +# # +# Pins / Unpins an application for later viewing # +# # +################################################## +case "pinApp": + $repository = getPost("repository","oops"); + $pinnedApps = readJsonFile($communityPaths['pinned']); + if ( $pinnedApps[$repository] ) { + unset($pinnedApps[$repository]); + } else { + $pinnedApps[$repository] = $repository; + } + writeJsonFile($communityPaths['pinned'],$pinnedApps); + writeJsonFile($communityPaths['pinnedRam'],$pinnedApps); + break; + +#################################### +# # +# Displays the pinned applications # +# # +#################################### +case "pinnedApps": + $pinnedApps = getPinnedApps(); + $file = readJsonFile($communityPaths['community-templates-info']); + + foreach ($pinnedApps as $pinned) { + $index = searchArray($file,"Repository",$pinned); + if ( $index === false ) { + continue; + } else { + $displayed[] = $file[$index]; + } + } + $displayedApplications['community'] = $displayed; + $displayedApplications['pinnedFlag'] = true; + writeJsonFile($communityPaths['community-templates-displayed'],$displayedApplications); + echo "fini!"; + break; + +################################################ +# # +# Displays the possible branch tags for an app # +# # +################################################ +case 'displayTags': + $leadTemplate = getPost("leadTemplate","oops"); + $file = readJsonFile($communityPaths['community-templates-info']); + $template = $file[$leadTemplate]; + $childTemplates = $file[$leadTemplate]['BranchID']; + if ( ! is_array($childTemplates) ) { + echo "Something really went wrong here"; + } else { + $defaultTag = $template['BranchDefault'] ? $template['BranchDefault'] : "latest"; + echo ""; + echo ""; + foreach ($childTemplates as $child) { + echo ""; + } + echo "
      DefaultInstall Using The Template's Default Tag (:$defaultTag)
      ".$file[$child]['BranchName']."".$file[$child]['BranchDescription']."
"; + } + break; + +################################################ +# # +# Specialized search for additional CA Modules # +# # +################################################ +case 'populateModules': + $file = readJsonFile($communityPaths['community-templates-info']); + foreach ($file as $template) { + if ($template['CA']) { + if ( ! $template['Compatible'] ) { + continue; + } + $filename = basename($template['PluginURL']); + if ( is_file("/var/log/plugins/$filename") ) { + $template['MyPath'] = "/var/log/plugins/$filename"; + $template['Uninstall'] = true; + } + $displayed['community'][] = $template; + } + } + writeJsonFile($communityPaths['community-templates-displayed'],$displayed); + echo "done"; + break; + +########################################### +# # +# Displays The Statistics For The Appfeed # +# # +########################################### +case 'statistics': + $statistics = readJsonFile($communityPaths['statistics']); + if ( ! $statistics ) { $statistics = array(); } + + $statistics['totalModeration'] = count(readJsonFile($communityPaths['moderation'])); + + $templates = readJsonFile($communityPaths['community-templates-info']); + if ( is_array($templates) ) { + foreach ($templates as $template) { + if ( $template['Deprecated'] ) { + $statistics['totalDeprecated']++; + $deprecated .= "{$template['Repo']}{$template['Name']}".str_replace("
","",trim($template['ModeratorComment'])).""; + } + if ( ! $template['Compatible'] ) { + $statistics['totalIncompatible']++; + $incompatible .= "{$template['Repo']}{$template['Name']}
{$template['MinVer']}
{$template['MaxVer']}"; + } + if ( ! $template['Support'] ) { + $statistics['NoSupport']++; + $noSupport .= "{$template['Repo']}{$template['Name']}"; + } + if ( ! $template['Description'] && ! $template['Overview'] ) { + $statistics['NoDescription']++; + file_put_contents("/tmp/noDescription",$template['Repository'],FILE_APPEND); + } + } + } + if ( $incompatible ) { + $incompatible = "$incompatible
RepositoryApplicationMinimum OSMaximum OS
"; + file_put_contents($communityPaths['totalIncompatible_txt'],$incompatible); + } else { + @unlink($communityPaths['totalIcompatible_txt']); + } + if ( $deprecated ) { + $deprecated = "$deprecated
RepositoryApplicationComment
"; + file_put_contents($communityPaths['totalDeprecated_txt'],$deprecated); + } else { + @unlink($communityPaths['totalDeprecated_txt']); + } + if ( $noSupport ) { + $noSupport = "$noSupport
"; + file_put_contents($communityPaths['noSupport_txt'],$noSupport); + } else { + @unlink($communityPaths['noSupport_txt']); + } + foreach ($statistics as &$stat) { + if ( ! $stat ) { $stat = "0"; } + } + if ( $statistics['fixedTemplates'] ) { + writeJsonFile($communityPaths['fixedTemplates_txt'],$statistics['fixedTemplates']); + } else { + @unlink($communityPaths['fixedTemplates_txt']); + } + if ( is_file($communityPaths['lastUpdated-old']) ) { + $appFeedTime = readJsonFile($communityPaths['lastUpdated-old']); + } else { + $appFeedTime['last_updated_timestamp'] = filemtime($communityPaths['community-templates-info']); + } + $updateTime = date("F d Y H:i",$appFeedTime['last_updated_timestamp']); + $updateTime = ( is_file($communityPaths['LegacyMode']) ) ? "N/A - Legacy Mode Active" : $updateTime; + $defaultArray = Array('caFixed' => 0,'totalApplications' => 0, 'repository' => 0, 'docker' => 0, 'plugin' => 0, 'invalidXML' => 0, 'blacklist' => 0, 'totalIncompatible' =>0, 'totalDeprecated' => 0, 'totalModeration' => 0, 'private' => 0, 'NoSupport' => 0); + $statistics = array_merge($defaultArray,$statistics); + + foreach ($statistics as &$stat) { + if ( ! $stat ) { + $stat = "0"; + } + } + + $color = ""; + echo "

Community Applications
"; + echo "
Application Feed Statistics


"; + echo ""; + echo ""; + echo ""; + echo ""; + echo ""; + echo ""; + echo ""; + echo ""; + echo ""; + echo ""; + echo ""; + echo ""; + echo ""; + echo ""; + echo "
{$color}Application List Current As Of$color$updateTime
{$color}Total Number Of Templates$color{$statistics['totalApplications']}
{$color}Total Number Of Repositories$color{$statistics['repository']}
{$color}Total Number Of Docker Applications$color{$statistics['docker']}
{$color}Total Number Of Plugins$color{$statistics['plugin']}
{$color}Total Number Of Private Docker Applications$color{$statistics['private']}
{$color}Total Number Of Invalid Templates Found$color{$statistics['invalidXML']}
{$color}Total Number Of Template Errors Fixed Automatically$color{$statistics['caFixed']}
{$color}Total Number Of Blacklisted Apps Found In Appfeed$color{$statistics['blacklist']}
{$color}Total Number Of Incompatible Applications$color{$statistics['totalIncompatible']}
{$color}Total Number Of Deprecated Applications$color{$statistics['totalDeprecated']}
{$color}Total Number Of Moderation Entries$color{$statistics['totalModeration']}
{$color}Applications without any support thread:$color{$statistics['NoSupport']}
"; + echo "
"; + echo "
Ensuring only safe applications are present is a full time job

"; + break; + +##################################################################################### +# # +# Updates The maxPerPage setting (maxPerPage is already grabbed globally from POST) # +# # +##################################################################################### +case 'changeSettings': + file_put_contents($communityPaths['pluginSettings'],create_ini_file($communitySettings,false)); + echo "settings updated"; + break; + +########################################## +# # +# Updates the viewMode for next instance # +# # +########################################## +case 'changeViewModeSettings': + $communitySettings['viewMode'] = getPost("view",$communitySettings['viewMode']); + file_put_contents($communityPaths['pluginSettings'],create_ini_file($communitySettings,false)); + echo "ok"; + break; +} +?> \ No newline at end of file diff --git a/source/community.applications/usr/local/emhttp/plugins/community.applications/include/helpers.php b/source/community.applications/usr/local/emhttp/plugins/community.applications/include/helpers.php new file mode 100644 index 00000000..057ecd2c --- /dev/null +++ b/source/community.applications/usr/local/emhttp/plugins/community.applications/include/helpers.php @@ -0,0 +1,704 @@ +$defaultFlag, "two"=>$defaultFlag, "three"=>$defaultFlag # +# # +################################################################################################################## + +function arrayEntriesToObject($sourceArray,$defaultFlag=true) { + if ( ! is_array($sourceArray) ) { + return array(); + } + foreach ($sourceArray as $entry) { + $newArray[$entry] = $defaultFlag; + } + return $newArray; +} + +#################################################################################################### +# # +# 2 Functions because unRaid includes comments in .cfg files starting with # in violation of PHP 7 # +# # +#################################################################################################### +function my_parse_ini_file($file,$mode=false,$scanner_mode=INI_SCANNER_NORMAL) { + return parse_ini_string(preg_replace('/^#.*\\n/m', "", @file_get_contents($file)),$mode,$scanner_mode); +} + +function my_parse_ini_string($string, $mode=false,$scanner_mode=INI_SCANNER_NORMAL) { + return parse_ini_string(preg_replace('/^#.*\\n/m', "", $string),$mode,$scanner_mode); +} + +########################################################################### +# # +# Helper function to determine if a plugin has an update available or not # +# # +########################################################################### +function checkPluginUpdate($filename) { + global $unRaidVersion; + + $filename = basename($filename); + $installedVersion = plugin("version","/var/log/plugins/$filename"); + $upgradeVersion = (is_file("/tmp/plugins/$filename")) ? plugin("version","/tmp/plugins/$filename") : "0"; + + if ( $installedVersion < $upgradeVersion ) { + $unRaid = plugin("unRAID","/tmp/plugins/$filename"); + if ( $unRaid === false || version_compare($unRaidVersion,$unRaid,">=") ) { + return true; + } else { + return false; + } + } + return false; +} + +############################################################# +# # +# Helper function to return an array of directory contents. # +# Returns an empty array if the directory does not exist # +# # +############################################################# +function dirContents($path) { + $dirContents = @scandir($path); + if ( ! $dirContents ) { $dirContents = array(); } + return array_diff($dirContents,array(".","..")); +} + +################################################################################### +# # +# returns a random file name (/tmp/community.applications/tempFiles/34234234.tmp) # +# # +################################################################################### +function randomFile() { + global $communityPaths; + + return tempnam($communityPaths['tempFiles'],"CA-Temp-"); +} + +################################################################## +# # +# 2 Functions to avoid typing the same lines over and over again # +# # +################################################################## +function readJsonFile($filename) { + return json_decode(@file_get_contents($filename),true); +} + +function writeJsonFile($filename,$jsonArray) { + file_put_contents($filename,json_encode($jsonArray, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT)); +} + +############################################### +# # +# Helper function to download a URL to a file # +# # +############################################### +function download_url($url, $path = "", $bg = false){ + exec("curl --compressed --max-time 60 --silent --insecure --location --fail ".($path ? " -o '$path' " : "")." $url ".($bg ? ">/dev/null 2>&1 &" : "2>/dev/null"), $out, $exit_code ); + return ($exit_code === 0 ) ? implode("\n", $out) : false; +} + +######################################################## +# # +# Helper function to get the plugin's launch entitity. # +# # +######################################################## +function getPluginLaunch($pluginName) { + return plugin("launch","/var/log/plugins/$pluginName"); +} + +################################################################# +# # +# Helper function to determine if $haystack begins with $needle # +# # +################################################################# +function startsWith($haystack, $needle) { + return $needle === "" || strripos($haystack, $needle, -strlen($haystack)) !== FALSE; +} + +####################################################################################### +# # +# Helper function to further remove formatting from descriptions (suitable for popUps # +# # +####################################################################################### +function fixPopUpDescription($PopUpDescription) { + $PopUpDescription = str_replace("'","'",$PopUpDescription); + $PopUpDescription = str_replace('"','"',$PopUpDescription); + $PopUpDescription = strip_tags($PopUpDescription); + $PopUpDescription = trim($PopUpDescription); + return ($PopUpDescription); +} + +################################################################### +# # +# Helper function to remove any formatting, etc from descriptions # +# # +################################################################### +function fixDescription($Description) { + $Description = preg_replace("#\[br\s*\]#i", "{}", $Description); + $Description = preg_replace("#\[b[\\\]*\s*\]#i", "||", $Description); + $Description = preg_replace('#\[([^\]]*)\]#', '<$1>', $Description); + $Description = preg_replace("#]*>#i", '', $Description); + $Description = preg_replace("#"."{}"."#i", '
', $Description); + $Description = preg_replace("#"."\|\|"."#i", '', $Description); + $Description = str_replace("<","<",$Description); + $Description = str_replace(">",">",$Description); + $Description = strip_tags($Description); + $Description = trim($Description); + return $Description; +} + +######################################################################## +# # +# Security function to remove any #is',$tempElement) || preg_match('#(.*?)#is',$tempElement) ) { + logger("Alert the maintainers of Community Applications with the following Information:".$originalTemplate['RepoName']." ".$originalTemplate['Name']." ".$originalTemplate['Repository']); + $originalTemplate['Blacklist'] = true; + return; + } + } + } +} + +####################### +# # +# Custom sort routine # +# # +####################### +function mySort($a, $b) { + global $sortOrder; + + if ( $sortOrder['sortBy'] != "downloads" ) { + $c = strtolower($a[$sortOrder['sortBy']]); + $d = strtolower($b[$sortOrder['sortBy']]); + } else { + $c = $a[$sortOrder['sortBy']]; + $d = $b[$sortOrder['sortBy']]; + } + + $return1 = ($sortOrder['sortDir'] == "Down") ? -1 : 1; + $return2 = ($sortOrder['sortDir'] == "Down") ? 1 : -1; + + if ($c > $d) { return $return1; } + else if ($c < $d) { return $return2; } + else { return 0; } +} + +############################################### +# # +# Search array for a particular key and value # +# returns the index number of the array # +# return value === false if not found # +# # +############################################### +function searchArray($array,$key,$value) { + $result = false; + if (count($array) ) { + for ($i = 0; $i <= max(array_keys($array)); $i++) { + if ( $array[$i][$key] == $value ) { + $result = $i; + break; + } + } + } + return $result; +} + +############################# +# # +# Highlights search results # +# # +############################# +function highlight($text, $search) { + return preg_replace('#'. preg_quote($text,'#') .'#si', '\\0', $search); +} + +######################################################## +# # +# Fix common problems (maintainer errors) in templates # +# # +######################################################## +function fixTemplates($template) { + global $statistics; + + $origFixed = $statistics['caFixed']; +# this fix must always be the first test + if ( is_array($template['Repository']) ) { # due to cmer + $template['Repository'] = $template['Repository'][0]; + $statistics['caFixed']++; + $statistics['fixedTemplates'][$template['Repo']][$template['Repository']][] = "Fatal: Multiple Repositories Found - Removing application from lists"; + return false; + } + if ( (is_array($template['Support'])) && (count($template['Support'])) ) { + unset($template['Support']); + $statistics['caFixed']++; + $statistics['fixedTemplates'][$template['Repo']][$template['Repository']][] = "Multiple Support Tags Found"; + } + if ( ! is_string($template['Name']) ) { + $template['Name']=" "; + $statistics['caFixed']++; + $statistics['fixedTemplates'][$template['Repo']][$template['Repository']][] = "Name is not a string"; + } + if ( ! is_string($template['Author']) ) { + $template['Author']=" "; + $statistics['caFixed']++; + $statistics['fixedTemplates'][$template['Repo']][$template['Repository']][] = "Author is not a string"; + } + if ( is_array($template['Description']) ) { + $template['Description']=""; + if ( count($template['Description']) > 1 ) { + $statistics['fixedTemplates'][$template['Repo']][$template['Repository']][] = "Fatal: Multiple Description tags present"; + $statistics['caFixed']++; + return false; + } + } + if ( is_array($template['Beta']) ) { + $template['Beta'] = "false"; + $statistics['caFixed']++; + $statistics['fixedTemplates'][$template['Repo']][$template['Repository']][] = "Multiple Beta tags found"; + } else { + $template['Beta'] = strtolower(stripslashes($template['Beta'])); + } + $template['Date'] = ( $template['Date'] ) ? strtotime( $template['Date'] ) : 0; + + if ( ! $template['MinVer'] ) { + $template['MinVer'] = $template['Plugin'] ? "6.1" : "6.0"; + } + if ( is_array($template['Category']) ) { + $template['Category'] = $template['Category'][0]; # due to lsio / CHBMB + $statistics['caFixed']++; + $statistics['fixedTemplates'][$template['Repo']][$template['Repository']][] = "Multiple Category tags or Category present but empty"; + } + $template['Category'] = $template['Category'] ? $template['Category'] : "Uncategorized"; + if ( ! is_string($template['Category']) ) { + $template['Category'] = "Uncategorized"; + $statistics['caFixed']++; + $statistics['fixedTemplates'][$template['Repo']][$template['Repository']][] = "Multiple Category tags or Category present but empty"; + } + + if ( !is_string($template['Overview']) ) { + unset($template['Overview']); + } + if ( is_array($template['SortAuthor']) ) { # due to cmer + $template['SortAuthor'] = $template['SortAuthor'][0]; + $template['Author'] = $template['SortAuthor']; + $statistics['caFixed']++; + $statistics['fixedTemplates'][$template['Repo']][$template['Repository']][] = "Multiple Authors / Repositories Found"; + } + + if ( is_array($template['PluginURL']) ) { # due to coppit + $template['PluginURL'] = $template['PluginURL'][1]; + $statistics['caFixed']++; + $statistics['fixedTemplates'][$template['Repo']][$template['Repository']][] = "Fatal: Multiple PluginURL's found"; + return false; + } + if ( $template['PluginURL'] ) { # due to bonienl + $template['PluginURL'] = str_replace("raw.github.com","raw.githubusercontent.com",$template['PluginURL']); + $template['Repository'] = $template['PluginURL']; + } + if ( strlen($template['Overview']) > 0 ) { + $template['Description'] = $template['Overview']; + $template['Description'] = preg_replace('#\[([^\]]*)\]#', '<$1>', $template['Description']); + $template['Description'] = fixDescription($template['Description']); + $template['Overview'] = $template['Description']; + } else { + $template['Description'] = fixDescription($template['Description']); + } + if ( ( ! strlen(trim($template['Overview'])) ) && ( ! strlen(trim($template['Description'])) ) ){ + $statistics['caFixed']++; + $statistics['fixedTemplates'][$template['Repo']][$template['Repository']][] = "Fatal: No valid Overview Or Description present - Application dropped from CA automatically"; + return false; + } + if ( ( stripos($template['RepoName'],' beta') > 0 ) ) { + $template['Beta'] = "true"; + } + + $template['Support'] = validURL($template['Support']); + $template['Project'] = validURL($template['Project']); + $template['DonateLink'] = validURL($template['DonateLink']); + $template['DonateImg'] = validURL($template['DonateImg']); + $template['DonateText'] = str_replace("'","'",$template['DonateText']); + $template['DonateText'] = str_replace('"','"',$template['DonateText']); + + # support v6.2 redefining deprecating the tag and moving it to a category + if ( stripos($template['Category'],":Beta") ) { + $template['Beta'] = "true"; + } else { + if ( $template['Beta'] === "true" ) { + $template['Category'] .= " Status:Beta"; + } + } + $template['PopUpDescription'] = fixPopUpDescription($template['Description']); + return $template; +} + +############################################### +# # +# Function used to create XML's from appFeeds # +# # +############################################### +function makeXML($template) { + # ensure its a v2 template if the Config entries exist + if ( $template['Config'] ) { + if ( ! $template['@attributes'] ) { + $template['@attributes'] = array("version"=>2); + } + } + + # handle the case where there is only a single entry + if ( $template['Config']['@attributes'] ) { + $template['Config'][0]['@attributes'] = $template['Config']['@attributes']; + if ( $template['Config']['value']) { + $template['Config'][0]['value'] = $template['Config']['value']; + } + unset($template['Config']['@attributes']); + unset($template['Config']['value']); + } + + # hack to fix differing schema in the appfeed vs what Array2XML class wants + if ( $template['Config'] ) { + foreach ($template['Config'] as $tempArray) { + if ( $tempArray['value'] ) { + $tempArray2[] = array('@attributes'=>$tempArray['@attributes'],'@value'=>$tempArray['value']); + } else { + $tempArray2[] = array('@attributes'=>$tempArray['@attributes']); + } + } + $template['Config'] = $tempArray2; + } + $Array2XML = new Array2XML(); + $xml = $Array2XML->createXML("Container",$template); + return $xml->saveXML(); +} + +################################################################# +# # +# checks the Min/Max version of an app against unRaid's version # +# Returns: TRUE if it's valid to run, FALSE if not # +# # +################################################################# +function versionCheck($template) { + global $unRaidVersion; + + if ( $template['MinVer'] && ( version_compare($template['MinVer'],$unRaidVersion) > 0 ) ) { return false; } + if ( $template['MaxVer'] && ( version_compare($template['MaxVer'],$unRaidVersion) < 0 ) ) { return false; } + return true; +} + +############################################### +# # +# Function to read a template XML to an array # +# # +############################################### +function readXmlFile($xmlfile) { + global $statistics; + + $xml = file_get_contents($xmlfile); + $o = TypeConverter::xmlToArray($xml,TypeConverter::XML_GROUP); + if ( ! $o ) { return false; } + + # Fix some errors in templates prior to continuing + + if ( is_array($o['SortAuthor']) ) { + $o['SortAuthor'] = $o['SortAuthor'][0]; $statistics['caFixed']++; + } + if ( is_array($o['Repository']) ) { + $o['Repository'] = $o['Repository'][0]; $statistics['caFixed']++; + } + $o['Path'] = $xmlfile; + $o['Author'] = preg_replace("#/.*#", "", $o['Repository']); + $o['DockerHubName'] = strtolower($o['Name']); + $o['Base'] = $o['BaseImage']; + $o['SortAuthor'] = $o['Author']; + $o['SortName'] = $o['Name']; + $o['Forum'] = $Repo['forum']; +# configure the config attributes to same format as appfeed +# handle the case where there is only a single entry + + if ( $o['Config']['@attributes'] ) { + $o['Config'] = array('@attributes'=>$o['Config']['@attributes'],'value'=>$o['Config']['value']); + } + if ( $o['Plugin'] ) { + $o['Author'] = $o['PluginAuthor']; + $o['Repository'] = $o['PluginURL']; + $o['Category'] .= " Plugins: "; + $o['SortAuthor'] = $o['Author']; + $o['SortName'] = $o['Name']; + $statistics['plugin']++; + } else { + $statistics['docker']++; + } + return $o; +} + +################################################################### +# # +# Function To Merge Moderation into templates array # +# (Because moderation can be updated when templates are not ) # +# If appfeed is updated, this is done when creating the templates # +# # +################################################################### +function moderateTemplates() { + global $communityPaths; + + $templates = readJsonFile($communityPaths['community-templates-info']); + $moderation = readJsonFile($communityPaths['moderation']); + if ( ! $templates ) { return; } + foreach ($templates as $template) { + if ( is_array($moderation[$template['Repository']]) ) { + $o[] = array_merge($template,$moderation[$template['Repository']]); + } else { + $o[] = $template; + } + } + writeJsonFile($communityPaths['community-templates-info'],$o); +} + +############################################ +# # +# Function to write a string to the syslog # +# # +############################################ +function logger($string) { + shell_exec("logger ".escapeshellarg($string)); +} + +########################################### +# # +# Function to send a dynamix notification # +# # +########################################### +function notify($event,$subject,$description,$message,$type="normal") { + $command = '/usr/local/emhttp/plugins/dynamix/scripts/notify -e "'.$event.'" -s "'.$subject.'" -d "'.$description.'" -m "'.$message.'" -i "'.$type.'"'; + shell_exec($command); +} + +####################################################### +# # +# Function to check for a valid URL # +# # +####################################################### +function validURL($URL) { + if ( function_exists("filter_var") ) { # function only works on unRaid 6.1.8+ + return filter_var($URL, FILTER_VALIDATE_URL); + } else { + return $URL; + } +} + +#################################################################################### +# # +# Read the pinned apps from temp files. If it fails, gets it from the flash drive # +# # +#################################################################################### +function getPinnedApps() { + global $communityPaths; + + $pinnedApps = readJsonFile($communityPaths['pinnedRam']); + if ( ! $pinnedApps ) { + $pinnedApps = readJsonFile($communityPaths['pinned']); + } + return $pinnedApps; +} + +######################################################## +# # +# Avoids having to write this line over and over again # +# # +######################################################## +function getPost($setting,$default) { + return isset($_POST[$setting]) ? urldecode(($_POST[$setting])) : $default; +} +function getPostArray($setting) { + return $_POST[$setting]; +} +function getSortOrder($sortArray) { + foreach ($sortArray as $sort) { + $sortOrder[$sort[0]] = $sort[1]; + } + return $sortOrder; +} + +################################################# +# # +# Sets the updateButton to the appropriate Mode # +# # +################################################# +function caGetMode() { + global $communityPaths; + + $caMode = ( is_file($communityPaths['LegacyMode']) ) ? "appFeed Mode" : "Legacy Mode"; + return ""; +} + +################################################ +# # +# Returns the actual URL after any redirection # +# # +################################################ +# works, but very slow. Switched to a simple string replace as all redirects are plugin and simply github.com/raw/ vs raw.github.usercontent/ +function getRedirectedURL($url) { + $ch = curl_init(); + curl_setopt($ch, CURLOPT_URL, $url); + curl_setopt($ch, CURLOPT_HEADER, true); + curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); + $a = curl_exec($ch); + return curl_getinfo($ch, CURLINFO_EFFECTIVE_URL); +} + +########################################################### +# # +# Returns the maximum number of columns per display width # +# # +########################################################### +function getMaxColumns($windowWidth) { + global $communitySettings, $templateSkin, $unRaid64; + + if ( ! $unRaid64 ) { + $communitySettings['maxDetailColumns'] = 2; + $communitySettings['maxIconColumns'] = 5; + return; + } + $communitySettings['windowWidth'] = $windowWidth; + $communitySettings['maxDetailColumns'] = floor($windowWidth / $templateSkin['detail']['templateWidth']); + $communitySettings['maxIconColumns'] = floor($windowWidth / $templateSkin['icon']['templateWidth']); + if ( ! $communitySettings['maxDetailColumns'] ) $communitySettings['maxDetailColumns'] = 1; + if ( ! $communitySettings['maxIconColumns'] ) $communitySettings['maxIconColumns'] = 1; +} + +####################### +# # +# Creates an ini file # +# # +####################### +function create_ini_file($settings,$mode=false) { + if ( $mode ) { + $keys = array_keys($settings); + + foreach ($keys as $key) { + $iniFile .= "[$key]\r\n"; + $entryKeys = array_keys($settings[$key]); + foreach ($entryKeys as $entry) { + $iniFile .= $entry.'="'.$settings[$key][$entry].'"'."\r\n"; + } + } + } else { + $entryKeys = array_keys($settings); + foreach ($entryKeys as $entry) { + $iniFile .= $entry.'="'.$settings[$entry].'"'."\r\n"; + } + } + return $iniFile; +} + +############################################################################ +# # +# Function to convert a template's associative tags to static numeric tags # +# (Because the associate tag order can change depending upon the template) # +# # +############################################################################ +function toNumericArray($template) { + return array( + $template['Repository'], # 1 + $template['Author'], # 2 + $template['Name'], # 3 + $template['DockerHubName'], # 4 + $template['Beta'], # 5 + $template['Changes'], # 6 + $template['Date'], # 7 + $template['RepoName'], # 8 + $template['Project'], # 9 + $template['ID'], #10 + $template['Base'], #11 + $template['BaseImage'], #12 + $template['SortAuthor'], #13 + $template['SortName'], #14 + $template['Licence'], #15 + $template['Plugin'], #16 + $template['PluginURL'], #17 + $template['PluginAuthor'], #18 + $template['MinVer'], #19 + $template['MaxVer'], #20 + $template['Category'], #21 + $template['Description'], #22 + $template['Overview'], #23 + $template['Downloads'], #24 + $template['Stars'], #25 + $template['Announcement'], #26 + $template['Support'], #27 + $template['IconWeb'], #28 + $template['DonateText'], #29 + $template['DonateImg'], #30 + $template['DonateLink'], #31 + $template['PopUpDescription'], #32 + $template['ModeratorComment'], #33 + $template['Compatible'], #34 + $template['display_DonateLink'], #35 + $template['display_Project'], #36 + $template['display_Support'], #37 + $template['display_UpdateAvailable'], #38 + $template['display_ModeratorComment'],#39 + $template['display_Announcement'], #40 + $template['display_Stars'], #41 + $template['display_Downloads'], #42 + $template['display_pinButton'], #43 + $template['display_Uninstall'], #44 + $template['display_removable'], #45 + $template['display_newIcon'], #46 + $template['display_changes'], #47 + $template['display_webPage'], #48 + $template['display_humanDate'], #49 + $template['display_pluginSettings'], #50 + $template['display_pluginInstall'], #51 + $template['display_dockerDefault'], #52 + $template['display_dockerEdit'], #53 + $template['display_dockerReinstall'], #54 + $template['display_dockerInstall'], #55 + $template['display_dockerDisable'], #56 + $template['display_compatible'], #57 + $template['display_compatibleShort'], #58 + $template['display_author'], #59 + $template['display_iconSmall'], #60 + $template['display_iconSelectable'], #61 + $template['display_popupDesc'], #62 + $template['display_updateAvail'], #63 *** NO LONGER USED - USE #38 instead + $template['display_dateUpdated'], #64 + $template['display_iconClickable'], #65 + str_replace("-"," ",$template['display_dockerName']), #66 + $template['Path'], #67 + $template['display_pluginInstallIcon'],#68 + $template['display_dockerDefaultIcon'],#69 + $template['display_dockerEditIcon'], #70 + $template['display_dockerReinstallIcon'], #71 + $template['display_dockerInstallIcon'], #72 + $template['display_pluginSettingsIcon'], #73 + $template['dockerWebIcon'], #74 + $template['display_multi_install'] #75 + ); +} + + + + +?> diff --git a/source/community.applications/usr/local/emhttp/plugins/community.applications/include/manualExec.php b/source/community.applications/usr/local/emhttp/plugins/community.applications/include/manualExec.php new file mode 100644 index 00000000..45b7f685 --- /dev/null +++ b/source/community.applications/usr/local/emhttp/plugins/community.applications/include/manualExec.php @@ -0,0 +1,17 @@ +/dev/null 2>&1 &" : "2>/dev/null"), $out, $exit_code ); + return ($exit_code === 0 ) ? implode("\n", $out) : false; +} + +function randomFile() { + return tempnam("/tmp","CA-Temp-"); +} + +$filename = randomFile(); +download_url("https://raw.githubusercontent.com/Squidly271/ca.documentation/master/caDocumentation.html",$filename); +$manual = @file_get_contents($filename); +$manual = $manual ? $manual : "Unable to download manual. Try again later"; +@unlink($filename); +echo $manual; +?> \ No newline at end of file diff --git a/source/community.applications/usr/local/emhttp/plugins/community.applications/include/paths.php b/source/community.applications/usr/local/emhttp/plugins/community.applications/include/paths.php new file mode 100644 index 00000000..d74cdfa1 --- /dev/null +++ b/source/community.applications/usr/local/emhttp/plugins/community.applications/include/paths.php @@ -0,0 +1,67 @@ + diff --git a/source/community.applications/usr/local/emhttp/plugins/community.applications/include/xmlHelpers.php b/source/community.applications/usr/local/emhttp/plugins/community.applications/include/xmlHelpers.php new file mode 100644 index 00000000..12e0b0ed --- /dev/null +++ b/source/community.applications/usr/local/emhttp/plugins/community.applications/include/xmlHelpers.php @@ -0,0 +1,786 @@ + <'. $root .'>'); + $response = self::buildXml($xml, $array); + + return $response->asXML(); + } + + return $resource; + } + + /** + * Turn an object into an array. Alternative to array_map magic. + * + * @access public + * @param object $object + * @return array + */ + public static function buildArray($object) { + $array = array(); + + foreach ($object as $key => $value) { + if (is_object($value)) { + $array[$key] = self::buildArray($value); + } else { + $array[$key] = $value; + } + } + + return $array; + } + + /** + * Turn an array into an object. Alternative to array_map magic. + * + * @access public + * @param array $array + * @return object + */ + public static function buildObject($array) { + $obj = new \stdClass(); + + foreach ($array as $key => $value) { + if (is_array($value)) { + $obj->{$key} = self::buildObject($value); + } else { + $obj->{$key} = $value; + } + } + + return $obj; + } + + /** + * Turn an array into an XML document. Alternative to array_map magic. + * + * @access public + * @param object $xml + * @param array $array + * @return object + */ + public static function buildXml(&$xml, $array) { + if (is_array($array)) { + foreach ($array as $key => $value) { + // XML_NONE + if (!is_array($value)) { + $xml->addChild($key, $value); + continue; + } + + // Multiple nodes of the same name + if (isset($value[0])) { + foreach ($value as $kValue) { + if (is_array($kValue)) { + self::buildXml($xml, array($key => $kValue)); + } else { + $xml->addChild($key, $kValue); + } + } + + // XML_GROUP + } else if (isset($value['@attributes'])) { + if (is_array($value['value'])) { + $node = $xml->addChild($key); + self::buildXml($node, $value['value']); + } else { + $node = $xml->addChild($key, $value['value']); + } + + if (!empty($value['@attributes'])) { + foreach ($value['@attributes'] as $aKey => $aValue) { + $node->addAttribute($aKey, $aValue); + } + } + + // XML_MERGE + } else if (isset($value['value'])) { + $node = $xml->addChild($key, $value['value']); + unset($value['value']); + + if (!empty($value)) { + foreach ($value as $aKey => $aValue) { + if (is_array($aValue)) { + self::buildXml($node, array($aKey => $aValue)); + } else { + $node->addAttribute($aKey, $aValue); + } + } + } + + // XML_OVERWRITE + } else { + $node = $xml->addChild($key); + + if (!empty($value)) { + foreach ($value as $aKey => $aValue) { + if (is_array($aValue)) { + self::buildXml($node, array($aKey => $aValue)); + } else { + $node->addChild($aKey, $aValue); + } + } + } + } + } + } + + return $xml; + } + + /** + * Convert a SimpleXML object into an array. + * + * @access public + * @param object $xml + * @param int $format + * @return array + */ + public static function xmlToArray($xml, $format = self::XML_GROUP) { + if (is_string($xml)) { + $xml = @simplexml_load_string($xml); + } + if ( ! $xml ) { return false; } + if (count($xml->children()) <= 0) { + return (string)$xml; + } + + $array = array(); + + foreach ($xml->children() as $element => $node) { + $data = array(); + + if (!isset($array[$element])) { +# $array[$element] = ""; +$array[$element] = []; + } + + if (!$node->attributes() || $format === self::XML_NONE) { + $data = self::xmlToArray($node, $format); + + } else { + switch ($format) { + case self::XML_GROUP: + $data = array( + '@attributes' => array(), + 'value' => (string)$node + ); + + if (count($node->children()) > 0) { + $data['value'] = self::xmlToArray($node, $format); + } + + foreach ($node->attributes() as $attr => $value) { + $data['@attributes'][$attr] = (string)$value; + } + break; + + case self::XML_MERGE: + case self::XML_OVERWRITE: + if ($format === self::XML_MERGE) { + if (count($node->children()) > 0) { + $data = $data + self::xmlToArray($node, $format); + } else { + $data['value'] = (string)$node; + } + } + + foreach ($node->attributes() as $attr => $value) { + $data[$attr] = (string)$value; + } + break; + } + } + + if (count($xml->{$element}) > 1) { + $array[$element][] = $data; + } else { + $array[$element] = $data; + } + } + + return $array; + } + + /** + * Encode a resource object for UTF-8. + * + * @access public + * @param mixed $data + * @return array|string + * @static + */ + public static function utf8Encode($data) { + if (is_string($data)) { + return utf8_encode($data); + + } else if (is_array($data)) { + foreach ($data as $key => $value) { + $data[utf8_encode($key)] = self::utf8Encode($value); + } + + } else if (is_object($data)) { + foreach ($data as $key => $value) { + $data->{$key} = self::utf8Encode($value); + } + } + + return $data; + } + + /** + * Decode a resource object for UTF-8. + * + * @access public + * @param mixed $data + * @return array|string + * @static + */ + public static function utf8Decode($data) { + if (is_string($data)) { + return utf8_decode($data); + + } else if (is_array($data)) { + foreach ($data as $key => $value) { + $data[utf8_decode($key)] = self::utf8Decode($value); + } + + } else if (is_object($data)) { + foreach ($data as $key => $value) { + $data->{$key} = self::utf8Decode($value); + } + } + + return $data; + } + +} + + /** + * Array2XML: A class to convert array in PHP to XML + * It also takes into account attributes names unlike SimpleXML in PHP + * It returns the XML in form of DOMDocument class for further manipulation. + * It throws exception if the tag name or attribute name has illegal chars. + * + * Author : Lalit Patel + * Website: http://www.lalit.org/lab/convert-php-array-to-xml-with-attributes + * License: Apache License 2.0 + * http://www.apache.org/licenses/LICENSE-2.0 + * Version: 0.1 (10 July 2011) + * Version: 0.2 (16 August 2011) + * - replaced htmlentities() with htmlspecialchars() (Thanks to Liel Dulev) + * - fixed a edge case where root node has a false/null/0 value. (Thanks to Liel Dulev) + * Version: 0.3 (22 August 2011) + * - fixed tag sanitize regex which didn't allow tagnames with single character. + * Version: 0.4 (18 September 2011) + * - Added support for CDATA section using @cdata instead of @value. + * Version: 0.5 (07 December 2011) + * - Changed logic to check numeric array indices not starting from 0. + * Version: 0.6 (04 March 2012) + * - Code now doesn't @cdata to be placed in an empty array + * Version: 0.7 (24 March 2012) + * - Reverted to version 0.5 + * Version: 0.8 (02 May 2012) + * - Removed htmlspecialchars() before adding to text node or attributes. + * + * Usage: + * $xml = Array2XML::createXML('root_node_name', $php_array); + * echo $xml->saveXML(); + */ +class Array2XML { + private static $xml = null; + private static $encoding = 'UTF-8'; + /** + * Initialize the root XML node [optional] + * @param $version + * @param $encoding + * @param $format_output + */ + public static function init($version = '1.0', $encoding = 'UTF-8', $format_output = true) { + self::$xml = new DomDocument($version, $encoding); + self::$xml->formatOutput = $format_output; + self::$encoding = $encoding; + } + /** + * Convert an Array to XML + * @param string $node_name - name of the root node to be converted + * @param array $arr - aray to be converterd + * @return DomDocument + */ + public static function &createXML($node_name, $arr=array()) { + $xml = self::getXMLRoot(); + $xml->appendChild(self::convert($node_name, $arr)); + self::$xml = null; // clear the xml node in the class for 2nd time use. + return $xml; + } + /** + * Convert an Array to XML + * @param string $node_name - name of the root node to be converted + * @param array $arr - aray to be converterd + * @return DOMNode + */ + private static function &convert($node_name, $arr=array()) { + //print_arr($node_name); + $xml = self::getXMLRoot(); + $node = $xml->createElement($node_name); + if(is_array($arr)){ + // get the attributes first.; + if(isset($arr['@attributes'])) { + foreach($arr['@attributes'] as $key => $value) { + if(!self::isValidTagName($key)) { + throw new Exception('[Array2XML] Illegal character in attribute name. attribute: '.$key.' in node: '.$node_name); + } + $node->setAttribute($key, self::bool2str($value)); + } + unset($arr['@attributes']); //remove the key from the array once done. + } + // check if it has a value stored in @value, if yes store the value and return + // else check if its directly stored as string + if(isset($arr['@value'])) { + $node->appendChild($xml->createTextNode(self::bool2str($arr['@value']))); + unset($arr['@value']); //remove the key from the array once done. + //return from recursion, as a note with value cannot have child nodes. + return $node; + } else if(isset($arr['@cdata'])) { + $node->appendChild($xml->createCDATASection(self::bool2str($arr['@cdata']))); + unset($arr['@cdata']); //remove the key from the array once done. + //return from recursion, as a note with cdata cannot have child nodes. + return $node; + } + } + //create subnodes using recursion + if(is_array($arr)){ + // recurse to get the node for that key + foreach($arr as $key=>$value){ + if(!self::isValidTagName($key)) { + throw new Exception('[Array2XML] Illegal character in tag name. tag: '.$key.' in node: '.$node_name); + } + if(is_array($value) && is_numeric(key($value))) { + // MORE THAN ONE NODE OF ITS KIND; + // if the new array is numeric index, means it is array of nodes of the same kind + // it should follow the parent key name + foreach($value as $k=>$v){ + $node->appendChild(self::convert($key, $v)); + } + } else { + // ONLY ONE NODE OF ITS KIND + $node->appendChild(self::convert($key, $value)); + } + unset($arr[$key]); //remove the key from the array once done. + } + } + // after we are done with all the keys in the array (if it is one) + // we check if it has any text value, if yes, append it. + if(!is_array($arr)) { + $node->appendChild($xml->createTextNode(self::bool2str($arr))); + } + return $node; + } + /* + * Get the root XML node, if there isn't one, create it. + */ + private static function getXMLRoot(){ + if(empty(self::$xml)) { + self::init(); + } + return self::$xml; + } + /* + * Get string representation of boolean value + */ + private static function bool2str($v){ + //convert boolean to text value. + $v = $v === true ? 'true' : $v; + $v = $v === false ? 'false' : $v; + return $v; + } + /* + * Check if the tag name or attribute name contains illegal characters + * Ref: http://www.w3.org/TR/xml/#sec-common-syn + */ + private static function isValidTagName($tag){ + $pattern = '/^[a-z_]+[a-z0-9\:\-\.\_]*[^:]*$/i'; + return preg_match($pattern, $tag, $matches) && $matches[0] == $tag; + } +} + +/** + * XML2Array: A class to convert XML to array in PHP + * It returns the array which can be converted back to XML using the Array2XML script + * It takes an XML string or a DOMDocument object as an input. + * + * See Array2XML: http://www.lalit.org/lab/convert-php-array-to-xml-with-attributes + * + * Author : Lalit Patel + * Website: http://www.lalit.org/lab/convert-xml-to-array-in-php-xml2array + * License: Apache License 2.0 + * http://www.apache.org/licenses/LICENSE-2.0 + * Version: 0.1 (07 Dec 2011) + * Version: 0.2 (04 Mar 2012) + * Fixed typo 'DomDocument' to 'DOMDocument' + * + * Usage: + * $array = XML2Array::createArray($xml); + */ + +class XML2Array { + + private static $xml = null; + private static $encoding = 'UTF-8'; + + /** + * Initialize the root XML node [optional] + * @param $version + * @param $encoding + * @param $format_output + */ + public static function init($version = '1.0', $encoding = 'UTF-8', $format_output = true) { + self::$xml = new DOMDocument($version, $encoding); + self::$xml->formatOutput = $format_output; + self::$encoding = $encoding; + } + + /** + * Convert an XML to Array + * @param string $node_name - name of the root node to be converted + * @param array $arr - aray to be converterd + * @return DOMDocument + */ + public static function &createArray($input_xml) { + $xml = self::getXMLRoot(); + if(is_string($input_xml)) { + $parsed = $xml->loadXML($input_xml); + if(!$parsed) { + throw new Exception('[XML2Array] Error parsing the XML string.'); + } + } else { + if(get_class($input_xml) != 'DOMDocument') { + throw new Exception('[XML2Array] The input XML object should be of type: DOMDocument.'); + } + $xml = self::$xml = $input_xml; + } + $array[$xml->documentElement->tagName] = self::convert($xml->documentElement); + self::$xml = null; // clear the xml node in the class for 2nd time use. + return $array; + } + + /** + * Convert an Array to XML + * @param mixed $node - XML as a string or as an object of DOMDocument + * @return mixed + */ + private static function &convert($node) { + $output = array(); + + switch ($node->nodeType) { + case XML_CDATA_SECTION_NODE: + $output['@cdata'] = trim($node->textContent); + break; + + case XML_TEXT_NODE: + $output = trim($node->textContent); + break; + + case XML_ELEMENT_NODE: + + // for each child node, call the covert function recursively + for ($i=0, $m=$node->childNodes->length; $i<$m; $i++) { + $child = $node->childNodes->item($i); + $v = self::convert($child); + if(isset($child->tagName)) { + $t = $child->tagName; + + // assume more nodes of same kind are coming + if(!isset($output[$t])) { + $output[$t] = array(); + } + $output[$t][] = $v; + } else { + //check if it is not an empty text node + if($v !== '') { + $output = $v; + } + } + } + + if(is_array($output)) { + // if only one node of its kind, assign it directly instead if array($value); + foreach ($output as $t => $v) { + if(is_array($v) && count($v)==1) { + $output[$t] = $v[0]; + } + } + if(empty($output)) { + //for empty nodes + $output = ''; + } + } + + // loop through the attributes and collect them + if($node->attributes->length) { + $a = array(); + foreach($node->attributes as $attrName => $attrNode) { + $a[$attrName] = (string) $attrNode->value; + } + // if its an leaf node, store the value in @value instead of directly storing it. + if(!is_array($output)) { + $output = array('@value' => $output); + } + $output['@attributes'] = $a; + } + break; + } + return $output; + } + + /* + * Get the root XML node, if there isn't one, create it. + */ + private static function getXMLRoot(){ + if(empty(self::$xml)) { + self::init(); + } + return self::$xml; + } +} +?> + diff --git a/source/community.applications/usr/local/emhttp/plugins/community.applications/javascript/tooltipster.bundle.min.js b/source/community.applications/usr/local/emhttp/plugins/community.applications/javascript/tooltipster.bundle.min.js new file mode 100644 index 00000000..3d0ace71 --- /dev/null +++ b/source/community.applications/usr/local/emhttp/plugins/community.applications/javascript/tooltipster.bundle.min.js @@ -0,0 +1,2 @@ +/*! tooltipster v4.1.7 */!function(a,b){"function"==typeof define&&define.amd?define(["jquery"],function(a){return b(a)}):"object"==typeof exports?module.exports=b(require("jquery")):b(jQuery)}(this,function(a){function b(a){this.$container,this.constraints=null,this.__$tooltip,this.__init(a)}function c(b,c){var d=!0;return a.each(b,function(a,e){return void 0===c[a]||b[a]!==c[a]?(d=!1,!1):void 0}),d}function d(b){var c=b.attr("id"),d=c?h.window.document.getElementById(c):null;return d?d===b[0]:a.contains(h.window.document.body,b[0])}function e(){if(!g)return!1;var a=g.document.body||g.document.documentElement,b=a.style,c="transition",d=["Moz","Webkit","Khtml","O","ms"];if("string"==typeof b[c])return!0;c=c.charAt(0).toUpperCase()+c.substr(1);for(var e=0;e0?e=c.__plugins[d]:a.each(c.__plugins,function(a,b){return b.name.substring(b.name.length-d.length-1)=="."+d?(e=b,!1):void 0}),e}if(b.name.indexOf(".")<0)throw new Error("Plugins must be namespaced");return c.__plugins[b.name]=b,b.core&&c.__bridge(b.core,c,b.name),this},_trigger:function(){var a=Array.prototype.slice.apply(arguments);return"string"==typeof a[0]&&(a[0]={type:a[0]}),this.__$emitterPrivate.trigger.apply(this.__$emitterPrivate,a),this.__$emitterPublic.trigger.apply(this.__$emitterPublic,a),this},instances:function(b){var c=[],d=b||".tooltipstered";return a(d).each(function(){var b=a(this),d=b.data("tooltipster-ns");d&&a.each(d,function(a,d){c.push(b.data(d))})}),c},instancesLatest:function(){return this.__instancesLatestArr},off:function(){return this.__$emitterPublic.off.apply(this.__$emitterPublic,Array.prototype.slice.apply(arguments)),this},on:function(){return this.__$emitterPublic.on.apply(this.__$emitterPublic,Array.prototype.slice.apply(arguments)),this},one:function(){return this.__$emitterPublic.one.apply(this.__$emitterPublic,Array.prototype.slice.apply(arguments)),this},origins:function(b){var c=b?b+" ":"";return a(c+".tooltipstered").toArray()},setDefaults:function(b){return a.extend(f,b),this},triggerHandler:function(){return this.__$emitterPublic.triggerHandler.apply(this.__$emitterPublic,Array.prototype.slice.apply(arguments)),this}},a.tooltipster=new i,a.Tooltipster=function(b,c){this.__callbacks={close:[],open:[]},this.__closingTime,this.__Content,this.__contentBcr,this.__destroyed=!1,this.__destroying=!1,this.__$emitterPrivate=a({}),this.__$emitterPublic=a({}),this.__enabled=!0,this.__garbageCollector,this.__Geometry,this.__lastPosition,this.__namespace="tooltipster-"+Math.round(1e6*Math.random()),this.__options,this.__$originParents,this.__pointerIsOverOrigin=!1,this.__previousThemes=[],this.__state="closed",this.__timeouts={close:[],open:null},this.__touchEvents=[],this.__tracker=null,this._$origin,this._$tooltip,this.__init(b,c)},a.Tooltipster.prototype={__init:function(b,c){var d=this;if(d._$origin=a(b),d.__options=a.extend(!0,{},f,c),d.__optionsFormat(),!h.IE||h.IE>=d.__options.IEmin){var e=null;if(void 0===d._$origin.data("tooltipster-initialTitle")&&(e=d._$origin.attr("title"),void 0===e&&(e=null),d._$origin.data("tooltipster-initialTitle",e)),null!==d.__options.content)d.__contentSet(d.__options.content);else{var g,i=d._$origin.attr("data-tooltip-content");i&&(g=a(i)),g&&g[0]?d.__contentSet(g.first()):d.__contentSet(e)}d._$origin.removeAttr("title").addClass("tooltipstered"),d.__prepareOrigin(),d.__prepareGC(),a.each(d.__options.plugins,function(a,b){d._plug(b)}),h.hasTouchCapability&&a("body").on("touchmove."+d.__namespace+"-triggerOpen",function(a){d._touchRecordEvent(a)}),d._on("created",function(){d.__prepareTooltip()})._on("repositioned",function(a){d.__lastPosition=a.position})}else d.__options.disabled=!0},__contentInsert:function(){var a=this,b=a._$tooltip.find(".tooltipster-content"),c=a.__Content,d=function(a){c=a};return a._trigger({type:"format",content:a.__Content,format:d}),a.__options.functionFormat&&(c=a.__options.functionFormat.call(a,a,{origin:a._$origin[0]},a.__Content)),"string"!=typeof c||a.__options.contentAsHTML?b.empty().append(c):b.text(c),a},__contentSet:function(b){return b instanceof a&&this.__options.contentCloning&&(b=b.clone(!0)),this.__Content=b,this._trigger({type:"updated",content:b}),this},__destroyError:function(){throw new Error("This tooltip has been destroyed and cannot execute your method call.")},__geometry:function(){var b=this,c=b._$origin,d=b._$origin.is("area");if(d){var e=b._$origin.parent().attr("name");c=a('img[usemap="#'+e+'"]')}var f=c[0].getBoundingClientRect(),g=a(h.window.document),i=a(h.window),j=c,k={available:{document:null,window:null},document:{size:{height:g.height(),width:g.width()}},window:{scroll:{left:h.window.scrollX||h.window.document.documentElement.scrollLeft,top:h.window.scrollY||h.window.document.documentElement.scrollTop},size:{height:i.height(),width:i.width()}},origin:{fixedLineage:!1,offset:{},size:{height:f.bottom-f.top,width:f.right-f.left},usemapImage:d?c[0]:null,windowOffset:{bottom:f.bottom,left:f.left,right:f.right,top:f.top}}};if(d){var l=b._$origin.attr("shape"),m=b._$origin.attr("coords");if(m&&(m=m.split(","),a.map(m,function(a,b){m[b]=parseInt(a)})),"default"!=l)switch(l){case"circle":var n=m[0],o=m[1],p=m[2],q=o-p,r=n-p;k.origin.size.height=2*p,k.origin.size.width=k.origin.size.height,k.origin.windowOffset.left+=r,k.origin.windowOffset.top+=q;break;case"rect":var s=m[0],t=m[1],u=m[2],v=m[3];k.origin.size.height=v-t,k.origin.size.width=u-s,k.origin.windowOffset.left+=s,k.origin.windowOffset.top+=t;break;case"poly":for(var w=0,x=0,y=0,z=0,A="even",B=0;By&&(y=C,0===B&&(w=y)),w>C&&(w=C),A="odd"):(C>z&&(z=C,1==B&&(x=z)),x>C&&(x=C),A="even")}k.origin.size.height=z-x,k.origin.size.width=y-w,k.origin.windowOffset.left+=w,k.origin.windowOffset.top+=x}}var D=function(a){k.origin.size.height=a.height,k.origin.windowOffset.left=a.left,k.origin.windowOffset.top=a.top,k.origin.size.width=a.width};for(b._trigger({type:"geometry",edit:D,geometry:{height:k.origin.size.height,left:k.origin.windowOffset.left,top:k.origin.windowOffset.top,width:k.origin.size.width}}),k.origin.windowOffset.right=k.origin.windowOffset.left+k.origin.size.width,k.origin.windowOffset.bottom=k.origin.windowOffset.top+k.origin.size.height,k.origin.offset.left=k.origin.windowOffset.left+k.window.scroll.left,k.origin.offset.top=k.origin.windowOffset.top+k.window.scroll.top,k.origin.offset.bottom=k.origin.offset.top+k.origin.size.height,k.origin.offset.right=k.origin.offset.left+k.origin.size.width,k.available.document={bottom:{height:k.document.size.height-k.origin.offset.bottom,width:k.document.size.width},left:{height:k.document.size.height,width:k.origin.offset.left},right:{height:k.document.size.height,width:k.document.size.width-k.origin.offset.right},top:{height:k.origin.offset.top,width:k.document.size.width}},k.available.window={bottom:{height:Math.max(k.window.size.height-Math.max(k.origin.windowOffset.bottom,0),0),width:k.window.size.width},left:{height:k.window.size.height,width:Math.max(k.origin.windowOffset.left,0)},right:{height:k.window.size.height,width:Math.max(k.window.size.width-Math.max(k.origin.windowOffset.right,0),0)},top:{height:Math.max(k.origin.windowOffset.top,0),width:k.window.size.width}};"html"!=j[0].tagName.toLowerCase();){if("fixed"==j.css("position")){k.origin.fixedLineage=!0;break}j=j.parent()}return k},__optionsFormat:function(){return"number"==typeof this.__options.animationDuration&&(this.__options.animationDuration=[this.__options.animationDuration,this.__options.animationDuration]),"number"==typeof this.__options.delay&&(this.__options.delay=[this.__options.delay,this.__options.delay]),"number"==typeof this.__options.delayTouch&&(this.__options.delayTouch=[this.__options.delayTouch,this.__options.delayTouch]),"string"==typeof this.__options.theme&&(this.__options.theme=[this.__options.theme]),"string"==typeof this.__options.parent&&(this.__options.parent=a(this.__options.parent)),"hover"==this.__options.trigger?(this.__options.triggerOpen={mouseenter:!0,touchstart:!0},this.__options.triggerClose={mouseleave:!0,originClick:!0,touchleave:!0}):"click"==this.__options.trigger&&(this.__options.triggerOpen={click:!0,tap:!0},this.__options.triggerClose={click:!0,tap:!0}),this._trigger("options"),this},__prepareGC:function(){var b=this;return b.__options.selfDestruction?b.__garbageCollector=setInterval(function(){var c=(new Date).getTime();b.__touchEvents=a.grep(b.__touchEvents,function(a,b){return c-a.time>6e4}),d(b._$origin)||b.destroy()},2e4):clearInterval(b.__garbageCollector),b},__prepareOrigin:function(){var a=this;if(a._$origin.off("."+a.__namespace+"-triggerOpen"),h.hasTouchCapability&&a._$origin.on("touchstart."+a.__namespace+"-triggerOpen touchend."+a.__namespace+"-triggerOpen touchcancel."+a.__namespace+"-triggerOpen",function(b){a._touchRecordEvent(b)}),a.__options.triggerOpen.click||a.__options.triggerOpen.tap&&h.hasTouchCapability){var b="";a.__options.triggerOpen.click&&(b+="click."+a.__namespace+"-triggerOpen "),a.__options.triggerOpen.tap&&h.hasTouchCapability&&(b+="touchend."+a.__namespace+"-triggerOpen"),a._$origin.on(b,function(b){a._touchIsMeaningfulEvent(b)&&a._open(b)})}if(a.__options.triggerOpen.mouseenter||a.__options.triggerOpen.touchstart&&h.hasTouchCapability){var b="";a.__options.triggerOpen.mouseenter&&(b+="mouseenter."+a.__namespace+"-triggerOpen "),a.__options.triggerOpen.touchstart&&h.hasTouchCapability&&(b+="touchstart."+a.__namespace+"-triggerOpen"),a._$origin.on(b,function(b){!a._touchIsTouchEvent(b)&&a._touchIsEmulatedEvent(b)||(a.__pointerIsOverOrigin=!0,a._openShortly(b))})}if(a.__options.triggerClose.mouseleave||a.__options.triggerClose.touchleave&&h.hasTouchCapability){var b="";a.__options.triggerClose.mouseleave&&(b+="mouseleave."+a.__namespace+"-triggerOpen "),a.__options.triggerClose.touchleave&&h.hasTouchCapability&&(b+="touchend."+a.__namespace+"-triggerOpen touchcancel."+a.__namespace+"-triggerOpen"),a._$origin.on(b,function(b){a._touchIsMeaningfulEvent(b)&&(a.__pointerIsOverOrigin=!1)})}return a},__prepareTooltip:function(){var b=this,c=b.__options.interactive?"auto":"";return b._$tooltip.attr("id",b.__namespace).css({"pointer-events":c,zIndex:b.__options.zIndex}),a.each(b.__previousThemes,function(a,c){b._$tooltip.removeClass(c)}),a.each(b.__options.theme,function(a,c){b._$tooltip.addClass(c)}),b.__previousThemes=a.merge([],b.__options.theme),b},__scrollHandler:function(b){var c=this;if(c.__options.triggerClose.scroll)c._close(b);else if(d(c._$origin)&&d(c._$tooltip)){if(b.target===h.window.document)c.__Geometry.origin.fixedLineage||c.__options.repositionOnScroll&&c.reposition(b);else{var e=c.__geometry(),f=!1;if("fixed"!=c._$origin.css("position")&&c.__$originParents.each(function(b,c){var d=a(c),g=d.css("overflow-x"),h=d.css("overflow-y");if("visible"!=g||"visible"!=h){var i=c.getBoundingClientRect();if("visible"!=g&&(e.origin.windowOffset.lefti.right))return f=!0,!1;if("visible"!=h&&(e.origin.windowOffset.topi.bottom))return f=!0,!1}return"fixed"==d.css("position")?!1:void 0}),f)c._$tooltip.css("visibility","hidden");else if(c._$tooltip.css("visibility","visible"),c.__options.repositionOnScroll)c.reposition(b);else{var g=e.origin.offset.left-c.__Geometry.origin.offset.left,i=e.origin.offset.top-c.__Geometry.origin.offset.top;c._$tooltip.css({left:c.__lastPosition.coord.left+g,top:c.__lastPosition.coord.top+i})}}c._trigger({type:"scroll",event:b})}return c},__stateSet:function(a){return this.__state=a,this._trigger({type:"state",state:a}),this},__timeoutsClear:function(){return clearTimeout(this.__timeouts.open),this.__timeouts.open=null,a.each(this.__timeouts.close,function(a,b){clearTimeout(b)}),this.__timeouts.close=[],this},__trackerStart:function(){var a=this,b=a._$tooltip.find(".tooltipster-content");return a.__options.trackTooltip&&(a.__contentBcr=b[0].getBoundingClientRect()),a.__tracker=setInterval(function(){if(d(a._$origin)&&d(a._$tooltip)){if(a.__options.trackOrigin){var e=a.__geometry(),f=!1;c(e.origin.size,a.__Geometry.origin.size)&&(a.__Geometry.origin.fixedLineage?c(e.origin.windowOffset,a.__Geometry.origin.windowOffset)&&(f=!0):c(e.origin.offset,a.__Geometry.origin.offset)&&(f=!0)),f||(a.__options.triggerClose.mouseleave?a._close():a.reposition())}if(a.__options.trackTooltip){var g=b[0].getBoundingClientRect();g.height===a.__contentBcr.height&&g.width===a.__contentBcr.width||(a.reposition(),a.__contentBcr=g)}}else a._close()},a.__options.trackerInterval),a},_close:function(b,c){var d=this,e=!0;if(d._trigger({type:"close",event:b,stop:function(){e=!1}}),e||d.__destroying){c&&d.__callbacks.close.push(c),d.__callbacks.open=[],d.__timeoutsClear();var f=function(){a.each(d.__callbacks.close,function(a,c){c.call(d,d,{event:b,origin:d._$origin[0]})}),d.__callbacks.close=[]};if("closed"!=d.__state){var g=!0,i=new Date,j=i.getTime(),k=j+d.__options.animationDuration[1];if("disappearing"==d.__state&&k>d.__closingTime&&(g=!1),g){d.__closingTime=k,"disappearing"!=d.__state&&d.__stateSet("disappearing");var l=function(){clearInterval(d.__tracker),d._trigger({type:"closing",event:b}),d._$tooltip.off("."+d.__namespace+"-triggerClose").removeClass("tooltipster-dying"),a(h.window).off("."+d.__namespace+"-triggerClose"),d.__$originParents.each(function(b,c){a(c).off("scroll."+d.__namespace+"-triggerClose")}),d.__$originParents=null,a("body").off("."+d.__namespace+"-triggerClose"),d._$origin.off("."+d.__namespace+"-triggerClose"),d._off("dismissable"),d.__stateSet("closed"),d._trigger({type:"after",event:b}),d.__options.functionAfter&&d.__options.functionAfter.call(d,d,{event:b,origin:d._$origin[0]}),f()};h.hasTransitions?(d._$tooltip.css({"-moz-animation-duration":d.__options.animationDuration[1]+"ms","-ms-animation-duration":d.__options.animationDuration[1]+"ms","-o-animation-duration":d.__options.animationDuration[1]+"ms","-webkit-animation-duration":d.__options.animationDuration[1]+"ms","animation-duration":d.__options.animationDuration[1]+"ms","transition-duration":d.__options.animationDuration[1]+"ms"}),d._$tooltip.clearQueue().removeClass("tooltipster-show").addClass("tooltipster-dying"),d.__options.animationDuration[1]>0&&d._$tooltip.delay(d.__options.animationDuration[1]),d._$tooltip.queue(l)):d._$tooltip.stop().fadeOut(d.__options.animationDuration[1],l)}}else f()}return d},_off:function(){return this.__$emitterPrivate.off.apply(this.__$emitterPrivate,Array.prototype.slice.apply(arguments)),this},_on:function(){return this.__$emitterPrivate.on.apply(this.__$emitterPrivate,Array.prototype.slice.apply(arguments)),this},_one:function(){return this.__$emitterPrivate.one.apply(this.__$emitterPrivate,Array.prototype.slice.apply(arguments)),this},_open:function(b,c){var e=this;if(!e.__destroying&&d(e._$origin)&&e.__enabled){var f=!0;if("closed"==e.__state&&(e._trigger({type:"before",event:b,stop:function(){f=!1}}),f&&e.__options.functionBefore&&(f=e.__options.functionBefore.call(e,e,{event:b,origin:e._$origin[0]}))),f!==!1&&null!==e.__Content){c&&e.__callbacks.open.push(c),e.__callbacks.close=[],e.__timeoutsClear();var g,i=function(){"stable"!=e.__state&&e.__stateSet("stable"),a.each(e.__callbacks.open,function(a,b){b.call(e,e,{origin:e._$origin[0],tooltip:e._$tooltip[0]})}),e.__callbacks.open=[]};if("closed"!==e.__state)g=0,"disappearing"===e.__state?(e.__stateSet("appearing"),h.hasTransitions?(e._$tooltip.clearQueue().removeClass("tooltipster-dying").addClass("tooltipster-show"),e.__options.animationDuration[0]>0&&e._$tooltip.delay(e.__options.animationDuration[0]),e._$tooltip.queue(i)):e._$tooltip.stop().fadeIn(i)):"stable"==e.__state&&i();else{if(e.__stateSet("appearing"),g=e.__options.animationDuration[0],e.__contentInsert(),e.reposition(b,!0),h.hasTransitions?(e._$tooltip.addClass("tooltipster-"+e.__options.animation).addClass("tooltipster-initial").css({"-moz-animation-duration":e.__options.animationDuration[0]+"ms","-ms-animation-duration":e.__options.animationDuration[0]+"ms","-o-animation-duration":e.__options.animationDuration[0]+"ms","-webkit-animation-duration":e.__options.animationDuration[0]+"ms","animation-duration":e.__options.animationDuration[0]+"ms","transition-duration":e.__options.animationDuration[0]+"ms"}),setTimeout(function(){"closed"!=e.__state&&(e._$tooltip.addClass("tooltipster-show").removeClass("tooltipster-initial"),e.__options.animationDuration[0]>0&&e._$tooltip.delay(e.__options.animationDuration[0]),e._$tooltip.queue(i))},0)):e._$tooltip.css("display","none").fadeIn(e.__options.animationDuration[0],i),e.__trackerStart(),a(h.window).on("resize."+e.__namespace+"-triggerClose",function(b){var c=a(document.activeElement);(c.is("input")||c.is("textarea"))&&a.contains(e._$tooltip[0],c[0])||e.reposition(b)}).on("scroll."+e.__namespace+"-triggerClose",function(a){e.__scrollHandler(a)}),e.__$originParents=e._$origin.parents(),e.__$originParents.each(function(b,c){a(c).on("scroll."+e.__namespace+"-triggerClose",function(a){e.__scrollHandler(a)})}),e.__options.triggerClose.mouseleave||e.__options.triggerClose.touchleave&&h.hasTouchCapability){e._on("dismissable",function(a){a.dismissable?a.delay?(m=setTimeout(function(){e._close(a.event)},a.delay),e.__timeouts.close.push(m)):e._close(a):clearTimeout(m)});var j=e._$origin,k="",l="",m=null;e.__options.interactive&&(j=j.add(e._$tooltip)),e.__options.triggerClose.mouseleave&&(k+="mouseenter."+e.__namespace+"-triggerClose ",l+="mouseleave."+e.__namespace+"-triggerClose "),e.__options.triggerClose.touchleave&&h.hasTouchCapability&&(k+="touchstart."+e.__namespace+"-triggerClose",l+="touchend."+e.__namespace+"-triggerClose touchcancel."+e.__namespace+"-triggerClose"),j.on(l,function(a){if(e._touchIsTouchEvent(a)||!e._touchIsEmulatedEvent(a)){var b="mouseleave"==a.type?e.__options.delay:e.__options.delayTouch;e._trigger({delay:b[1],dismissable:!0,event:a,type:"dismissable"})}}).on(k,function(a){!e._touchIsTouchEvent(a)&&e._touchIsEmulatedEvent(a)||e._trigger({dismissable:!1,event:a,type:"dismissable"})})}e.__options.triggerClose.originClick&&e._$origin.on("click."+e.__namespace+"-triggerClose",function(a){e._touchIsTouchEvent(a)||e._touchIsEmulatedEvent(a)||e._close(a)}),(e.__options.triggerClose.click||e.__options.triggerClose.tap&&h.hasTouchCapability)&&setTimeout(function(){if("closed"!=e.__state){var b="";e.__options.triggerClose.click&&(b+="click."+e.__namespace+"-triggerClose "),e.__options.triggerClose.tap&&h.hasTouchCapability&&(b+="touchend."+e.__namespace+"-triggerClose"),a("body").on(b,function(b){e._touchIsMeaningfulEvent(b)&&(e._touchRecordEvent(b),e.__options.interactive&&a.contains(e._$tooltip[0],b.target)||e._close(b))}),e.__options.triggerClose.tap&&h.hasTouchCapability&&a("body").on("touchstart."+e.__namespace+"-triggerClose",function(a){e._touchRecordEvent(a)})}},0),e._trigger("ready"),e.__options.functionReady&&e.__options.functionReady.call(e,e,{origin:e._$origin[0],tooltip:e._$tooltip[0]})}if(e.__options.timer>0){var m=setTimeout(function(){e._close()},e.__options.timer+g);e.__timeouts.close.push(m)}}}return e},_openShortly:function(a){var b=this,c=!0;if("stable"!=b.__state&&"appearing"!=b.__state&&!b.__timeouts.open&&(b._trigger({type:"start",event:a,stop:function(){c=!1}}),c)){var d=0==a.type.indexOf("touch")?b.__options.delayTouch:b.__options.delay;d[0]?b.__timeouts.open=setTimeout(function(){b.__timeouts.open=null,b.__pointerIsOverOrigin&&b._touchIsMeaningfulEvent(a)?(b._trigger("startend"),b._open(a)):b._trigger("startcancel")},d[0]):(b._trigger("startend"),b._open(a))}return b},_optionsExtract:function(b,c){var d=this,e=a.extend(!0,{},c),f=d.__options[b];return f||(f={},a.each(c,function(a,b){var c=d.__options[a];void 0!==c&&(f[a]=c)})),a.each(e,function(b,c){void 0!==f[b]&&("object"!=typeof c||c instanceof Array||null==c||"object"!=typeof f[b]||f[b]instanceof Array||null==f[b]?e[b]=f[b]:a.extend(e[b],f[b]))}),e},_plug:function(b){var c=a.tooltipster._plugin(b);if(!c)throw new Error('The "'+b+'" plugin is not defined');return c.instance&&a.tooltipster.__bridge(c.instance,this,c.name),this},_touchIsEmulatedEvent:function(a){for(var b=!1,c=(new Date).getTime(),d=this.__touchEvents.length-1;d>=0;d--){var e=this.__touchEvents[d];if(!(c-e.time<500))break;e.target===a.target&&(b=!0)}return b},_touchIsMeaningfulEvent:function(a){return this._touchIsTouchEvent(a)&&!this._touchSwiped(a.target)||!this._touchIsTouchEvent(a)&&!this._touchIsEmulatedEvent(a)},_touchIsTouchEvent:function(a){return 0==a.type.indexOf("touch")},_touchRecordEvent:function(a){return this._touchIsTouchEvent(a)&&(a.time=(new Date).getTime(),this.__touchEvents.push(a)),this},_touchSwiped:function(a){for(var b=!1,c=this.__touchEvents.length-1;c>=0;c--){var d=this.__touchEvents[c];if("touchmove"==d.type){b=!0;break}if("touchstart"==d.type&&a===d.target)break}return b},_trigger:function(){var b=Array.prototype.slice.apply(arguments);return"string"==typeof b[0]&&(b[0]={type:b[0]}),b[0].instance=this,b[0].origin=this._$origin?this._$origin[0]:null,b[0].tooltip=this._$tooltip?this._$tooltip[0]:null,this.__$emitterPrivate.trigger.apply(this.__$emitterPrivate,b),a.tooltipster._trigger.apply(a.tooltipster,b),this.__$emitterPublic.trigger.apply(this.__$emitterPublic,b),this},_unplug:function(b){var c=this;if(c[b]){var d=a.tooltipster._plugin(b);d.instance&&a.each(d.instance,function(a,d){c[a]&&c[a].bridged===c[b]&&delete c[a]}),c[b].__destroy&&c[b].__destroy(),delete c[b]}return c},close:function(a){return this.__destroyed?this.__destroyError():this._close(null,a),this},content:function(a){var b=this;if(void 0===a)return b.__Content;if(b.__destroyed)b.__destroyError();else if(b.__contentSet(a),null!==b.__Content){if("closed"!==b.__state&&(b.__contentInsert(),b.reposition(),b.__options.updateAnimation))if(h.hasTransitions){var c=b.__options.updateAnimation;b._$tooltip.addClass("tooltipster-update-"+c),setTimeout(function(){"closed"!=b.__state&&b._$tooltip.removeClass("tooltipster-update-"+c)},1e3)}else b._$tooltip.fadeTo(200,.5,function(){"closed"!=b.__state&&b._$tooltip.fadeTo(200,1)})}else b._close();return b},destroy:function(){var b=this;return b.__destroyed?b.__destroyError():b.__destroying||(b.__destroying=!0,b._close(null,function(){b._trigger("destroy"),b.__destroying=!1,b.__destroyed=!0,b._$origin.removeData(b.__namespace).off("."+b.__namespace+"-triggerOpen"),a("body").off("."+b.__namespace+"-triggerOpen");var c=b._$origin.data("tooltipster-ns");if(c)if(1===c.length){var d=null;"previous"==b.__options.restoration?d=b._$origin.data("tooltipster-initialTitle"):"current"==b.__options.restoration&&(d="string"==typeof b.__Content?b.__Content:a("
").append(b.__Content).html()),d&&b._$origin.attr("title",d),b._$origin.removeClass("tooltipstered"),b._$origin.removeData("tooltipster-ns").removeData("tooltipster-initialTitle")}else c=a.grep(c,function(a,c){return a!==b.__namespace}),b._$origin.data("tooltipster-ns",c);b._trigger("destroyed"),b._off(),b.off(),b.__Content=null,b.__$emitterPrivate=null,b.__$emitterPublic=null,b.__options.parent=null,b._$origin=null,b._$tooltip=null,a.tooltipster.__instancesLatestArr=a.grep(a.tooltipster.__instancesLatestArr,function(a,c){return b!==a}),clearInterval(b.__garbageCollector)})),b},disable:function(){return this.__destroyed?(this.__destroyError(),this):(this._close(),this.__enabled=!1,this)},elementOrigin:function(){return this.__destroyed?void this.__destroyError():this._$origin[0]},elementTooltip:function(){return this._$tooltip?this._$tooltip[0]:null},enable:function(){return this.__enabled=!0,this},hide:function(a){return this.close(a)},instance:function(){return this},off:function(){return this.__destroyed||this.__$emitterPublic.off.apply(this.__$emitterPublic,Array.prototype.slice.apply(arguments)),this},on:function(){return this.__destroyed?this.__destroyError():this.__$emitterPublic.on.apply(this.__$emitterPublic,Array.prototype.slice.apply(arguments)),this},one:function(){return this.__destroyed?this.__destroyError():this.__$emitterPublic.one.apply(this.__$emitterPublic,Array.prototype.slice.apply(arguments)),this},open:function(a){return this.__destroyed||this.__destroying?this.__destroyError():this._open(null,a),this},option:function(b,c){return void 0===c?this.__options[b]:(this.__destroyed?this.__destroyError():(this.__options[b]=c,this.__optionsFormat(),a.inArray(b,["trigger","triggerClose","triggerOpen"])>=0&&this.__prepareOrigin(),"selfDestruction"===b&&this.__prepareGC()),this)},reposition:function(a,b){var c=this;return c.__destroyed?c.__destroyError():"closed"!=c.__state&&d(c._$origin)&&(b||d(c._$tooltip))&&(b||c._$tooltip.detach(),c.__Geometry=c.__geometry(),c._trigger({type:"reposition",event:a,helper:{geo:c.__Geometry}})),c},show:function(a){return this.open(a)},status:function(){return{destroyed:this.__destroyed,destroying:this.__destroying,enabled:this.__enabled,open:"closed"!==this.__state,state:this.__state}},triggerHandler:function(){return this.__destroyed?this.__destroyError():this.__$emitterPublic.triggerHandler.apply(this.__$emitterPublic,Array.prototype.slice.apply(arguments)),this}},a.fn.tooltipster=function(){var b=Array.prototype.slice.apply(arguments),c="You are using a single HTML element as content for several tooltips. You probably want to set the contentCloning option to TRUE.";if(0===this.length)return this;if("string"==typeof b[0]){var d="#*$~&";return this.each(function(){var e=a(this).data("tooltipster-ns"),f=e?a(this).data(e[0]):null;if(!f)throw new Error("You called Tooltipster's \""+b[0]+'" method on an uninitialized element');if("function"!=typeof f[b[0]])throw new Error('Unknown method "'+b[0]+'"');this.length>1&&"content"==b[0]&&(b[1]instanceof a||"object"==typeof b[1]&&null!=b[1]&&b[1].tagName)&&!f.__options.contentCloning&&f.__options.debug&&console.log(c);var g=f[b[0]](b[1],b[2]);return g!==f||"instance"===b[0]?(d=g,!1):void 0}),"#*$~&"!==d?d:this}a.tooltipster.__instancesLatestArr=[];var e=b[0]&&void 0!==b[0].multiple,g=e&&b[0].multiple||!e&&f.multiple,h=b[0]&&void 0!==b[0].content,i=h&&b[0].content||!h&&f.content,j=b[0]&&void 0!==b[0].contentCloning,k=j&&b[0].contentCloning||!j&&f.contentCloning,l=b[0]&&void 0!==b[0].debug,m=l&&b[0].debug||!l&&f.debug;return this.length>1&&(i instanceof a||"object"==typeof i&&null!=i&&i.tagName)&&!k&&m&&console.log(c),this.each(function(){var c=!1,d=a(this),e=d.data("tooltipster-ns"),f=null;e?g?c=!0:m&&(console.log("Tooltipster: one or more tooltips are already attached to the element below. Ignoring."),console.log(this)):c=!0,c&&(f=new a.Tooltipster(this,b[0]),e||(e=[]),e.push(f.__namespace),d.data("tooltipster-ns",e),d.data(f.__namespace,f),f.__options.functionInit&&f.__options.functionInit.call(f,f,{origin:this}),f._trigger("init")),a.tooltipster.__instancesLatestArr.push(f)}),this},b.prototype={__init:function(b){this.__$tooltip=b,this.__$tooltip.css({left:0,overflow:"hidden",position:"absolute",top:0}).find(".tooltipster-content").css("overflow","auto"),this.$container=a('
').append(this.__$tooltip).appendTo("body")},__forceRedraw:function(){var a=this.__$tooltip.parent();this.__$tooltip.detach(),this.__$tooltip.appendTo(a)},constrain:function(a,b){return this.constraints={width:a,height:b},this.__$tooltip.css({display:"block",height:"",overflow:"auto",width:a}),this},destroy:function(){this.__$tooltip.detach().find(".tooltipster-content").css({display:"",overflow:""}),this.$container.remove()},free:function(){return this.constraints=null,this.__$tooltip.css({display:"",height:"",overflow:"visible",width:""}),this},measure:function(){this.__forceRedraw();var a=this.__$tooltip[0].getBoundingClientRect(),b={size:{height:a.height||a.bottom,width:a.width||a.right}};if(this.constraints){var c=this.__$tooltip.find(".tooltipster-content"),d=this.__$tooltip.outerHeight(),e=c[0].getBoundingClientRect(),f={height:d<=this.constraints.height,width:a.width<=this.constraints.width&&e.width>=c[0].scrollWidth-1};b.fits=f.height&&f.width}return h.IE&&h.IE<=11&&b.size.width!==h.window.document.documentElement.clientWidth&&(b.size.width=Math.ceil(b.size.width)+1),b}};var j=navigator.userAgent.toLowerCase();-1!=j.indexOf("msie")?h.IE=parseInt(j.split("msie")[1]):-1!==j.toLowerCase().indexOf("trident")&&-1!==j.indexOf(" rv:11")?h.IE=11:-1!=j.toLowerCase().indexOf("edge/")&&(h.IE=parseInt(j.toLowerCase().split("edge/")[1]));var k="tooltipster.sideTip";return a.tooltipster._plugin({name:k,instance:{__defaults:function(){return{arrow:!0,distance:6,functionPosition:null,maxWidth:null,minIntersection:16,minWidth:0,position:null,side:"top",viewportAware:!0}},__init:function(a){var b=this;b.__instance=a,b.__namespace="tooltipster-sideTip-"+Math.round(1e6*Math.random()),b.__previousState="closed",b.__options,b.__optionsFormat(),b.__instance._on("state."+b.__namespace,function(a){"closed"==a.state?b.__close():"appearing"==a.state&&"closed"==b.__previousState&&b.__create(),b.__previousState=a.state}),b.__instance._on("options."+b.__namespace,function(){b.__optionsFormat()}),b.__instance._on("reposition."+b.__namespace,function(a){b.__reposition(a.event,a.helper)})},__close:function(){this.__instance.content()instanceof a&&this.__instance.content().detach(),this.__instance._$tooltip.remove(),this.__instance._$tooltip=null},__create:function(){var b=a('
');this.__options.arrow||b.find(".tooltipster-box").css("margin",0).end().find(".tooltipster-arrow").hide(),this.__options.minWidth&&b.css("min-width",this.__options.minWidth+"px"),this.__options.maxWidth&&b.css("max-width",this.__options.maxWidth+"px"),this.__instance._$tooltip=b,this.__instance._trigger("created")},__destroy:function(){this.__instance._off("."+self.__namespace)},__optionsFormat:function(){ +var b=this;if(b.__options=b.__instance._optionsExtract(k,b.__defaults()),b.__options.position&&(b.__options.side=b.__options.position),"object"!=typeof b.__options.distance&&(b.__options.distance=[b.__options.distance]),b.__options.distance.length<4&&(void 0===b.__options.distance[1]&&(b.__options.distance[1]=b.__options.distance[0]),void 0===b.__options.distance[2]&&(b.__options.distance[2]=b.__options.distance[0]),void 0===b.__options.distance[3]&&(b.__options.distance[3]=b.__options.distance[1]),b.__options.distance={top:b.__options.distance[0],right:b.__options.distance[1],bottom:b.__options.distance[2],left:b.__options.distance[3]}),"string"==typeof b.__options.side){var c={top:"bottom",right:"left",bottom:"top",left:"right"};b.__options.side=[b.__options.side,c[b.__options.side]],"left"==b.__options.side[0]||"right"==b.__options.side[0]?b.__options.side.push("top","bottom"):b.__options.side.push("right","left")}6===a.tooltipster._env.IE&&b.__options.arrow!==!0&&(b.__options.arrow=!1)},__reposition:function(b,c){var d,e=this,f=e.__targetFind(c),g=[];e.__instance._$tooltip.detach();var h=e.__instance._$tooltip.clone(),i=a.tooltipster._getRuler(h),j=!1,k=e.__instance.option("animation");switch(k&&h.removeClass("tooltipster-"+k),a.each(["window","document"],function(d,k){var l=null;if(e.__instance._trigger({container:k,helper:c,satisfied:j,takeTest:function(a){l=a},results:g,type:"positionTest"}),1==l||0!=l&&0==j&&("window"!=k||e.__options.viewportAware))for(var d=0;d=h.outerSize.width&&c.geo.available[k][n].height>=h.outerSize.height?h.fits=!0:h.fits=!1:h.fits=p.fits,"window"==k&&(h.fits?"top"==n||"bottom"==n?h.whole=c.geo.origin.windowOffset.right>=e.__options.minIntersection&&c.geo.window.size.width-c.geo.origin.windowOffset.left>=e.__options.minIntersection:h.whole=c.geo.origin.windowOffset.bottom>=e.__options.minIntersection&&c.geo.window.size.height-c.geo.origin.windowOffset.top>=e.__options.minIntersection:h.whole=!1),g.push(h),h.whole)j=!0;else if("natural"==h.mode&&(h.fits||h.size.width<=c.geo.available[k][n].width))return!1}})}}),e.__instance._trigger({edit:function(a){g=a},event:b,helper:c,results:g,type:"positionTested"}),g.sort(function(a,b){if(a.whole&&!b.whole)return-1;if(!a.whole&&b.whole)return 1;if(a.whole&&b.whole){var c=e.__options.side.indexOf(a.side),d=e.__options.side.indexOf(b.side);return d>c?-1:c>d?1:"natural"==a.mode?-1:1}if(a.fits&&!b.fits)return-1;if(!a.fits&&b.fits)return 1;if(a.fits&&b.fits){var c=e.__options.side.indexOf(a.side),d=e.__options.side.indexOf(b.side);return d>c?-1:c>d?1:"natural"==a.mode?-1:1}return"document"==a.container&&"bottom"==a.side&&"natural"==a.mode?-1:1}),d=g[0],d.coord={},d.side){case"left":case"right":d.coord.top=Math.floor(d.target-d.size.height/2);break;case"bottom":case"top":d.coord.left=Math.floor(d.target-d.size.width/2)}switch(d.side){case"left":d.coord.left=c.geo.origin.windowOffset.left-d.outerSize.width;break;case"right":d.coord.left=c.geo.origin.windowOffset.right+d.distance.horizontal;break;case"top":d.coord.top=c.geo.origin.windowOffset.top-d.outerSize.height;break;case"bottom":d.coord.top=c.geo.origin.windowOffset.bottom+d.distance.vertical}"window"==d.container?"top"==d.side||"bottom"==d.side?d.coord.left<0?c.geo.origin.windowOffset.right-this.__options.minIntersection>=0?d.coord.left=0:d.coord.left=c.geo.origin.windowOffset.right-this.__options.minIntersection-1:d.coord.left>c.geo.window.size.width-d.size.width&&(c.geo.origin.windowOffset.left+this.__options.minIntersection<=c.geo.window.size.width?d.coord.left=c.geo.window.size.width-d.size.width:d.coord.left=c.geo.origin.windowOffset.left+this.__options.minIntersection+1-d.size.width):d.coord.top<0?c.geo.origin.windowOffset.bottom-this.__options.minIntersection>=0?d.coord.top=0:d.coord.top=c.geo.origin.windowOffset.bottom-this.__options.minIntersection-1:d.coord.top>c.geo.window.size.height-d.size.height&&(c.geo.origin.windowOffset.top+this.__options.minIntersection<=c.geo.window.size.height?d.coord.top=c.geo.window.size.height-d.size.height:d.coord.top=c.geo.origin.windowOffset.top+this.__options.minIntersection+1-d.size.height):(d.coord.left>c.geo.window.size.width-d.size.width&&(d.coord.left=c.geo.window.size.width-d.size.width),d.coord.left<0&&(d.coord.left=0)),e.__sideChange(h,d.side),c.tooltipClone=h[0],c.tooltipParent=e.__instance.option("parent").parent[0],c.mode=d.mode,c.whole=d.whole,c.origin=e.__instance._$origin[0],c.tooltip=e.__instance._$tooltip[0],delete d.container,delete d.fits,delete d.mode,delete d.outerSize,delete d.whole,d.distance=d.distance.horizontal||d.distance.vertical;var l=a.extend(!0,{},d);if(e.__instance._trigger({edit:function(a){d=a},event:b,helper:c,position:l,type:"position"}),e.__options.functionPosition){var m=e.__options.functionPosition.call(e,e.__instance,c,l);m&&(d=m)}i.destroy();var n,o;"top"==d.side||"bottom"==d.side?(n={prop:"left",val:d.target-d.coord.left},o=d.size.width-this.__options.minIntersection):(n={prop:"top",val:d.target-d.coord.top},o=d.size.height-this.__options.minIntersection),n.valo&&(n.val=o);var p;p=c.geo.origin.fixedLineage?c.geo.origin.windowOffset:{left:c.geo.origin.windowOffset.left+c.geo.window.scroll.left,top:c.geo.origin.windowOffset.top+c.geo.window.scroll.top},d.coord={left:p.left+(d.coord.left-c.geo.origin.windowOffset.left),top:p.top+(d.coord.top-c.geo.origin.windowOffset.top)},e.__sideChange(e.__instance._$tooltip,d.side),c.geo.origin.fixedLineage?e.__instance._$tooltip.css("position","fixed"):e.__instance._$tooltip.css("position",""),e.__instance._$tooltip.css({left:d.coord.left,top:d.coord.top,height:d.size.height,width:d.size.width}).find(".tooltipster-arrow").css({left:"",top:""}).css(n.prop,n.val),e.__instance._$tooltip.appendTo(e.__instance.option("parent")),e.__instance._trigger({type:"repositioned",event:b,position:d})},__sideChange:function(a,b){a.removeClass("tooltipster-bottom").removeClass("tooltipster-left").removeClass("tooltipster-right").removeClass("tooltipster-top").addClass("tooltipster-"+b)},__targetFind:function(a){var b={},c=this.__instance._$origin[0].getClientRects();if(c.length>1){var d=this.__instance._$origin.css("opacity");1==d&&(this.__instance._$origin.css("opacity",.99),c=this.__instance._$origin[0].getClientRects(),this.__instance._$origin.css("opacity",1))}if(c.length<2)b.top=Math.floor(a.geo.origin.windowOffset.left+a.geo.origin.size.width/2),b.bottom=b.top,b.left=Math.floor(a.geo.origin.windowOffset.top+a.geo.origin.size.height/2),b.right=b.left;else{var e=c[0];b.top=Math.floor(e.left+(e.right-e.left)/2),e=c.length>2?c[Math.ceil(c.length/2)-1]:c[0],b.right=Math.floor(e.top+(e.bottom-e.top)/2),e=c[c.length-1],b.bottom=Math.floor(e.left+(e.right-e.left)/2),e=c.length>2?c[Math.ceil((c.length+1)/2)-1]:c[c.length-1],b.left=Math.floor(e.top+(e.bottom-e.top)/2)}return b}}}),a}); \ No newline at end of file diff --git a/source/community.applications/usr/local/emhttp/plugins/community.applications/scripts/deleteAppData.sh b/source/community.applications/usr/local/emhttp/plugins/community.applications/scripts/deleteAppData.sh new file mode 100644 index 00000000..2e348c11 --- /dev/null +++ b/source/community.applications/usr/local/emhttp/plugins/community.applications/scripts/deleteAppData.sh @@ -0,0 +1,4 @@ +#!/bin/bash + +/usr/local/emhttp/plugins/community.applications/scripts/deleteAppData1.sh "$1" & > /dev/null | at NOW -M >/dev/null 2>&1 + diff --git a/source/community.applications/usr/local/emhttp/plugins/community.applications/scripts/deleteAppData1.sh b/source/community.applications/usr/local/emhttp/plugins/community.applications/scripts/deleteAppData1.sh new file mode 100644 index 00000000..913973d2 --- /dev/null +++ b/source/community.applications/usr/local/emhttp/plugins/community.applications/scripts/deleteAppData1.sh @@ -0,0 +1,8 @@ +#!/bin/bash + +/usr/local/emhttp/plugins/dynamix/scripts/notify -e "Community Applications" -s "Deleting AppData" -d "Deleting $1" -i "normal" + +rm -r -f "$1" >/dev/null 2>&1 + +/usr/local/emhttp/plugins/dynamix/scripts/notify -e "Community Applications" -s "AppData Deleted" -d "Deleted $1" -i "normal" + diff --git a/source/community.applications/usr/local/emhttp/plugins/community.applications/scripts/installMulti.php b/source/community.applications/usr/local/emhttp/plugins/community.applications/scripts/installMulti.php new file mode 100644 index 00000000..e8d7c575 --- /dev/null +++ b/source/community.applications/usr/local/emhttp/plugins/community.applications/scripts/installMulti.php @@ -0,0 +1,114 @@ +$javascript"; + +if ( $_GET['docker'] ) { + echo "
"; + $dockers = explode(",",$_GET['docker']); + echo "Installing docker applications {$_GET['docker']}
"; + $_GET['updateContainer'] = true; + $_GET['ct'] = $dockers; + include("/tmp/community.applications/tempFiles/newCreateDocker.php"); + echo "
"; +?> + +$docker

"; + unset($output); + exec("docker start $docker 2>&1",$output,$retval); + if ($retval) { + $failFlag = true; + echo "$docker failed to start. You should install it alone (by clicking on the application) to fix the errors
"; + foreach ($output as $line) { + echo "$line
"; + } + echo "
"; + } + } + echo "
Setting installed applications to autostart
"; + $autostartFile = @file("/var/lib/docker/unraid-autostart",FILE_IGNORE_NEW_LINES); + if ( ! $autostartFile ) { + $autostartFile = array(); + } + foreach ($autostartFile as $line) { + $autostart[$line] = true; + } + foreach ($dockers as $docker) { + $autostart[$docker] = true; + } + $autostartFile = implode("\n",array_keys($autostart)); + file_put_contents("/var/lib/docker/unraid-autostart",$autostartFile); + if ( $_GET['plugin'] ) { + file_put_contents($communityPaths['PluginInstallPending'],$_GET['plugin']); + } + if ( $failFlag || !$_GET['plugin']) { + echo "
Docker Application Installation finished.
"; + } else { + echo ""; + } +} +?> + + + + + diff --git a/source/community.applications/usr/local/emhttp/plugins/community.applications/scripts/installMultiPlugin.sh b/source/community.applications/usr/local/emhttp/plugins/community.applications/scripts/installMultiPlugin.sh new file mode 100644 index 00000000..95687074 --- /dev/null +++ b/source/community.applications/usr/local/emhttp/plugins/community.applications/scripts/installMultiPlugin.sh @@ -0,0 +1,15 @@ +#!/bin/bash +IFS="*" read -r -a array <<< "$1" +for element in "${array[@]}" +do + /usr/local/sbin/plugin install "$element" +done + +echo +echo "*************************************************************************************************************************" +echo "* Finished Installing. If the DONE button did not appear, then you will need to click the red X in the top right corner *" +echo "* (Certain plugins will cause this issue due to how they are installed.)                                                *" +echo "*************************************************************************************************************************" +echo +echo + diff --git a/source/community.applications/usr/local/emhttp/plugins/community.applications/scripts/showBlacklist.php b/source/community.applications/usr/local/emhttp/plugins/community.applications/scripts/showBlacklist.php new file mode 100644 index 00000000..2f0c3465 --- /dev/null +++ b/source/community.applications/usr/local/emhttp/plugins/community.applications/scripts/showBlacklist.php @@ -0,0 +1,13 @@ +"; +if ( ! $moderation ) { + echo "

No blacklisted apps found
"; + return; +} +$moderation = str_replace(" "," ",$moderation); +$moderation = str_replace("\n","
",$moderation); +echo "These applications are still found within the application feed. CA will never allow you to install or reinstall these applications

$moderation"; +?> + diff --git a/source/community.applications/usr/local/emhttp/plugins/community.applications/scripts/showDeprecated.php b/source/community.applications/usr/local/emhttp/plugins/community.applications/scripts/showDeprecated.php new file mode 100644 index 00000000..c1e17f10 --- /dev/null +++ b/source/community.applications/usr/local/emhttp/plugins/community.applications/scripts/showDeprecated.php @@ -0,0 +1,11 @@ +"; +if ( ! $moderation ) { + echo "

No deprecated apps found
"; + return; +} +echo "Deprecated Applications are able to still be installed if you have previously had them installed. New installations of these applications are blocked unless you enable Display Deprecated Applications within CA's General Settings

$moderation"; +?> + diff --git a/source/community.applications/usr/local/emhttp/plugins/community.applications/scripts/showDesc.php b/source/community.applications/usr/local/emhttp/plugins/community.applications/scripts/showDesc.php new file mode 100644 index 00000000..85566bf6 --- /dev/null +++ b/source/community.applications/usr/local/emhttp/plugins/community.applications/scripts/showDesc.php @@ -0,0 +1,204 @@ +getAllInfo(); + $DockerClient = new DockerClient(); + $dockerRunning = $DockerClient->getDockerContainers(); +} else { + $info = array(); + $dockerRunning = array(); +} +$appNumber = urldecode($_GET['appNumber']); +$appName = urldecode($_GET['appName']); +if ( ! $appNumber ) { + $appNumber = $_POST['appNumber']; + $color=""; +} + +$repos = readJsonFile($communityPaths['Repositories']); +if ( ! $repos ) { + $repos = array(); +} +$displayed = readJsonFile($communityPaths['community-templates-displayed']); +foreach ($displayed as $file) { + $index = searchArray($file,"ID",$appNumber); + if ( $index === false ) { + continue; + } else { + $template = $file[$index]; + $Displayed = true; + break; + } +} +# handle case where the app being asked to display isn't on the most recent displayed list (ie: multiple browser tabs open) +if ( ! $template ) { + $file = readJsonFile($communityPaths['community-templates-info']); + $index = searchArray($file,"ID",$appNumber); + if ( $index === false ) { + echo "Something really wrong happened"; + return; + } + $template = $file[$index]; + $Displayed = false; +} + +$ID = $appNumber; +$repoIndex = searchArray($repos,"name",$template['RepoName']); +$webPageURL = $repos[$repoIndex]['web']; + +$donatelink = $template['DonateLink']; +$donateimg = $template['DonateImg']; +$donatetext = $template['DonateText']; + +if ( ! $template['Plugin'] ) { + foreach ($dockerRunning as $testDocker) { + $templateRepo = explode(":",$template['Repository']); + $testRepo = explode(":",$testDocker['Image']); + if ($templateRepo[0] == $testRepo[0]) { + $selected = true; + $name = $testDocker['Name']; + break; + } + } +} + +$template['Icon'] = $template['Icon'] ? $template['Icon'] : "/plugins/community.applications/images/question.png"; +$template['Description'] = trim($template['Description']); + +$templateDescription .= ""; +if ( $color ) { + $templateDescription .= "
{$template['Name']}



"; +} +$templateDescription .= "
"; +$templateDescription .= ($template['Beta'] == "true") ? "
(beta)
" : ""; +$templateDescription .= "
"; +$templateDescription .= "
"; +$templateDescription .= ""; +$templateDescription .= ""; +$templateDescription .= ($template['Private'] == "true") ? "" : ""; +$templateDescription .= ""; + +$template['Base'] = $template['Plugin'] ? "$colorunRaid Plugin" : $template['Base']; + +if ( strtolower($template['Base']) == "unknown" ) { + $template['Base'] = $template['BaseImage']; +} +if ( ! $template['Base'] ) { + $template['Base'] = "Could Not Determine"; +} + +$templateDescription .= ""; +$templateDescription .= $template['stars'] ? "" : ""; + +# In this day and age with auto-updating apps, NO ONE keeps up to date with the date updated. Remove from docker containers to avoid confusion +if ( $template['Date'] && $template['Plugin'] ) { + $niceDate = date("F j, Y",$template['Date']); + $templateDescription .= ""; +} +$templateDescription .= $template['MinVer'] ? "" : ""; +$templateDescription .= $template['MaxVer'] ? "" : ""; +$templateDescription .= ""; +$templateDescription .= $template['Licence'] ? "" : ""; + +$templateDescription .= "
$colorAuthor: $color".$template['Author']."
$colorRepository: $color"; +$templateDescription .= $template['Forum'] ? "".$template['RepoName']."" : "{$template['RepoName']}"; +if ( $template['Profile'] ) { + $profileDescription = $template['Plugin'] ? "Author" : "Maintainer"; + $templateDescription .= "    ($profileDescription Profile)"; +} +$templateDescription .= "
Private Repository
$colorCategories: $color".$template['Category']."
$colorBase OS: $color".$template['Base']."
$colorStar Rating: $color ".$template['stars']."
$colorDate Updated:
See below
$color$niceDate
$colorMinimum OS:{$color}unRaid v".$template['MinVer']."
$colorMax OS:{$color}unRaid v".$template['MaxVer']."
$colorDownloads:$color"; +$templateDescription .= $template['downloads'] ? $template['downloads'] : "Could Not Determine"; +$templateDescription .= "
$colorLicence:$color".$template['Licence']."
"; + +$templateDescription .= "
"; +$templateDescription .= "
"; +$templateDescription .= ""; + +if ( $Displayed ) { + if ( ! $template['Plugin'] ) { + if ( $communitySettings['dockerRunning'] ) { + if ( $selected ) { + $templateDescription .= "    "; + $templateDescription .= "    "; + if ( $info[$name]['url'] && $info[$name]['running'] ) { + $templateDescription .= "    "; + } + } else { + if ( $template['MyPath'] ) { + $templateDescription .= "    "; + } else { + $install = "    "; + $templateDescription .= $template['BranchID'] ? "    " : $install; + } + } + } + } else { + $pluginName = basename($template['PluginURL']); + if ( file_exists("/var/log/plugins/$pluginName") ) { + $pluginSettings = isset($template['CAlink']) ? $template['CAlink'] : getPluginLaunch($pluginName); + if ( $pluginSettings ) { + $templateDescription .= ""; + } + } else { + $buttonTitle = $template['MyPath'] ? "Reinstall Plugin" : "Install Plugin"; + $templateDescription .= "    "; + } + if ( checkPluginUpdate($template['PluginURL']) ) { + $templateDescription .= "    "; + } + } +} +$templateDescription .= "
"; +$templateDescription .= "
"; +$templateDescription .= $template['Description']; +$templateDescription .= $template['ModeratorComment'] ? "

Moderator Comments: ".$template['ModeratorComment'] : ""; +$templateDescription .= "


"; +$templateDescription .= $template['Support'] ? "  Support Thread  " : ""; +$templateDescription .= $template['Project'] ? "  Project Page  " : ""; +$templateDescription .= $template['WebPageURL'] ? "  Web Page  " : ""; + +if ( ($donatelink) && ($donateimg) ) { + $templateDescription .= "

$donatetext
"; + if ( $template['RepoName'] != "Squid's plugin Repository" ) { + $templateDescription .= "
The above link is set by the author of the template, not the author of Community Applications
"; + } +} +$templateDescription .= "
"; +if ( $template['Changes'] ) { + if ( $template['Plugin'] ) { + $appInformation = Markdown($template['Changes']); + } else { + $appInformation = $template['Changes']; + $appInformation = str_replace("\n","
",$appInformation); + $appInformation = str_replace("[","<",$appInformation); + $appInformation = str_replace("]",">",$appInformation); + } + $templateDescription .= "

Change Log Note: not all maintainers keep up to date on change logs

$appInformation"; +} +echo "
"; +echo $templateDescription; +echo "
"; +?> diff --git a/source/community.applications/usr/local/emhttp/plugins/community.applications/scripts/showFixed.php b/source/community.applications/usr/local/emhttp/plugins/community.applications/scripts/showFixed.php new file mode 100644 index 00000000..ee80ef4e --- /dev/null +++ b/source/community.applications/usr/local/emhttp/plugins/community.applications/scripts/showFixed.php @@ -0,0 +1,13 @@ +"; +if ( ! $moderation ) { + echo "

No templates were automatically fixed
"; + return; +} +$moderation = str_replace(" "," ",$moderation); +$moderation = str_replace("\n","
",$moderation); +echo "All of these errors found have been fixed automatically. These errors only affect the operation of Community Applications. The template may have other errors present

$moderation"; +?> + diff --git a/source/community.applications/usr/local/emhttp/plugins/community.applications/scripts/showIncompatible.php b/source/community.applications/usr/local/emhttp/plugins/community.applications/scripts/showIncompatible.php new file mode 100644 index 00000000..48f07ee1 --- /dev/null +++ b/source/community.applications/usr/local/emhttp/plugins/community.applications/scripts/showIncompatible.php @@ -0,0 +1,11 @@ +"; +if ( ! $moderation ) { + echo "

No incompatible apps found
"; + return; +} +echo "While highly not recommended to do, incompatible applications can be installed by enabling Display Incompatible Applications within CA's General Settings

$moderation"; +?> + diff --git a/source/community.applications/usr/local/emhttp/plugins/community.applications/scripts/showInfo.php b/source/community.applications/usr/local/emhttp/plugins/community.applications/scripts/showInfo.php new file mode 100644 index 00000000..7318e4c6 --- /dev/null +++ b/source/community.applications/usr/local/emhttp/plugins/community.applications/scripts/showInfo.php @@ -0,0 +1,59 @@ +",$appInformation); + $appInformation = str_replace("[","<",$appInformation); + $appInformation = str_replace("]",">",$appInformation); + } + $appInformation .= "


"; + $appInformation .= $template['Support'] ? "" : ""; + $appInformation .= $template['Project'] ? "" : ""; + $appInformation .= $template['WebPageURL'] ? "" : ""; + $appInformation .= "
Support ThreadProject PageWeb Page


"; + if ( ($donatelink) && ($donateimg) ) { + $appInformation .= "
$donatetext
"; + if ( $template['RepoName'] != "Squid's plugin Repository" ) { + $appInformation .= "
The above link is set by the author of the template, not the author of Community Applications
"; + } + } + $appInformation = "$appInformation"; + echo "
"; + echo $appInformation; + echo "
"; + +?> diff --git a/source/community.applications/usr/local/emhttp/plugins/community.applications/scripts/showInvalid.php b/source/community.applications/usr/local/emhttp/plugins/community.applications/scripts/showInvalid.php new file mode 100644 index 00000000..e3f9a8a6 --- /dev/null +++ b/source/community.applications/usr/local/emhttp/plugins/community.applications/scripts/showInvalid.php @@ -0,0 +1,13 @@ +"; +if ( ! $moderation ) { + echo "

No invalid templates found
"; + return; +} +$moderation = str_replace(" "," ",$moderation); +$moderation = str_replace("\n","
",$moderation); +echo "These templates are invalid and the application they are referring to is unknown

$moderation"; +?> + diff --git a/source/community.applications/usr/local/emhttp/plugins/community.applications/scripts/showModeration.php b/source/community.applications/usr/local/emhttp/plugins/community.applications/scripts/showModeration.php new file mode 100644 index 00000000..712ebe28 --- /dev/null +++ b/source/community.applications/usr/local/emhttp/plugins/community.applications/scripts/showModeration.php @@ -0,0 +1,12 @@ +"; +if ( ! $moderation ) { + echo "

No moderation entries found
"; +} +$moderation = str_replace(" "," ",$moderation); +$moderation = str_replace("\n","
",$moderation); +echo "$moderation"; +?> + diff --git a/source/community.applications/usr/local/emhttp/plugins/community.applications/scripts/showNoSupport.php b/source/community.applications/usr/local/emhttp/plugins/community.applications/scripts/showNoSupport.php new file mode 100644 index 00000000..27333ac7 --- /dev/null +++ b/source/community.applications/usr/local/emhttp/plugins/community.applications/scripts/showNoSupport.php @@ -0,0 +1,11 @@ +"; +if ( ! $moderation ) { + echo "

All applications have support threads
"; + return; +} +echo "These applications do not have any support thread specified by the template author.

$moderation"; +?> + diff --git a/source/community.applications/usr/local/emhttp/plugins/community.applications/scripts/updatePLG.sh b/source/community.applications/usr/local/emhttp/plugins/community.applications/scripts/updatePLG.sh new file mode 100644 index 00000000..6dac576a --- /dev/null +++ b/source/community.applications/usr/local/emhttp/plugins/community.applications/scripts/updatePLG.sh @@ -0,0 +1,7 @@ +#!/bin/bash + +echo Getting update information... +/usr/local/emhttp/plugins/dynamix.plugin.manager/scripts/plugin check "$1" > /dev/null 2>&1 +echo Installing update... +/usr/local/emhttp/plugins/dynamix.plugin.manager/scripts/plugin update "$1" + diff --git a/source/community.applications/usr/local/emhttp/plugins/community.applications/skins/default.skin b/source/community.applications/usr/local/emhttp/plugins/community.applications/skins/default.skin new file mode 100644 index 00000000..303674ac --- /dev/null +++ b/source/community.applications/usr/local/emhttp/plugins/community.applications/skins/default.skin @@ -0,0 +1,26 @@ +{ + "icon": { + "templateWidth": 220, + "header": "
", + "sol": "
", + "template": "
%75$sAuthor: %59$s
%40$s
%43$s%41$s
%65$s
%66$s
%46$s%45$s%44$s
%68$s%69$s%70$s%71$s%72$s%73$s%74$s
%58$s
%56$s
", + "eol": "
", + "footer": "
" + }, + "detail": { + "templateWidth": 600, + "header": "
", + "sol": "
", + "template": "
%75$sAuthor: %59$s
%40$s
%43$s%41$s
%65$s
%66$s
%46$s%45$s%44$s
%58$s
%56$s
Categories: %21$s
%57$s
%22$s%64$s

%39$s%38$s
%68$s%69$s%70$s%71$s%72$s%73$s%74$s

%37$s%36$s%48$s
%35$s
", + "eol": "
", + "footer": "
" + }, + "table": { + "templateWidth": 1280, + "header": "", + "sol": "", + "template": "", + "eol": "", + "footer": "
ApplicationDownloadsAuthorDescriptionRepository
%75$s%66$s
%47$s %46$s %45$s %44$s   %43$s
%41$s
%60$s
%58$s
%68$s%69$s%70$s%71$s%72$s%73$s%74$s
%42$s %59$s Categories: %21$s

%22$s%64$s
%39$s %38$s
%37$s    %36$s    %48$s    %35$s
%40$s
" + } +} \ No newline at end of file diff --git a/source/community.applications/usr/local/emhttp/plugins/community.applications/skins/legacy.skin b/source/community.applications/usr/local/emhttp/plugins/community.applications/skins/legacy.skin new file mode 100644 index 00000000..e54fe86e --- /dev/null +++ b/source/community.applications/usr/local/emhttp/plugins/community.applications/skins/legacy.skin @@ -0,0 +1,23 @@ +{ + "icon": { + "header": "", + "sol": "", + "template": "", + "eol": "", + "footer": "
%75$sAuthor: %59$s
%40$s
%43$s%41$s
%65$s
%66$s
%46$s%45$s%44$s
%68$s%69$s%70$s%71$s%72$s%73$s%74$s
%58$s
%56$s
" + }, + "detail": { + "header": "", + "sol": "", + "template": "", + "footer": "
%75$sAuthor: %59$s
%40$s
%43$s%41$s
%65$s
%66$s
%46$s%45$s%44$s
%58$s
%56$s
Categories: %21$s
%57$s
%22$s%64$s

%39$s%38$s
%68$s%69$s%70$s%71$s%72$s%73$s%74$s

%37$s%36$s%48$s
%35$s
", + "eol": "

" + }, + "table": { + "header": "", + "sol": "", + "template": "", + "eol": "", + "footer": "
ApplicationDownloadsAuthorDescriptionRepository
%75$s%66$s
%47$s %46$s %45$s %44$s   %43$s
%41$s
%60$s
%58$s
%68$s%69$s%70$s%71$s%72$s%73$s%74$s
%42$s %59$s Categories: %21$s

%22$s'
%39$s %38$s
%37$s    %36$s    %48$s    %35$s
%40$s
" + } +} \ No newline at end of file diff --git a/source/community.applications/usr/local/emhttp/plugins/community.applications/styles/tooltipster.css b/source/community.applications/usr/local/emhttp/plugins/community.applications/styles/tooltipster.css new file mode 100644 index 00000000..a0148326 --- /dev/null +++ b/source/community.applications/usr/local/emhttp/plugins/community.applications/styles/tooltipster.css @@ -0,0 +1,56 @@ +.tooltipster-fall,.tooltipster-grow.tooltipster-show{-webkit-transition-timing-function:cubic-bezier(.175,.885,.32,1);-moz-transition-timing-function:cubic-bezier(.175,.885,.32,1.15);-ms-transition-timing-function:cubic-bezier(.175,.885,.32,1.15);-o-transition-timing-function:cubic-bezier(.175,.885,.32,1.15)} +.tooltipster-base{display:flex;pointer-events:none;position:absolute} +.tooltipster-box{flex:1 1 auto} +.tooltipster-content{box-sizing:border-box;max-height:100%;max-width:100%;overflow:auto} +.tooltipster-ruler{bottom:0;left:0;overflow:hidden;position:fixed;right:0;top:0;visibility:hidden} +.tooltipster-fade{opacity:0;-webkit-transition-property:opacity;-moz-transition-property:opacity;-o-transition-property:opacity;-ms-transition-property:opacity;transition-property:opacity} +.tooltipster-fade.tooltipster-show{opacity:1} +.tooltipster-grow{-webkit-transform:scale(0,0);-moz-transform:scale(0,0);-o-transform:scale(0,0);-ms-transform:scale(0,0);transform:scale(0,0);-webkit-transition-property:-webkit-transform;-moz-transition-property:-moz-transform;-o-transition-property:-o-transform;-ms-transition-property:-ms-transform;transition-property:transform;-webkit-backface-visibility:hidden} +.tooltipster-grow.tooltipster-show{-webkit-transform:scale(1,1);-moz-transform:scale(1,1);-o-transform:scale(1,1);-ms-transform:scale(1,1);transform:scale(1,1);-webkit-transition-timing-function:cubic-bezier(.175,.885,.32,1.15);transition-timing-function:cubic-bezier(.175,.885,.32,1.15)} +.tooltipster-swing{opacity:0;-webkit-transform:rotateZ(4deg);-moz-transform:rotateZ(4deg);-o-transform:rotateZ(4deg);-ms-transform:rotateZ(4deg);transform:rotateZ(4deg);-webkit-transition-property:-webkit-transform,opacity;-moz-transition-property:-moz-transform;-o-transition-property:-o-transform;-ms-transition-property:-ms-transform;transition-property:transform} +.tooltipster-swing.tooltipster-show{opacity:1;-webkit-transform:rotateZ(0);-moz-transform:rotateZ(0);-o-transform:rotateZ(0);-ms-transform:rotateZ(0);transform:rotateZ(0);-webkit-transition-timing-function:cubic-bezier(.23,.635,.495,1);-webkit-transition-timing-function:cubic-bezier(.23,.635,.495,2.4);-moz-transition-timing-function:cubic-bezier(.23,.635,.495,2.4);-ms-transition-timing-function:cubic-bezier(.23,.635,.495,2.4);-o-transition-timing-function:cubic-bezier(.23,.635,.495,2.4);transition-timing-function:cubic-bezier(.23,.635,.495,2.4)} +.tooltipster-fall{-webkit-transition-property:top;-moz-transition-property:top;-o-transition-property:top;-ms-transition-property:top;transition-property:top;-webkit-transition-timing-function:cubic-bezier(.175,.885,.32,1.15);transition-timing-function:cubic-bezier(.175,.885,.32,1.15)} +.tooltipster-fall.tooltipster-initial{top:0!important} +.tooltipster-fall.tooltipster-dying{-webkit-transition-property:all;-moz-transition-property:all;-o-transition-property:all;-ms-transition-property:all;transition-property:all;top:0!important;opacity:0} +.tooltipster-slide{-webkit-transition-property:left;-moz-transition-property:left;-o-transition-property:left;-ms-transition-property:left;transition-property:left;-webkit-transition-timing-function:cubic-bezier(.175,.885,.32,1);-webkit-transition-timing-function:cubic-bezier(.175,.885,.32,1.15);-moz-transition-timing-function:cubic-bezier(.175,.885,.32,1.15);-ms-transition-timing-function:cubic-bezier(.175,.885,.32,1.15);-o-transition-timing-function:cubic-bezier(.175,.885,.32,1.15);transition-timing-function:cubic-bezier(.175,.885,.32,1.15)} +.tooltipster-slide.tooltipster-initial{left:-40px!important} +.tooltipster-slide.tooltipster-dying{-webkit-transition-property:all;-moz-transition-property:all;-o-transition-property:all;-ms-transition-property:all;transition-property:all;left:0!important;opacity:0} +@keyframes tooltipster-fading{0%{opacity:0}100%{opacity:1}} +.tooltipster-update-fade{animation:tooltipster-fading .4s} +@keyframes tooltipster-rotating{25%{transform:rotate(-2deg)}75%{transform:rotate(2deg)}100%{transform:rotate(0)}} +.tooltipster-update-rotate{animation:tooltipster-rotating .6s} +@keyframes tooltipster-scaling{50%{transform:scale(1.1)}100%{transform:scale(1)}} +.tooltipster-update-scale{animation:tooltipster-scaling .6s} +/*.tooltipster-sidetip .tooltipster-box{background:#565656;border:2px solid #000;border-radius:4px}*/ +.tooltipster-sidetip .tooltipster-box{border-radius:5px;border:none;border-bottom:3px solid #478406;background: -webkit-radial-gradient(#303030,#000000);background: linear-gradient(#303030,#000000)} +.tooltipster-sidetip.tooltipster-bottom .tooltipster-box{margin-top:8px} +.tooltipster-sidetip.tooltipster-left .tooltipster-box{margin-right:8px} +.tooltipster-sidetip.tooltipster-right .tooltipster-box{margin-left:8px} +/*.tooltipster-sidetip.tooltipster-top .tooltipster-box{margin-bottom:8px}*/ +.tooltipster-sidetip.tooltipster-top .tooltipster-box{margin-bottom:7px} +/*.tooltipster-sidetip .tooltipster-content{color:#fff;line-height:18px;padding:6px 14px}*/ +.tooltipster-sidetip .tooltipster-content{color:#fff;padding:8px 16px} +.tooltipster-sidetip .tooltipster-arrow{overflow:hidden;position:absolute} +.tooltipster-sidetip.tooltipster-bottom .tooltipster-arrow{height:10px;margin-left:-10px;top:0;width:20px} +.tooltipster-sidetip.tooltipster-left .tooltipster-arrow{height:20px;margin-top:-10px;right:0;top:0;width:10px} +.tooltipster-sidetip.tooltipster-right .tooltipster-arrow{height:20px;margin-top:-10px;left:0;top:0;width:10px} +.tooltipster-sidetip.tooltipster-top .tooltipster-arrow{bottom:0;height:10px;margin-left:-10px;width:20px} +.tooltipster-sidetip .tooltipster-arrow-background,.tooltipster-sidetip .tooltipster-arrow-border{height:0;position:absolute;width:0} +/*.tooltipster-sidetip .tooltipster-arrow-background{border:10px solid transparent}*/ +.tooltipster-sidetip .tooltipster-arrow-background{display:none} +.tooltipster-sidetip.tooltipster-bottom .tooltipster-arrow-background{border-bottom-color:#565656;left:0;top:3px} +.tooltipster-sidetip.tooltipster-left .tooltipster-arrow-background{border-left-color:#565656;left:-3px;top:0} +.tooltipster-sidetip.tooltipster-right .tooltipster-arrow-background{border-right-color:#565656;left:3px;top:0} +.tooltipster-sidetip.tooltipster-top .tooltipster-arrow-background{border-top-color:#565656;left:0;top:-3px} +.tooltipster-sidetip .tooltipster-arrow-border{border:10px solid transparent;left:0;top:0} +/*.tooltipster-sidetip.tooltipster-bottom .tooltipster-arrow-border{border-bottom-color:#000}*/ +.tooltipster-sidetip.tooltipster-bottom .tooltipster-arrow-border{border-bottom-color:#2a2a2a} +/*.tooltipster-sidetip.tooltipster-left .tooltipster-arrow-border{border-left-color:#000}*/ +.tooltipster-sidetip.tooltipster-left .tooltipster-arrow-border{border-left-color:#2a2a2a} +/*.tooltipster-sidetip.tooltipster-right .tooltipster-arrow-border{border-right-color:#000}*/ +.tooltipster-sidetip.tooltipster-right .tooltipster-arrow-border{border-right-color:#2a2a2a} +/*.tooltipster-sidetip.tooltipster-top .tooltipster-arrow-border{border-top-color:#000}*/ +.tooltipster-sidetip.tooltipster-top .tooltipster-arrow-border{border-top-color:#478406} +.tooltipster-sidetip .tooltipster-arrow-uncropped{position:relative} +.tooltipster-sidetip.tooltipster-bottom .tooltipster-arrow-uncropped{top:-10px} +.tooltipster-sidetip.tooltipster-right .tooltipster-arrow-uncropped{left:-10px} diff --git a/webImages/Warning2.png b/webImages/Warning2.png new file mode 100644 index 00000000..8f6f9296 Binary files /dev/null and b/webImages/Warning2.png differ