From 2676ed099db74baf470b5f69a7486561b326e6e4 Mon Sep 17 00:00:00 2001 From: arabcoders Date: Sat, 7 Jun 2025 23:40:59 +0300 Subject: [PATCH] support pywebview --- .gitignore | 2 + .vscode/settings.json | 3 + Pipfile | 1 + Pipfile.lock | 185 ++++++++++++++++++++------------------ app.spec | 75 +++++++++++----- app/library/HttpAPI.py | 9 +- app/library/HttpSocket.py | 4 +- app/main.py | 24 ++--- app/native.py | 77 ++++++++++++++-- 9 files changed, 245 insertions(+), 135 deletions(-) diff --git a/.gitignore b/.gitignore index d01e6df6..c107c809 100644 --- a/.gitignore +++ b/.gitignore @@ -33,3 +33,5 @@ var/* __pycache__ .venv .idea +dist +build diff --git a/.vscode/settings.json b/.vscode/settings.json index 739b5a00..b404a990 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -38,6 +38,8 @@ "httpx", "levelno", "libcurl", + "libjavascriptcoregtk", + "libwebkit", "libx", "matroska", "mbed", @@ -55,6 +57,7 @@ "preferredcodec", "preferredquality", "printtraffic", + "pywebview", "quicktime", "rtime", "smhd", diff --git a/Pipfile b/Pipfile index eb4d274f..9965dae3 100644 --- a/Pipfile +++ b/Pipfile @@ -24,6 +24,7 @@ brotlicffi = "*" anyio = "*" pycryptodome = "*" yt-dlp = "*" +platformdirs = "*" [dev-packages] diff --git a/Pipfile.lock b/Pipfile.lock index f6be127e..c4577005 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "48fcd9e2b5944d90ebb226668ac120414836e416bea2685411b1c0184f29d7df" + "sha256": "382681436129497dab967014f5f951dfac0308eaa5e77f2b6d75813302d67f46" }, "pipfile-spec": 6, "requires": { @@ -35,96 +35,96 @@ }, "aiohttp": { "hashes": [ - "sha256:00d801ad3485c43f2d630c430bb023f7c22eb7621bd8a6f83dd328e730ec3cc4", - "sha256:05f1619126d679effcecac71caa186ffab93a6b03e638242c741653844a51f0e", - "sha256:0aa51ab3ed410b4e59381cf2ed8048ebafdc7d5690e80623c851e5451a6e8a0a", - "sha256:0cbddd75a04e09b969a550773ee6c00bb84bf020bcd4a2023667a4eec1d4905b", - "sha256:0e0992499b0ac711d58dbf17e896335b37fa7a6b6b683d6687bc826d639065c4", - "sha256:11de2738af979dcdf25debbea45a7dbbbf03d4ad6ecaeb93bc387005bb2a627d", - "sha256:127690e5eb2546a43bea7131094028fc029d150f2b5076f85cfbc25b3061861d", - "sha256:14dcdbeac2c1d35c632e2feb4946958d04eb734b3866d43d94bac257febefcf7", - "sha256:151129084b08223b7fb425e06536f68c54bb6e3e7aec096f795170dbad516d29", - "sha256:19a8d362b222a40fe97cd1641ce5c6a1fb2b2fbe2cf247d514f84f9c1d0f5549", - "sha256:1a9a616ce193b3118e458dde1642e142790fd9ed4cf3ac137fa8dc6e1d8916c5", - "sha256:1ad8d06941d3309909972b36ac7bee559ec35ca2129414309dc550ee5fc8ab31", - "sha256:203cd1122278b33c60bc4d6f63eabb1ba5f4841f9582a20ccd6dcfba99ee8c5c", - "sha256:215db70f6b6d01f4755763a11f9c277ad5828fad348df3eb4cb67e23fe829492", - "sha256:22b43ecd749901f63513d87333d16faeeecfe9d7d61733f27dd2c72602abd2e5", - "sha256:2a632c874c102316f94fce1a76aa7dc9d3b2c19b0c6f9a971158618e53429bc3", - "sha256:2c2dc19ab7d59aada559c3c96f4373d5c01794d53c1a18f0d745cf6843e5a917", - "sha256:2decb66dc0c2d4ab3e4a93df23cdede83dd137143e4d3e5eb5731582244d04f4", - "sha256:2f42c1a05a852ff1b8047ef3e5b9481e6ad9905feeb46b51178e27d8d0fb799e", - "sha256:2f61943e0c0e492ec701445b36c1ea43b5f196a79639ac799f9a89f3baeb2cf9", - "sha256:303ddf7efcfa7ba38c1ee9f4d72184afa9585a713ff057daa8b2e11af42ef1e0", - "sha256:318587425795f16e612750cad5d4f1e4e86f5d36ef6e35796fa4259c794973d6", - "sha256:3b35e461e0e99b438ab61de6d687fcc3b6f68c0bc41dab64b4e5021786d445aa", - "sha256:43f6923780b0d12c2e059710e5fe02be357d53e066d87a1129d47fe1ffd80ec5", - "sha256:4f20e14d553a73a41d6d8e87ca1d44eebfbac100addfd2c38459e8a6e93b065d", - "sha256:51ecc537774f0a1c9ed7054d8ac86cb1cbfe6b053a0a9899782dd4d6f83a2c4f", - "sha256:52f7666b76437f317bb3699b28462b5ebceba5f2dd66ed3fab4f3b1dd68d3968", - "sha256:53e2bb3179c78ab4dc693d17b1b94d8cc0127150fc559085dd2fac0a782db019", - "sha256:5aa6eebe6e5a62c630f8b53d9925f94c30d12e03b7dcf21db377295b0ef3c232", - "sha256:5b5e97582eb3d1674d0130c605508da18dc6b2a2f52a01f4476b27f056594ffe", - "sha256:5e24090aa1968191a3b15ae078ed5ce4d12a9b43b4d7fba1ae064cc519134385", - "sha256:65dab452be7b11e58af797b824191dbf6727a89f61e52ddd6508bbcd3dcff1df", - "sha256:680832b26b09a2784f93b94d894bfc7709441552293a5773e712fafaec1716ba", - "sha256:6c1fcfcc77fc9a4a9abcb4f01fe658d02e15b0446cef81010ba6945cbcb743f4", - "sha256:705d10796f3a0bb7cd473f6fc2918eb3629b1a85aa3eca872e34d3b11c9895ac", - "sha256:71df8e89efa091578f1a078ea9253668ef63bc0d9fc14e4e8072c60ddfe03733", - "sha256:7a8af50e5ef94e59781a5848ce0e254f9d08465e431a49f79609e3723db95fcb", - "sha256:7c032210a3c5477269ba414bc4eec2689630509184cecceda80c746325fcd946", - "sha256:8292511a577d2d21ca85ee73d917bde3c76532beefbd74640b25e6e0f5f6eb61", - "sha256:82d4deeef4b09e9f8526f1d677b1892d895360f54c358ca9f0e596a30c9ee947", - "sha256:8419434bb1cf3603d5fa0eddd7501d0b679db3b3c30175d40606e39dab6a141f", - "sha256:8431f29223bbb5f9f0f6e0f110c21adfc59e685805bd3b2adf5526eac680bba4", - "sha256:86e131555eb41dd058aaab8736ae6f123071585a86ada1526547688046e50e26", - "sha256:870326b74e23a2d6960096630830b6f20c0f87ea291ff6271a878d9a2db62174", - "sha256:87565e6a4b263fa8e0c08dfdda08d4734075a754fed573d5bd49bf35b3464761", - "sha256:883d923cef0393ab6c2bc177b3aa65eacb95fd3aa4f5d00cdc38c9670fc24c18", - "sha256:884e519a921a62816cfe20bf65243f03868b9d02f13c3d9577e18c55b63b1454", - "sha256:8bf5b5829e006bcd7ae31d44d4afad085a88176f896f33ed36197fbc52cb2eb9", - "sha256:8e702963f298fa471c046b38ea50992328afa1120f1c714be38e5a0e0eaa50b7", - "sha256:91401ae05e711689c8f02e4b3f72ae8a14390a31036e5c7d86d1fc6c9e14fb40", - "sha256:96220c5ee843d0c497d381a080f420f06e2be638589cded9c5ca23e8b36619cb", - "sha256:986ec1b4ff9ca0842259d943b925af2a546ca055cb6ac22062cf3443e9ad844b", - "sha256:9883d6bcccba88d4637e1b67734089b9e2a2f8a34dbf5171deedb4d61730afe7", - "sha256:a1f57c15b139bfdc5620be94d9abfe340924c665fb0fc9331a340ca5ffeb3282", - "sha256:a8e439e439d28e8a45b2ca3ca3bbc154d1f5490e06b637b6e62cb20daa94d221", - "sha256:a9871b1b1381f8d8241f3ff3de5fcb6e2fdcfe8af43c35bb0496b8be550c5fb9", - "sha256:ad9f688da4a971c1c47653ada8169066312eb1798fe860035867eb3dfd2df311", - "sha256:b5beaba7fa473e017b6fe0e78f29613a10843218f6891f41e8fa69e27dff68c5", - "sha256:b6142f26c9d3f00f869e262d7cd3e4505c515218e08ea206703a789cd671ded6", - "sha256:b6d8cdff8cc07ae46b4605781f46ad4cce74284185db0dfd787940aa81de9886", - "sha256:b8c0cbb43ccf56ac22db8aeaab3282ad232123f1cc1cd049d4935482663c7df0", - "sha256:b8d96ecf7afe08029723e2fc7432ec4afb45f57cd3ec788402cba31e11704d0a", - "sha256:b97302588e67d973bfae16bf9dfee22fcc6c10478275d53baf00d827420ecdb8", - "sha256:b9cc720fe9b89dffde534ac470d231f5ab867b6866ae3d3c3005dd7890b3bafc", - "sha256:ba6cf68c33434e9f07f28e56847533116f1be260fdf4f2fd6faba8d0d972e62c", - "sha256:bbc0f9a9bd68da5ef54179329d2a5ff86d7b8cded12fb13c06950f7fb5e8ae51", - "sha256:bc13c484d21ffc819b0e569e1b036ee6b6c5346436619d22e7bfb62e1fa6e916", - "sha256:bc8188293ec4b5dfddef05bde32b180e927e7e89c78dd29a7fe629181f87b753", - "sha256:c323f4c105bdcf586f749822738ba6c8176123619e4e2444a6ec2a8b0adab5ce", - "sha256:c7178ddb1b4137b2076e652d8d507147d20b6cfa7a64d26bc32c6a099f423528", - "sha256:cc60b450ceb4cc4e394cbff805ea81ceaaf0a4cec69af4ac31b165028aa28045", - "sha256:cd4560a16f6370c395bc9022ca6d785dd3dc15873dd3846039bb1c2c4d515ed0", - "sha256:d031808192703259a49da1e8b4cad95eb8b076de326b432f69495dedb7405e11", - "sha256:d6a8d01459299a34248fee73bdd92ee1d784f6efee61082e8912049bb6196ad0", - "sha256:d9a412c89f68f3f00ee3afe9b754c882b3a59c0de9826ebfd19451077555b71f", - "sha256:db8d26b8e901502fd3f9c2bb5d466beb35ebc8c02877bf844789f4b4d87a37ab", - "sha256:de571f72057833604a7620ad627d0b71bd0288a29a75384f8b97b7ba1dd5bfd7", - "sha256:e093a24605e8cf71d8bccd54672581a72404b84fa3adafa2c416b67edff1ced1", - "sha256:e1c04b27b8a87692a061fbd38b495f5dae0f7f114d755d71528978edd2f06c4a", - "sha256:e325c1248f3c146a7c794259666e1a0213d5d20b3cf229217755031e5419d5d9", - "sha256:e6b713c983907b2dffb114b3e1573d3ff97fb912507d82dfe9dd7629ca72d963", - "sha256:f040d9c100ea258e8bd8fa0f0853734afb640cbe7c8ed060826f1c2cde0c9fee", - "sha256:f06c6f233123280b9ac1023051b62a1444745f7e92c6196ae21dd74fa52696e2", - "sha256:f077b809f40bbb56e131d4e7170a840a1f3508da42cb1006503ea92dae56eb8b", - "sha256:f10f267b7cbb25b40d9e396b4fec7d0ab68022970749b7e9755c53e00f6666ab", - "sha256:f353d8ba1bb7ba8ddc741949bfa576f7cf7a37464e1b32e94c61fb872adc9918" + "sha256:019d6075bc18fdc1e47e9dabaf339c9cc32a432aca4894b55e23536919640d87", + "sha256:0329934d4df1500f13449c1db205d662123d9d0ee1c9d0c8c0cb997cdac75710", + "sha256:063b0de9936ed9b9222aa9bdf34b1cc731d34138adfc4dbb1e4bbde1ab686778", + "sha256:06e18aaa360d59dd25383f18454f79999915d063b7675cf0ac6e7146d1f19fd1", + "sha256:104f1f9135be00c8a71c5fc53ac7d49c293a8eb310379d2171f0e41172277a09", + "sha256:109b3544138ce8a5aca598d5e7ff958699e3e19ee3675d27d5ee9c2e30765a4a", + "sha256:1226325e98e6d3cdfdaca639efdc3af8e82cd17287ae393626d1bd60626b0e93", + "sha256:144d67c29ae36f052584fc45a363e92798441a5af5762d83037aade3e2aa9dc5", + "sha256:14aa6f41923324618687bec21adf1d5e8683264ccaa6266c38eb01aeaa404dea", + "sha256:1585fefa6a62a1140bf3e439f9648cb5bf360be2bbe76d057dddd175c030e30c", + "sha256:15e1da30ac8bf92fb3f8c245ff53ace3f0ea1325750cc2f597fb707140dfd950", + "sha256:196fbd7951b89d9a4be3a09e1f49b3534eb0b764989df66b429e8685138f8d27", + "sha256:1df121c3ffcc5f7381cd4c84e8554ff121f558e92c318f48e049843b47ee9f1b", + "sha256:210470f8078ecd1f596247a70f17d88c4e785ffa567ab909939746161f304444", + "sha256:22e2874e665c771e6c87e81f8d4ac64d999da5e1a110b3ae0088b035529a08d5", + "sha256:2601c1fcd9b67e632548cfd3c760741b31490502f6f3e5e21287678c1c6fa1b2", + "sha256:27e75e96a4a747756c2f59334e81cbb9a398e015bc9e08b28f91090e5f3a85ef", + "sha256:29f642b386daf2fadccbcd2bc8a3d6541a945c0b436f975c3ce0ec318b55ad6e", + "sha256:2a06b2a031d6c828828317ee951f07d8a0455edc9cd4fc0e0432fd6a4dfd612d", + "sha256:2af98debfdfcc52cae5713bbfbfe3328fc8591c6f18c93cf3b61749de75f6ef2", + "sha256:340ee38cecd533b48f1fe580aa4eddfb9c77af2a80c58d9ff853b9675adde416", + "sha256:39d29b6888ddd5a120dba1d52c78c0b45f5f34e227a23696cbece684872e62bd", + "sha256:3d222c693342ccca64320410ada8f06a47c4762ff82de390f3357a0e51ca102c", + "sha256:405a60b979da942cec2c26381683bc230f3bcca346bf23a59c1dfc397e44b17b", + "sha256:421ca03e2117d8756479e04890659f6b356d6399bbdf07af5a32d5c8b4ace5ac", + "sha256:47f7735b7e44965bd9c4bde62ca602b1614292278315e12fa5afbcc9f9180c28", + "sha256:4b603513b4596a8b80bfbedcb33e9f8ed93f44d3dfaac97db0bb9185a6d2c5c0", + "sha256:4f1f92cde9d9a470121a0912566585cf989f0198718477d73f3ae447a6911644", + "sha256:554f4338611155e7d2f0dc01e71e71e5f6741464508cbc31a74eb35c9fb42982", + "sha256:590e5d792150d75fa34029d0555b126e65ad50d66818a996303de4af52b65b32", + "sha256:5c981b7659379b5cb3b149e480295adfcdf557b5892a792519a56badbe9f33ef", + "sha256:5fadc4b67f972a701805aa501cd9d22cdbeda21f9c9ae85e60678f84b1727a16", + "sha256:644f74197757e26266a5f57af23424f8cd506c1ef70d9b288e21244af69d6fdc", + "sha256:65952736356d1fbc9efdd17492dce36e2501f609a14ccb298156e392d3ad8b83", + "sha256:6b73299e4bf37d14c6e4ca5ce7087b44914a8d9e1f40faedc271f28d64ec277e", + "sha256:726d9a15a1fd1058b2d27d094b1fec627e9fd92882ca990d90ded9b7c550bd21", + "sha256:734e64ceb8918b3d7099b2d000e174d8d944fb7d494de522cecb0fa45ffcb0cd", + "sha256:760846271518d649be968cee1b245b84d348afe896792279312ca758511d798f", + "sha256:7a0ecae011f2f779271407f2959877230670de3c48f67e5db9fbafa9fddbfa3a", + "sha256:7c345f7e7f10ac21a48ffd387c04a17da06f96bd087d55af30d1af238e9e164d", + "sha256:8437e3d8041d4a0d73a48c563188d5821067228d521805906e92f25576076f95", + "sha256:854132093e12dd77f5c07975581c42ae51a6a8868dcbbb509c77d1963c3713b7", + "sha256:87ece62697b8792e595627c4179f0eca4b038f39b0b354e67a149fa6f83d9493", + "sha256:8d353c5396964a79b505450e8efbfd468b0a042b676536505e8445d9ab1ef9ae", + "sha256:8d5b11ea794ee54b33d0d817a1aec0ef0dd2026f070b493bc5a67b7e413b95d4", + "sha256:8ddd775457180d149ca0dbc4ebff5616948c09fa914b66785e5f23227fec5a05", + "sha256:9c2a4dec596437b02f0c34f92ea799d6e300184a0304c1e54e462af52abeb0a8", + "sha256:9d9922bc6cca3bc7a8f8b60a3435f6bca6e33c8f9490f6079a023cfb4ee65af0", + "sha256:a01a21975b0fd5160886d9f2cd6ed13cdfc8d59f2a51051708ed729afcc2a2fb", + "sha256:a5149ae1b11ce4cf8b122846bfa3d7c5f29fe3bfe6745ab21b3eea9615bc5564", + "sha256:a7603f3998cd2893801d254072aaf1b5117183fcf5e726b6c27fc4239dc8c30a", + "sha256:a8a711883eedcd55f2e1ba218d8224b9f20f1dfac90ffca28e78daf891667e3a", + "sha256:aace119abc495cc4ced8745e3faceb0c22e8202c60b55217405c5f389b569576", + "sha256:afe8c1860fb0df6e94725339376628e915b2b85e734eca4d14281ed5c11275b0", + "sha256:b461f7918c8042e927f629eccf7c120197135bd2eb14cc12fffa106b937d051b", + "sha256:b4a36ae8bebb71276f1aaadb0c08230276fdadad88fef35efab11d17f46b9885", + "sha256:b54d4c3cd77cf394e71a7ad5c3b8143a5bfe105a40fc693bcdfe472a286f1d95", + "sha256:b63b3b5381791f96b07debbf9e2c4e909c87ecbebe4fea9dcdc82789c7366234", + "sha256:b795085d063d24c6d09300c85ddd6b9c49816d5c498b40b6899ca24584e936e4", + "sha256:bcf5791dcd63e1fc39f5b0d4d16fe5e6f2b62f0f3b0f1899270fa4f949763317", + "sha256:c6866da6869cc60d84921b55330d23cbac4f243aebfabd9da47bbc40550e6548", + "sha256:cb907dcd8899084a56bb13a74e9fdb49070aed06229ae73395f49a9ecddbd9b1", + "sha256:cb9af1ce647cda1707d7b7e23b36eead3104ed959161f14f4ebc51d9b887d4a2", + "sha256:ccef35cc9e96bb3fcd79f3ef9d6ae4f72c06585c2e818deafc4a499a220904a1", + "sha256:cd58a0fae0d13a44456953d43706f9457b231879c4b3c9d0a1e0c6e2a4913d46", + "sha256:cd749731390520a2dc1ce215bcf0ee1018c3e2e3cd834f966a02c0e71ad7d637", + "sha256:d211453930ab5995e99e3ffa7c5c33534852ad123a11761f1bf7810cd853d3d8", + "sha256:d28f7d2b68f4ef4006ca92baea02aa2dce2b8160cf471e4c3566811125f5c8b9", + "sha256:e4aec7c3ccf2ed6b55db39e36eb00ad4e23f784fca2d38ea02e6514c485866dc", + "sha256:e6cbaf3c02ef605b6f251d8bb71b06632ba24e365c262323a377b639bcfcbdae", + "sha256:e6fb2170cb0b9abbe0bee2767b08bb4a3dbf01583880ecea97bca9f3f918ea78", + "sha256:e8ccb376eaf184bcecd77711697861095bc3352c912282e33d065222682460da", + "sha256:ebcbc113f40e4c9c0f8d2b6b31a2dd2a9768f3fa5f623b7e1285684e24f5159f", + "sha256:efafc6f8c7c49ff567e0f02133b4d50eef5183cf96d4b0f1c7858d478e9751f6", + "sha256:efd174af34bd80aa07813a69fee000ce8745962e2d3807c560bdf4972b5748e4", + "sha256:f014d909931e34f81b0080b289642d4fc4f4a700a161bd694a5cebdd77882ab5", + "sha256:f20e4ec84a26f91adc8c54345a383095248d11851f257c816e8f1d853a6cef4c", + "sha256:f31bfeb53cfc5e028a0ade48ef76a3580016b92007ceb8311f5bd1b4472b7007", + "sha256:f36958b508e03d6c5b2ed3562f517feb415d7cc3a9b2255f319dcedb1517561a", + "sha256:f50c10bd5799d82a9effe90d5d5840e055a2c94e208b76f9ed9e6373ca2426fe", + "sha256:f6563fa3bfb79f892a24d3f39ca246c7409cf3b01a3a84c686e548a69e4fc1bf", + "sha256:f672d8dbca49e9cf9e43de934ee9fd6716740263a7e37c1a3155d6195cdef285", + "sha256:fa806cdb0b7e99fb85daea0de0dda3895eea6a624f962f3800dfbbfc07f34fb6", + "sha256:fb02a172c073b0aaf792f0b78d02911f124879961d262d3163119a3e91eec31d", + "sha256:fe3a9ae8a7c93bec5b7cfacfbc781ed5ae501cf6a6113cf3339b193af991eaf9", + "sha256:ff576cb82b995ff213e58255bc776a06ebd5ebb94a587aab2fb5df8ee4e3f967" ], "index": "pypi", "markers": "python_version >= '3.9'", - "version": "==3.12.10" + "version": "==3.12.11" }, "aiosignal": { "hashes": [ @@ -759,6 +759,15 @@ "markers": "python_version >= '3.7'", "version": "==1.47.0" }, + "platformdirs": { + "hashes": [ + "sha256:3d512d96e16bcb959a814c9f348431070822a6496326a4be0911c40b5a74c2bc", + "sha256:ff7059bb7eb1179e2685604f4aaf157cfd9535242bd23742eadc3c13542139b4" + ], + "index": "pypi", + "markers": "python_version >= '3.9'", + "version": "==4.3.8" + }, "propcache": { "hashes": [ "sha256:050b571b2e96ec942898f8eb46ea4bfbb19bd5502424747e83badc2d4a99a44e", diff --git a/app.spec b/app.spec index 88f20534..b3db6019 100644 --- a/app.spec +++ b/app.spec @@ -1,21 +1,60 @@ -# app.spec +import json +import os +import platform +import sys block_cipher = None +# Detect OS and architecture to include the correct GTK/WebKit libs +machine = platform.machine().lower() +binaries = [] +if sys.platform.startswith("linux"): + if machine in ("x86_64", "amd64"): + libdir = "/usr/lib/x86_64-linux-gnu" + elif machine in ("aarch64", "arm64"): + libdir = "/usr/lib/aarch64-linux-gnu" + else: + libdir = "/usr/lib" + binaries = [ + (os.path.join(libdir, "libwebkit2gtk-4.1.so.0"), "."), + (os.path.join(libdir, "libjavascriptcoregtk-4.1.so.0"), "."), + ] +elif sys.platform == "darwin": + binaries = [ + ("/Library/Frameworks/WebKit.framework/Versions/Current/WebKit", "."), + ] +elif sys.platform.startswith("win"): + # Windows DLLs go here (example paths) + binaries = [("C:\\\\path\\\\to\\\\WebKit2.dll", ".")] + +# pull in all your Pipfile.lock defaults as hidden-imports: +with open("Pipfile.lock") as f: + lock = json.load(f) + +hidden = [ + *list(lock.get("default", {}).keys()), + "aiohttp", + "socketio", + "engineio", + "engineio.async_drivers.aiohttp", + "socketio.async_drivers.aiohttp", +] + +hidden = [f.replace("-", "_") for f in hidden] + a = Analysis( - ['app/native.py'], - pathex=[], - binaries=[], + ["app/native.py"], # your entrypoint + pathex=["."], # make sure PyInstaller can find your code + binaries=binaries, datas=[ - ('ui/exported', 'ui/exported'), - ('app/migrations', 'migrations'), + ("ui/exported", "ui/exported"), + ("app/migrations", "migrations"), + ("app/library/presets.json", "library"), ], - hiddenimports=[], + hiddenimports=hidden, hookspath=[], runtime_hooks=[], excludes=[], - win_no_prefer_redirects=False, - win_private_assemblies=False, cipher=block_cipher, ) @@ -24,23 +63,13 @@ pyz = PYZ(a.pure, a.zipped_data, cipher=block_cipher) exe = EXE( pyz, a.scripts, - [], - exclude_binaries=True, - name='ytptube-native', - debug=False, - bootloader_ignore_signals=False, - strip=False, - upx=True, - console=False, -) - -coll = COLLECT( - exe, a.binaries, a.zipfiles, a.datas, + name="YTPTube", + debug=False, strip=False, upx=True, - upx_exclude=[], - name='ytptube-native' + console=False, + onefile=True, # ← this makes it a single-file bundle ) diff --git a/app/library/HttpAPI.py b/app/library/HttpAPI.py index 4fcc8b41..7050063d 100644 --- a/app/library/HttpAPI.py +++ b/app/library/HttpAPI.py @@ -85,6 +85,7 @@ class HttpAPI(Common): def __init__( self, + root_path: str, queue: DownloadQueue | None = None, encoder: Encoder | None = None, config: Config | None = None, @@ -94,7 +95,7 @@ class HttpAPI(Common): self.config = config or Config.get_instance() self._notify = EventBus.get_instance() - self.rootPath = str(Path(__file__).parent.parent.parent) + self.rootPath = root_path self.routes = web.RouteTableDef() self.cache = Cache() self.app: web.Application | None = None @@ -227,8 +228,10 @@ class HttpAPI(Common): """ staticDir = os.path.join(self.rootPath, "ui", "exported") if not os.path.exists(staticDir): - msg = f"Could not find the frontend UI static assets. '{staticDir}'." - raise ValueError(msg) + staticDir = os.path.join(self.rootPath, "..", "ui", "exported") + if not os.path.exists(staticDir): + msg = f"Could not find the frontend UI static assets. '{staticDir}'." + raise ValueError(msg) preloaded = 0 diff --git a/app/library/HttpSocket.py b/app/library/HttpSocket.py index 87496e56..58652591 100644 --- a/app/library/HttpSocket.py +++ b/app/library/HttpSocket.py @@ -50,8 +50,8 @@ class HttpSocket(Common): self.queue = queue or DownloadQueue.get_instance() self._notify = EventBus.get_instance() - #logger=True, engineio_logger=True, - self.sio = sio or socketio.AsyncServer(cors_allowed_origins="*") + # logger=True, engineio_logger=True, + self.sio = sio or socketio.AsyncServer(async_mode="aiohttp", cors_allowed_origins="*") encoder = encoder or Encoder() def emit(e: Event, _, **kwargs): diff --git a/app/main.py b/app/main.py index 168ed82c..ff7f3c98 100644 --- a/app/main.py +++ b/app/main.py @@ -23,16 +23,17 @@ from library.Tasks import Tasks LOG = logging.getLogger("app") MIME = magic.Magic(mime=True) +ROOT_PATH: Path = Path(__file__).parent.absolute() + class Main: def __init__(self): self._config = Config.get_instance() - self.rootPath = str(Path(__file__).parent.absolute()) self._app = web.Application() self._check_folders() - caribou.upgrade(self._config.db_file, os.path.join(self.rootPath, "migrations")) + caribou.upgrade(self._config.db_file, os.path.join(ROOT_PATH, "migrations")) connection = sqlite3.connect(database=self._config.db_file, isolation_level=None) connection.row_factory = sqlite3.Row @@ -50,7 +51,7 @@ class Main: pass self._queue = DownloadQueue(connection=connection) - self._http = HttpAPI(queue=self._queue) + self._http = HttpAPI(root_path=ROOT_PATH, queue=self._queue) self._socket = HttpSocket(queue=self._queue) self._app.on_cleanup.append(_close_connection) @@ -79,12 +80,14 @@ class Main: LOG.error(f"Could not create database file at '{self._config.db_file}'.") raise - def start(self, host: str | None = None, port: int | None = None): + def start(self, host: str | None = None, port: int | None = None, cb=None): """ Start the application. """ - EventBus.get_instance().sync_emit(Events.STARTUP, data={"app": self._app}) + host = host or self._config.host + port = port or self._config.port + EventBus.get_instance().sync_emit(Events.STARTUP, data={"app": self._app}) Scheduler.get_instance().attach(self._app) self._socket.attach(self._app) @@ -100,10 +103,10 @@ class Main: def started(_): LOG.info("=" * 40) - LOG.info( - f"YTPTube v{self._config.version} - started on http://{self._config.host}:{self._config.port}{self._config.base_path}" - ) + LOG.info(f"YTPTube v{self._config.version} - started on http://{host}:{port}{self._config.base_path}") LOG.info("=" * 40) + if cb: + cb() HTTP_LOGGER = None if self._config.access_log: @@ -113,12 +116,13 @@ class Main: web.run_app( self._app, - host=host or self._config.host, - port=port or self._config.port, + host=host, + port=port, reuse_port=True, loop=asyncio.get_event_loop(), access_log=HTTP_LOGGER, print=started, + handle_signals=cb is None, ) diff --git a/app/native.py b/app/native.py index b0d43ff6..6528a0e0 100644 --- a/app/native.py +++ b/app/native.py @@ -1,20 +1,79 @@ +import json +import logging +import os import socket import threading +from pathlib import Path + +# 1) create a global event +ready = threading.Event() + +APP_NAME = "YTPTube" try: import webview # type: ignore except ImportError as e: - msg = "Please install the 'webview' package to run this application." + msg = "Please install the 'pywebview' to run YTPTube in native mode." raise ImportError(msg) from e -if __name__ == "__main__": - host = "127.0.0.1" - with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s: - s.bind((host, 0)) - port = s.getsockname()[1] + +def set_env(): + import platformdirs + + dct = {} + + if not os.getenv("YTP_CONFIG_PATH"): + dct["YTP_CONFIG_PATH"] = platformdirs.user_config_dir(APP_NAME.lower(), "arabcoders", ensure_exists=True) + + if not os.getenv("YTP_TEMP_PATH"): + dct["YTP_TEMP_PATH"] = platformdirs.user_cache_dir(APP_NAME.lower(), "arabcoders", ensure_exists=True) + + if not os.getenv("YTP_DOWNLOAD_PATH"): + dct["YTP_DOWNLOAD_PATH"] = platformdirs.user_downloads_dir() + + if os.getenv("YTP_ACCESS_LOG", None) is None: + dct["YTP_ACCESS_LOG"] = "false" + + if len(dct) > 0: + os.environ.update(dct) + + +def app_start(host: str, port: int) -> None: + import asyncio from main import Main - threading.Thread(target=Main().start, args=(host, port), daemon=True).start() - webview.create_window("YTPTube", f"http://{host}:{port}") - webview.start() + try: + loop = asyncio.get_running_loop() + except RuntimeError: + loop = asyncio.new_event_loop() + asyncio.set_event_loop(loop) + + Main().start(host, port, cb=lambda: ready.set()) + + +if __name__ == "__main__": + host = "127.0.0.1" + + set_env() + + cfg = Path(os.getenv("YTP_CONFIG_PATH")) / "webview.json" + if cfg.exists(): + port = json.loads(cfg.read_text())["port"] + else: + logging.info(f"Creating configuration file at '{cfg}'.") + with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s: + s.bind((host, 0)) + port = s.getsockname()[1] + cfg.write_text(json.dumps({"port": port})) + + threading.Thread(target=app_start, args=(host, port), daemon=True).start() + + ready.wait() + + webview.create_window(APP_NAME, f"http://{host}:{port}") + webview.start( + debug=os.getenv("YTP_WV_DEBUG", "false").lower() in ("true", "1", "yes"), + storage_path=os.path.join(os.getenv("YTP_CONFIG_PATH", os.getcwd()), "webview"), + private_mode=False, + )