From 450869756380d12eee506fe6499c7e95a616e797 Mon Sep 17 00:00:00 2001 From: Vivianne Langdon Date: Wed, 27 Sep 2023 23:53:51 -0700 Subject: [PATCH 001/107] Update Post component, adding follow and unfollow methods. --- resources/assets/components/Post.vue | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/resources/assets/components/Post.vue b/resources/assets/components/Post.vue index 1cc57c84e..6b3361351 100644 --- a/resources/assets/components/Post.vue +++ b/resources/assets/components/Post.vue @@ -37,6 +37,8 @@ v-on:bookmark="handleBookmark()" v-on:share="shareStatus()" v-on:unshare="unshareStatus()" + v-on:follow="follow()" + v-on:unfollow="unfollow()" v-on:counter-change="counterChange" /> @@ -333,6 +335,30 @@ }) }, + follow() { + axios.post('/api/v1/accounts/' + this.post.account.id + '/follow') + .then(res => { + this.$store.commit('updateRelationship', [res.data]); + this.user.following_count++; + this.post.account.followers_count++; + }).catch(err => { + swal('Oops!', 'An error occurred when attempting to follow this account.', 'error'); + this.post.relationship.following = false; + }); + }, + + unfollow() { + axios.post('/api/v1/accounts/' + this.post.account.id + '/unfollow') + .then(res => { + this.$store.commit('updateRelationship', [res.data]); + this.user.following_count--; + this.post.account.followers_count--; + }).catch(err => { + swal('Oops!', 'An error occurred when attempting to unfollow this account.', 'error'); + this.post.relationship.following = true; + }); + }, + openContextMenu() { this.$nextTick(() => { this.$refs.contextMenu.open(); From 6c1e56fcb2bc5ffc135ba328aef496b8761a54c2 Mon Sep 17 00:00:00 2001 From: mbliznikova Date: Wed, 4 Oct 2023 19:02:55 +0000 Subject: [PATCH 002/107] Provide the error message if a file to upload is too large --- resources/assets/js/components/ComposeModal.vue | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/resources/assets/js/components/ComposeModal.vue b/resources/assets/js/components/ComposeModal.vue index 578679d32..a4737294a 100644 --- a/resources/assets/js/components/ComposeModal.vue +++ b/resources/assets/js/components/ComposeModal.vue @@ -1068,6 +1068,16 @@ export default { return App.util.format.timeAgo(ts); }, + formatBytes(bytes, decimals = 2) { + if (!+bytes) { + return '0 Bytes' + } + const dec = decimals < 0 ? 0 : decimals + const units = ['Bytes', 'KB', 'MB', 'GB', 'TB']; + const quotient = Math.floor(Math.log(bytes) / Math.log(1024)) + return `${parseFloat((bytes / Math.pow(1024, quotient)).toFixed(dec))} ${units[quotient]}` + }, + fetchProfile() { let tags = { public: 'Public', @@ -1178,6 +1188,13 @@ export default { }, 300); }).catch(function(e) { switch(e.response.status) { + case 413: + self.uploading = false; + io.value = null; + swal('File is too large', 'The file you uploaded has the size of ' + self.formatBytes(io.size) + '. Unfortunately, only images up to ' + self.formatBytes(self.config.uploader.max_photo_size * 1024) + ' are supported.\nPlease resize the file and try again.', 'error'); + self.page = 2; + break; + case 451: self.uploading = false; io.value = null; From e9d9c4d8cc2965fd0eb1ebfc31b96dfc9a6ff7d5 Mon Sep 17 00:00:00 2001 From: Andy Neillans Date: Wed, 11 Oct 2023 19:08:22 +0100 Subject: [PATCH 003/107] Strip tags from bio in embeds --- resources/views/profile/show.blade.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/views/profile/show.blade.php b/resources/views/profile/show.blade.php index d16eeb7c0..5107c0ab3 100644 --- a/resources/views/profile/show.blade.php +++ b/resources/views/profile/show.blade.php @@ -20,7 +20,7 @@ @endsection -@push('meta') +@push('meta') @if(false == $settings['crawlable'] || $profile->remote_url) @else From b838f90b776ce2bbc8dad797c3a4bf80f40f99c7 Mon Sep 17 00:00:00 2001 From: mbliznikova Date: Fri, 20 Oct 2023 21:09:29 +0000 Subject: [PATCH 004/107] Add check if collection is empty in Edit Collection before publishing --- .../js/components/CollectionComponent.vue | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/resources/assets/js/components/CollectionComponent.vue b/resources/assets/js/components/CollectionComponent.vue index dd7ebf433..3f77cfc13 100644 --- a/resources/assets/js/components/CollectionComponent.vue +++ b/resources/assets/js/components/CollectionComponent.vue @@ -205,12 +205,20 @@
+ +
@@ -201,10 +205,10 @@ -
+
-
+
@@ -236,7 +240,7 @@
-
+
@@ -337,7 +341,7 @@
-
+
-
+
@@ -368,7 +372,9 @@ @@ -376,20 +382,21 @@
-
-
+
@@ -524,7 +531,7 @@
-
+
When you tag someone, they are sent a notification.
For more information on tagging, click here.

-
+

Tagging someone is like mentioning them, with the option to make it private between you.

You can choose to tag someone in public or private mode. Public mode will allow others to see who you tagged in the post and private mode tagged users will not be shown to others.

-
+

Add Location

-
+
@@ -910,6 +923,7 @@ export default { }, namedPages: [ + 'filteringMedia', 'cropPhoto', 'tagPeople', 'addLocation', @@ -943,7 +957,6 @@ export default { cb(res.data); }) .catch(err => { - console.log(err); }) }) }, @@ -957,7 +970,6 @@ export default { cb(res.data); }) .catch(err => { - console.log(err); }) }) } @@ -1032,6 +1044,10 @@ export default { collectionsPage: 1, collectionsCanLoadMore: false, spoilerText: undefined, + isFilteringMedia: false, + filteringMediaTimeout: undefined, + filteringRemainingCount: 0, + isPosting: false, } }, @@ -1242,6 +1258,50 @@ export default { }); }, + mediaReorder(dir) { + const m = this.media; + const cur = this.carouselCursor; + const pla = m[cur]; + let res = []; + let cursor = 0; + + if(dir == 'prev') { + if(cur == 0) { + for (let i = cursor; i < m.length - 1; i++) { + res[i] = m[i+1]; + } + res[m.length - 1] = pla; + cursor = 0; + } else { + res = this.handleSwap(m, cur, cur - 1); + cursor = cur - 1; + } + } else { + if(cur == m.length - 1) { + res = m; + let lastItem = res.pop(); + res.unshift(lastItem); + cursor = m.length - 1; + } else { + res = this.handleSwap(m, cur, cur + 1); + cursor = cur + 1; + } + } + this.$nextTick(() => { + this.media = res; + this.carouselCursor = cursor; + }) + }, + + handleSwap(arr, index1, index2) { + if (index1 >= 0 && index1 < arr.length && index2 >= 0 && index2 < arr.length) { + const temp = arr[index1]; + arr[index1] = arr[index2]; + arr[index2] = temp; + return arr; + } + }, + compose() { let state = this.composeState; @@ -1254,8 +1314,15 @@ export default { return; } + switch(state) { - case 'publish' : + case 'publish': + this.isPosting = true; + let count = this.media.filter(m => m.filter_class && !m.hasOwnProperty('is_filtered')).length; + if(count) { + this.applyFilterToMedia(); + return; + } if(this.composeSettings.media_descriptions === true) { let count = this.media.filter(m => { return !m.hasOwnProperty('alt') || m.alt.length < 2; @@ -1377,6 +1444,10 @@ export default { switch(this.mode) { case 'photo': switch(this.page) { + case 'filteringMedia': + this.page = 2; + break; + case 'addText': this.page = 1; break; @@ -1411,6 +1482,10 @@ export default { case 'video': switch(this.page) { + case 'filteringMedia': + this.page = 2; + break; + case 'licensePicker': this.page = 'video-2'; break; @@ -1431,6 +1506,10 @@ export default { this.page = 1; break; + case 'filteringMedia': + this.page = 2; + break; + case 'textOptions': this.page = 'addText'; break; @@ -1470,6 +1549,9 @@ export default { this.page = 2; break; + case 'filteringMedia': + break; + case 'cropPhoto': this.pageLoading = true; let self = this; @@ -1495,14 +1577,7 @@ export default { break; case 2: - if(this.currentFilter) { - if(window.confirm('Are you sure you want to apply this filter?')) { - this.applyFilterToMedia(); - this.page++; - } - } else { this.page++; - } break; case 3: this.page++; @@ -1649,43 +1724,73 @@ export default { // this is where the magic happens var ua = navigator.userAgent.toLowerCase(); if(ua.indexOf('firefox') == -1 && ua.indexOf('chrome') == -1) { + this.isPosting = false; swal('Oops!', 'Your browser does not support the filter feature.', 'error'); + this.page = 3; return; } - let medias = this.media; - let media = null; - const canvas = document.getElementById('pr_canvas'); - const ctx = canvas.getContext('2d'); - let image = document.getElementById('pr_img'); - let blob = null; - let data = null; - - for (var i = medias.length - 1; i >= 0; i--) { - media = medias[i]; - if(media.filter_class) { - image.src = media.url; - image.addEventListener('load', e => { - canvas.width = image.width; - canvas.height = image.height; - ctx.filter = App.util.filterCss[media.filter_class]; - ctx.drawImage(image, 0, 0, image.width, image.height); - ctx.save(); - canvas.toBlob(function(blob) { - data = new FormData(); - data.append('file', blob); - data.append('id', media.id); - axios.post('/api/compose/v0/media/update', data).then(res => { - }).catch(err => { - }); - }); - }, media.mime, 0.9); - ctx.clearRect(0, 0, image.width, image.height); - } - } - + let count = this.media.filter(m => m.filter_class).length; + if(count) { + this.page = 'filteringMedia'; + this.filteringRemainingCount = count; + this.$nextTick(() => { + this.isFilteringMedia = true; + this.media.forEach((media, idx) => this.applyFilterToMediaSave(media, idx)); + }) + } else { + this.page = 3; + } }, + applyFilterToMediaSave(media, idx) { + if(!media.filter_class) { + return; + } + + let self = this; + let data = null; + const canvas = document.createElement('canvas'); + const ctx = canvas.getContext('2d'); + let image = document.createElement('img'); + image.src = media.url; + image.addEventListener('load', e => { + canvas.width = image.width; + canvas.height = image.height; + ctx.filter = App.util.filterCss[media.filter_class]; + ctx.drawImage(image, 0, 0, image.width, image.height); + ctx.save(); + canvas.toBlob(function(blob) { + data = new FormData(); + data.append('file', blob); + data.append('id', media.id); + axios.post('/api/compose/v0/media/update', data) + .then(res => { + self.media[idx].is_filtered = true; + self.updateFilteringMedia(); + }).catch(err => { + }); + }); + }, media.mime, 0.9); + ctx.clearRect(0, 0, image.width, image.height); + }, + + updateFilteringMedia() { + this.filteringRemainingCount--; + this.filteringMediaTimeout = setTimeout(() => this.filteringMediaTimeoutJob(), 500); + }, + + filteringMediaTimeoutJob() { + if(this.filteringRemainingCount === 0) { + this.isFilteringMedia = false; + clearTimeout(this.filteringMediaTimeout); + setTimeout(() => this.compose(), 500); + } else { + clearTimeout(this.filteringMediaTimeout); + this.filteringMediaTimeout = setTimeout(() => this.filteringMediaTimeoutJob(), 1000); + } + }, + tagSearch(input) { if (input.length < 1) { return []; } let self = this; @@ -1800,7 +1905,6 @@ export default { } window.location.href = res.data.url; }).catch(err => { - console.log(err.response.data.error); if(err.response.data.hasOwnProperty('error')) { if(err.response.data.error == 'Duplicate detected.') { this.postingPoll = false; From 00823545a5b9d3630989fad9c6a322b390e57068 Mon Sep 17 00:00:00 2001 From: Daniel Supernault Date: Sun, 22 Oct 2023 23:21:50 -0600 Subject: [PATCH 006/107] Add WebP2P support for Video --- config/media.php | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/config/media.php b/config/media.php index f550ff291..46c1719db 100644 --- a/config/media.php +++ b/config/media.php @@ -22,5 +22,39 @@ return [ 'resilient_mode' => env('ALT_PRI_ENABLED', false) || env('ALT_SEC_ENABLED', false), ], + ], + + 'hls' => [ + /* + |-------------------------------------------------------------------------- + | Enable HLS + |-------------------------------------------------------------------------- + | + | Enable optional HLS support, required for video p2p support. Requires FFMPEG + | Disabled by default. + | + */ + 'enabled' => env('MEDIA_HLS_ENABLED', false), + + 'debug' => env('MEDIA_HLS_DEBUG', false), + + /* + |-------------------------------------------------------------------------- + | Enable Video P2P support + |-------------------------------------------------------------------------- + | + | Enable optional video p2p support. Requires FFMPEG + HLS + | Disabled by default. + | + */ + 'p2p' => env('MEDIA_HLS_P2P', false), + + 'p2p_debug' => env('MEDIA_HLS_P2P_DEBUG', false), + + 'bitrate' => env('MEDIA_HLS_BITRATE', 1000), + + 'tracker' => env('MEDIA_HLS_P2P_TRACKER', 'wss://tracker.webtorrent.dev'), + + 'ice' => env('MEDIA_HLS_P2P_ICE_SERVER', 'stun:stun.l.google.com:19302'), ] ]; From 82fc36b2b377e45fe26439e5f5a72a895c46a21c Mon Sep 17 00:00:00 2001 From: Daniel Supernault Date: Sun, 22 Oct 2023 23:41:03 -0600 Subject: [PATCH 007/107] Update npm deps, add webp2p libs. Thanks @peertube <3 --- package-lock.json | 533 +++++++++++++++++++++++++++++++++++++++++++++- package.json | 5 +- 2 files changed, 533 insertions(+), 5 deletions(-) diff --git a/package-lock.json b/package-lock.json index 1dde4df84..ad3df5977 100644 --- a/package-lock.json +++ b/package-lock.json @@ -7,9 +7,12 @@ "name": "pixelfed", "dependencies": { "@fancyapps/fancybox": "^3.5.7", + "@hcaptcha/vue-hcaptcha": "^1.3.0", + "@peertube/p2p-media-loader-core": "^1.0.14", + "@peertube/p2p-media-loader-hlsjs": "^1.0.14", "@trevoreyre/autocomplete-vue": "^2.2.0", "@web3-storage/parse-link-header": "^3.1.0", - "@zip.js/zip.js": "^2.7.14", + "@zip.js/zip.js": "^2.7.24", "animate.css": "^4.1.0", "bigpicture": "^2.6.2", "blurhash": "^1.1.3", @@ -1807,6 +1810,14 @@ "jquery": ">=1.9.0" } }, + "node_modules/@hcaptcha/vue-hcaptcha": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@hcaptcha/vue-hcaptcha/-/vue-hcaptcha-1.3.0.tgz", + "integrity": "sha512-aUSWyhRucgFeBOBUC3nWBZuE0TkeoSH5QIVFwiTLnNsYpIaxD1tKBbI5Tdoy0TdpkuXKsB4KqyElbvoMZ9reGw==", + "peerDependencies": { + "vue": "^2.0.0" + } + }, "node_modules/@jridgewell/gen-mapping": { "version": "0.3.3", "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz", @@ -1918,6 +1929,29 @@ "npm": ">=5.0.0" } }, + "node_modules/@peertube/p2p-media-loader-core": { + "version": "1.0.14", + "resolved": "https://registry.npmjs.org/@peertube/p2p-media-loader-core/-/p2p-media-loader-core-1.0.14.tgz", + "integrity": "sha512-tjQv1CNziNY+zYzcL1h4q6AA2WuBUZnBIeVyjWR/EsO1EEC1VMdvPsL02cqYLz9yvIxgycjeTsWCm6XDqNgXRw==", + "dependencies": { + "bittorrent-tracker": "^9.19.0", + "debug": "^4.3.4", + "events": "^3.3.0", + "sha.js": "^2.4.11", + "simple-peer": "^9.11.1" + } + }, + "node_modules/@peertube/p2p-media-loader-hlsjs": { + "version": "1.0.14", + "resolved": "https://registry.npmjs.org/@peertube/p2p-media-loader-hlsjs/-/p2p-media-loader-hlsjs-1.0.14.tgz", + "integrity": "sha512-ySUVgUvAFXCE5E94xxjfywQ8xzk3jy9UGVkgi5Oqq+QeY7uG+o7CZ+LsQ/RjXgWBD70tEnyyfADHtL+9FCnwyQ==", + "dependencies": { + "@peertube/p2p-media-loader-core": "^1.0.14", + "debug": "^4.3.4", + "events": "^3.3.0", + "m3u8-parser": "^4.7.1" + } + }, "node_modules/@trevoreyre/autocomplete-vue": { "version": "2.4.1", "resolved": "https://registry.npmjs.org/@trevoreyre/autocomplete-vue/-/autocomplete-vue-2.4.1.tgz", @@ -2216,6 +2250,20 @@ "@types/node": "*" } }, + "node_modules/@videojs/vhs-utils": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/@videojs/vhs-utils/-/vhs-utils-3.0.5.tgz", + "integrity": "sha512-PKVgdo8/GReqdx512F+ombhS+Bzogiofy1LgAj4tN8PfdBx3HSS7V5WfJotKTqtOWGwVfSWsrYN/t09/DSryrw==", + "dependencies": { + "@babel/runtime": "^7.12.5", + "global": "^4.4.0", + "url-toolkit": "^2.2.1" + }, + "engines": { + "node": ">=8", + "npm": ">=5" + } + }, "node_modules/@vue/compiler-sfc": { "version": "2.7.14", "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-2.7.14.tgz", @@ -2464,10 +2512,11 @@ "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==" }, "node_modules/@zip.js/zip.js": { - "version": "2.7.15", - "resolved": "https://registry.npmjs.org/@zip.js/zip.js/-/zip.js-2.7.15.tgz", - "integrity": "sha512-iuL2otty04U4YBfdpd22XJacKaNuR7AHWlQrE/L9zHxfunXNtIeSgCxi66T74pnzHdmmpGqlBlZoVRkWOT70aA==", + "version": "2.7.30", + "resolved": "https://registry.npmjs.org/@zip.js/zip.js/-/zip.js-2.7.30.tgz", + "integrity": "sha512-nhMvQCj+TF1ATBqYzFds7v+yxPBhdDYHh8J341KtC1D2UrVBUIYcYK4Jy1/GiTsxOXEiKOXSUxvPG/XR+7jMqw==", "engines": { + "bun": ">=0.7.0", "deno": ">=1.0.0", "node": ">=16.5.0" } @@ -2503,6 +2552,11 @@ "acorn": "^8" } }, + "node_modules/addr-to-ip-port": { + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/addr-to-ip-port/-/addr-to-ip-port-1.5.4.tgz", + "integrity": "sha512-ByxmJgv8vjmDcl3IDToxL2yrWFrRtFpZAToY0f46XFXl8zS081t7El5MXIodwm7RC6DhHBRoOSMLFSPKCtHukg==" + }, "node_modules/adjust-sourcemap-loader": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/adjust-sourcemap-loader/-/adjust-sourcemap-loader-4.0.0.tgz", @@ -2826,6 +2880,11 @@ "resolved": "https://registry.npmjs.org/batch/-/batch-0.6.1.tgz", "integrity": "sha512-x+VAiMRL6UPkx+kudNvxTl6hB2XNNCG2r+7wixVfIYwu/2HKRXimwQyaumLjMveWvT2Hkd/cAJw+QBMfJ/EKVw==" }, + "node_modules/bencode": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/bencode/-/bencode-2.0.3.tgz", + "integrity": "sha512-D/vrAD4dLVX23NalHwb8dSvsUsxeRPO8Y7ToKA015JQYq69MLDOMkC0uGZYA/MPpltLO8rt8eqFC2j8DxjTZ/w==" + }, "node_modules/big.js": { "version": "5.2.2", "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz", @@ -2847,6 +2906,99 @@ "node": ">=8" } }, + "node_modules/bittorrent-peerid": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/bittorrent-peerid/-/bittorrent-peerid-1.3.6.tgz", + "integrity": "sha512-VyLcUjVMEOdSpHaCG/7odvCdLbAB1y3l9A2V6WIje24uV7FkJPrQrH/RrlFmKxP89pFVDEnE+YlHaFujlFIZsg==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/bittorrent-tracker": { + "version": "9.19.0", + "resolved": "https://registry.npmjs.org/bittorrent-tracker/-/bittorrent-tracker-9.19.0.tgz", + "integrity": "sha512-09d0aD2b+MC+zWvWajkUAKkYMynYW4tMbTKiRSthKtJZbafzEoNQSUHyND24SoCe3ZOb2fKfa6fu2INAESL9wA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "bencode": "^2.0.1", + "bittorrent-peerid": "^1.3.3", + "bn.js": "^5.2.0", + "chrome-dgram": "^3.0.6", + "clone": "^2.0.0", + "compact2string": "^1.4.1", + "debug": "^4.1.1", + "ip": "^1.1.5", + "lru": "^3.1.0", + "minimist": "^1.2.5", + "once": "^1.4.0", + "queue-microtask": "^1.2.3", + "random-iterate": "^1.0.1", + "randombytes": "^2.1.0", + "run-parallel": "^1.2.0", + "run-series": "^1.1.9", + "simple-get": "^4.0.0", + "simple-peer": "^9.11.0", + "simple-websocket": "^9.1.0", + "socks": "^2.0.0", + "string2compact": "^1.3.0", + "unordered-array-remove": "^1.0.2", + "ws": "^7.4.5" + }, + "bin": { + "bittorrent-tracker": "bin/cmd.js" + }, + "engines": { + "node": ">=12" + }, + "optionalDependencies": { + "bufferutil": "^4.0.3", + "utf-8-validate": "^5.0.5" + } + }, + "node_modules/bittorrent-tracker/node_modules/ws": { + "version": "7.5.9", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.9.tgz", + "integrity": "sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q==", + "engines": { + "node": ">=8.3.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, "node_modules/bluebird": { "version": "3.7.2", "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", @@ -3125,6 +3277,19 @@ "resolved": "https://registry.npmjs.org/buffer-xor/-/buffer-xor-1.0.3.tgz", "integrity": "sha512-571s0T7nZWK6vB67HI5dyUF7wXiNcfaPPPTl6zYCNApANjIvYJTg7hlud/+cJpdAhS7dVzqMLmfhfHR3rAcOjQ==" }, + "node_modules/bufferutil": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/bufferutil/-/bufferutil-4.0.8.tgz", + "integrity": "sha512-4T53u4PdgsXqKaIctwF8ifXlRTTmEPJ8iEPWFdGZvcf7sbwYo6FKFEX9eNNAnzFZ7EzJAQ3CJeOtCRA4rDp7Pw==", + "hasInstallScript": true, + "optional": true, + "dependencies": { + "node-gyp-build": "^4.3.0" + }, + "engines": { + "node": ">=6.14.2" + } + }, "node_modules/builtin-status-codes": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz", @@ -3285,6 +3450,29 @@ "fsevents": "~2.3.2" } }, + "node_modules/chrome-dgram": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/chrome-dgram/-/chrome-dgram-3.0.6.tgz", + "integrity": "sha512-bqBsUuaOiXiqxXt/zA/jukNJJ4oaOtc7ciwqJpZVEaaXwwxqgI2/ZdG02vXYWUhHGziDlvGMQWk0qObgJwVYKA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "inherits": "^2.0.4", + "run-series": "^1.1.9" + } + }, "node_modules/chrome-trace-event": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz", @@ -3349,6 +3537,14 @@ "node": ">=12" } }, + "node_modules/clone": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/clone/-/clone-2.1.2.tgz", + "integrity": "sha512-3Pe/CF1Nn94hyhIYpjtiLhdCoEoz0DqQ+988E9gmeEdQZlojxnOb74wctFyuwWQHzqyf9X7C7MG8juUpqBJT8w==", + "engines": { + "node": ">=0.8" + } + }, "node_modules/clone-deep": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz", @@ -3406,6 +3602,14 @@ "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", "integrity": "sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==" }, + "node_modules/compact2string": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/compact2string/-/compact2string-1.4.1.tgz", + "integrity": "sha512-3D+EY5nsRhqnOwDxveBv5T8wGo4DEvYxjDtPGmdOX+gfr5gE92c2RC0w2wa+xEefm07QuVqqcF3nZJUZ92l/og==", + "dependencies": { + "ipaddr.js": ">= 0.1.5" + } + }, "node_modules/compressible": { "version": "2.0.18", "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz", @@ -3954,6 +4158,20 @@ } } }, + "node_modules/decompress-response": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", + "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==", + "dependencies": { + "mimic-response": "^3.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/default-gateway": { "version": "6.0.3", "resolved": "https://registry.npmjs.org/default-gateway/-/default-gateway-6.0.3.tgz", @@ -4266,6 +4484,11 @@ "node": ">=4" } }, + "node_modules/err-code": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/err-code/-/err-code-3.0.1.tgz", + "integrity": "sha512-GiaH0KJUewYok+eeY05IIgjtAe4Yltygk9Wqp1V5yVWLdhf0hYZchRjNIT9bb0mSwRcIusT3cx7PJUf3zEIfUA==" + }, "node_modules/error-ex": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", @@ -4813,6 +5036,11 @@ "node": ">=6.9.0" } }, + "node_modules/get-browser-rtc": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/get-browser-rtc/-/get-browser-rtc-1.1.0.tgz", + "integrity": "sha512-MghbMJ61EJrRsDe7w1Bvqt3ZsBuqhce5nrn/XAwgwOXhcsz53/ltdxOse1h/8eKXj5slzxdsz56g5rzOFSGwfQ==" + }, "node_modules/get-caller-file": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", @@ -5422,6 +5650,11 @@ "node": ">= 0.10" } }, + "node_modules/ip": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/ip/-/ip-1.1.8.tgz", + "integrity": "sha512-PuExPYUiu6qMBQb4l06ecm6T6ujzhmh+MeJcW9wa89PoAz5pvd4zPgN5WJV104mb6S2T1AwNIAaB70JNrLQWhg==" + }, "node_modules/ipaddr.js": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-2.1.0.tgz", @@ -5964,6 +6197,17 @@ "tslib": "^2.0.3" } }, + "node_modules/lru": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/lru/-/lru-3.1.0.tgz", + "integrity": "sha512-5OUtoiVIGU4VXBOshidmtOsvBIvcQR6FD/RzWSvaeHyxCGB+PCUCu+52lqMfdc0h/2CLvHhZS4TwUmMQrrMbBQ==", + "dependencies": { + "inherits": "^2.0.1" + }, + "engines": { + "node": ">= 0.4.0" + } + }, "node_modules/lru-cache": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", @@ -5972,6 +6216,16 @@ "yallist": "^3.0.2" } }, + "node_modules/m3u8-parser": { + "version": "4.8.0", + "resolved": "https://registry.npmjs.org/m3u8-parser/-/m3u8-parser-4.8.0.tgz", + "integrity": "sha512-UqA2a/Pw3liR6Df3gwxrqghCP17OpPlQj6RBPLYygf/ZSQ4MoSgvdvhvt35qV+3NaaA0FSZx93Ix+2brT1U7cA==", + "dependencies": { + "@babel/runtime": "^7.12.5", + "@videojs/vhs-utils": "^3.0.5", + "global": "^4.4.0" + } + }, "node_modules/make-dir": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", @@ -6140,6 +6394,17 @@ "node": ">=6" } }, + "node_modules/mimic-response": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz", + "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/min-document": { "version": "2.19.0", "resolved": "https://registry.npmjs.org/min-document/-/min-document-2.19.0.tgz", @@ -6311,6 +6576,17 @@ "node": ">= 6.13.0" } }, + "node_modules/node-gyp-build": { + "version": "4.6.1", + "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.6.1.tgz", + "integrity": "sha512-24vnklJmyRS8ViBNI8KbtK/r/DmXQMRiOMXTNz2nrTnAYUwjmEEbnnpB/+kt+yWRv73bPsSPRFddrcIbAxSiMQ==", + "optional": true, + "bin": { + "node-gyp-build": "bin.js", + "node-gyp-build-optional": "optional.js", + "node-gyp-build-test": "build-test.js" + } + }, "node_modules/node-libs-browser": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/node-libs-browser/-/node-libs-browser-2.2.1.tgz", @@ -7507,6 +7783,11 @@ } ] }, + "node_modules/random-iterate": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/random-iterate/-/random-iterate-1.0.1.tgz", + "integrity": "sha512-Jdsdnezu913Ot8qgKgSgs63XkAjEsnMcS1z+cC6D6TNXsUXsMxy0RpclF2pzGZTEiTXL9BiArdGTEexcv4nqcA==" + }, "node_modules/randombytes": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", @@ -7844,6 +8125,25 @@ "queue-microtask": "^1.2.2" } }, + "node_modules/run-series": { + "version": "1.1.9", + "resolved": "https://registry.npmjs.org/run-series/-/run-series-1.1.9.tgz", + "integrity": "sha512-Arc4hUN896vjkqCYrUXquBFtRZdv1PfLbTYP71efP6butxyQ0kWpiNJyAgsxscmQg1cqvHY32/UCBzXedTpU2g==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, "node_modules/safe-buffer": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", @@ -8183,6 +8483,172 @@ "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==" }, + "node_modules/simple-concat": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz", + "integrity": "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/simple-get": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-4.0.1.tgz", + "integrity": "sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "decompress-response": "^6.0.0", + "once": "^1.3.1", + "simple-concat": "^1.0.0" + } + }, + "node_modules/simple-peer": { + "version": "9.11.1", + "resolved": "https://registry.npmjs.org/simple-peer/-/simple-peer-9.11.1.tgz", + "integrity": "sha512-D1SaWpOW8afq1CZGWB8xTfrT3FekjQmPValrqncJMX7QFl8YwhrPTZvMCANLtgBwwdS+7zURyqxDDEmY558tTw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "buffer": "^6.0.3", + "debug": "^4.3.2", + "err-code": "^3.0.1", + "get-browser-rtc": "^1.1.0", + "queue-microtask": "^1.2.3", + "randombytes": "^2.1.0", + "readable-stream": "^3.6.0" + } + }, + "node_modules/simple-peer/node_modules/buffer": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", + "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.2.1" + } + }, + "node_modules/simple-peer/node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/simple-websocket": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/simple-websocket/-/simple-websocket-9.1.0.tgz", + "integrity": "sha512-8MJPnjRN6A8UCp1I+H/dSFyjwJhp6wta4hsVRhjf8w9qBHRzxYt14RaOcjvQnhD1N4yKOddEjflwMnQM4VtXjQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "debug": "^4.3.1", + "queue-microtask": "^1.2.2", + "randombytes": "^2.1.0", + "readable-stream": "^3.6.0", + "ws": "^7.4.2" + } + }, + "node_modules/simple-websocket/node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/simple-websocket/node_modules/ws": { + "version": "7.5.9", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.9.tgz", + "integrity": "sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q==", + "engines": { + "node": ">=8.3.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, "node_modules/slash": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", @@ -8191,6 +8657,15 @@ "node": ">=8" } }, + "node_modules/smart-buffer": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", + "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==", + "engines": { + "node": ">= 6.0.0", + "npm": ">= 3.0.0" + } + }, "node_modules/sockjs": { "version": "0.3.24", "resolved": "https://registry.npmjs.org/sockjs/-/sockjs-0.3.24.tgz", @@ -8201,6 +8676,24 @@ "websocket-driver": "^0.7.4" } }, + "node_modules/socks": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/socks/-/socks-2.7.1.tgz", + "integrity": "sha512-7maUZy1N7uo6+WVEX6psASxtNlKaNVMlGQKkG/63nEDdLOWNbiUMoLK7X4uYoLhQstau72mLgfEWcXcwsaHbYQ==", + "dependencies": { + "ip": "^2.0.0", + "smart-buffer": "^4.2.0" + }, + "engines": { + "node": ">= 10.13.0", + "npm": ">= 3.0.0" + } + }, + "node_modules/socks/node_modules/ip": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ip/-/ip-2.0.0.tgz", + "integrity": "sha512-WKa+XuLG1A1R0UWhl2+1XQSi+fZWMsYKffMZTTYsiZaUD8k2yDAj5atimTUD2TZkyCkNEeYE5NhFZmupOGtjYQ==" + }, "node_modules/source-list-map": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/source-list-map/-/source-list-map-2.0.1.tgz", @@ -8333,6 +8826,15 @@ "node": ">=8" } }, + "node_modules/string2compact": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/string2compact/-/string2compact-1.3.2.tgz", + "integrity": "sha512-3XUxUgwhj7Eqh2djae35QHZZT4mN3fsO7kagZhSGmhhlrQagVvWSFuuFIWnpxFS0CdTB2PlQcaL16RDi14I8uw==", + "dependencies": { + "addr-to-ip-port": "^1.0.1", + "ipaddr.js": "^2.0.0" + } + }, "node_modules/strip-ansi": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", @@ -8677,6 +9179,11 @@ "node": ">= 10.0.0" } }, + "node_modules/unordered-array-remove": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/unordered-array-remove/-/unordered-array-remove-1.0.2.tgz", + "integrity": "sha512-45YsfD6svkgaCBNyvD+dFHm4qFX9g3wRSIVgWVPtm2OCnphvPxzJoe20ATsiNpNJrmzHifnxm+BN5F7gFT/4gw==" + }, "node_modules/unpipe": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", @@ -8744,6 +9251,24 @@ "resolved": "https://registry.npmjs.org/url-polyfill/-/url-polyfill-1.1.12.tgz", "integrity": "sha512-mYFmBHCapZjtcNHW0MDq9967t+z4Dmg5CJ0KqysK3+ZbyoNOWQHksGCTWwDhxGXllkWlOc10Xfko6v4a3ucM6A==" }, + "node_modules/url-toolkit": { + "version": "2.2.5", + "resolved": "https://registry.npmjs.org/url-toolkit/-/url-toolkit-2.2.5.tgz", + "integrity": "sha512-mtN6xk+Nac+oyJ/PrI7tzfmomRVNFIWKUbG8jdYFt52hxbiReFAXIjYskvu64/dvuW71IcB7lV8l0HvZMac6Jg==" + }, + "node_modules/utf-8-validate": { + "version": "5.0.10", + "resolved": "https://registry.npmjs.org/utf-8-validate/-/utf-8-validate-5.0.10.tgz", + "integrity": "sha512-Z6czzLq4u8fPOyx7TU6X3dvUZVvoJmxSQ+IcrlmagKhilxlhZgxPK6C5Jqbkw1IDUmFTM+cz9QDnnLTwDz/2gQ==", + "hasInstallScript": true, + "optional": true, + "dependencies": { + "node-gyp-build": "^4.3.0" + }, + "engines": { + "node": ">=6.14.2" + } + }, "node_modules/util": { "version": "0.11.1", "resolved": "https://registry.npmjs.org/util/-/util-0.11.1.tgz", diff --git a/package.json b/package.json index 9a188a1d4..6598175d9 100644 --- a/package.json +++ b/package.json @@ -34,9 +34,12 @@ }, "dependencies": { "@fancyapps/fancybox": "^3.5.7", + "@hcaptcha/vue-hcaptcha": "^1.3.0", + "@peertube/p2p-media-loader-core": "^1.0.14", + "@peertube/p2p-media-loader-hlsjs": "^1.0.14", "@trevoreyre/autocomplete-vue": "^2.2.0", "@web3-storage/parse-link-header": "^3.1.0", - "@zip.js/zip.js": "^2.7.14", + "@zip.js/zip.js": "^2.7.24", "animate.css": "^4.1.0", "bigpicture": "^2.6.2", "blurhash": "^1.1.3", From 4cd53247a66215ad7696b9bcab8571abccbe28c0 Mon Sep 17 00:00:00 2001 From: Daniel Supernault Date: Sun, 22 Oct 2023 23:42:25 -0600 Subject: [PATCH 008/107] Add MediaHlsService --- app/Services/Media/MediaHlsService.php | 27 ++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 app/Services/Media/MediaHlsService.php diff --git a/app/Services/Media/MediaHlsService.php b/app/Services/Media/MediaHlsService.php new file mode 100644 index 000000000..04b5ac649 --- /dev/null +++ b/app/Services/Media/MediaHlsService.php @@ -0,0 +1,27 @@ +media_path; + if(!$path) { return; } + $parts = explode('/', $path); + $filename = array_pop($parts); + $dir = implode('/', $parts); + [$name, $ext] = explode('.', $filename); + + $files = Storage::files($dir); + + return collect($files) + ->filter(function($p) use($dir, $name) { + return str_starts_with($p, $dir . '/' . $name); + }) + ->values() + ->toArray(); + } +} From a144301085b83769132bb634161d7a97be4509f9 Mon Sep 17 00:00:00 2001 From: Daniel Supernault Date: Mon, 23 Oct 2023 00:11:46 -0600 Subject: [PATCH 009/107] Add RegisterForm component --- .../remote-auth/partials/RegisterForm.vue | 800 ++++++++++++++++++ 1 file changed, 800 insertions(+) create mode 100644 resources/assets/components/remote-auth/partials/RegisterForm.vue diff --git a/resources/assets/components/remote-auth/partials/RegisterForm.vue b/resources/assets/components/remote-auth/partials/RegisterForm.vue new file mode 100644 index 000000000..6b1c4047f --- /dev/null +++ b/resources/assets/components/remote-auth/partials/RegisterForm.vue @@ -0,0 +1,800 @@ + + + + + From 4e3e23db36fe28f34c36d2d55272e86d1598b442 Mon Sep 17 00:00:00 2001 From: Daniel Supernault Date: Mon, 23 Oct 2023 00:15:53 -0600 Subject: [PATCH 010/107] Add js debounce util --- resources/assets/js/util/debounce.js | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 resources/assets/js/util/debounce.js diff --git a/resources/assets/js/util/debounce.js b/resources/assets/js/util/debounce.js new file mode 100644 index 000000000..b846d35e5 --- /dev/null +++ b/resources/assets/js/util/debounce.js @@ -0,0 +1,11 @@ +export function debounce (fn, delay) { + var timeoutID = null + return function () { + clearTimeout(timeoutID) + var args = arguments + var that = this + timeoutID = setTimeout(function () { + fn.apply(that, args) + }, delay) + } +} From fac7c3c5e79f4572d549d3767e02a577451dffad Mon Sep 17 00:00:00 2001 From: Daniel Supernault Date: Mon, 23 Oct 2023 00:38:37 -0600 Subject: [PATCH 011/107] Update MediaTransformer, add hls_manifest attribute --- app/Transformer/Api/MediaTransformer.php | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/app/Transformer/Api/MediaTransformer.php b/app/Transformer/Api/MediaTransformer.php index 0a4600bae..e1eeb1f6f 100644 --- a/app/Transformer/Api/MediaTransformer.php +++ b/app/Transformer/Api/MediaTransformer.php @@ -4,6 +4,7 @@ namespace App\Transformer\Api; use App\Media; use League\Fractal; +use Storage; class MediaTransformer extends Fractal\TransformerAbstract { @@ -28,6 +29,10 @@ class MediaTransformer extends Fractal\TransformerAbstract 'blurhash' => $media->blurhash ?? 'U4Rfzst8?bt7ogayj[j[~pfQ9Goe%Mj[WBay' ]; + if(config('media.hls.enabled') && $media->hls_transcoded_at != null && $media->hls_path) { + $res['hls_manifest'] = url(Storage::url($media->hls_path)); + } + if($media->width && $media->height) { $res['meta'] = [ 'focus' => [ From f9bbb055755c4a985e51209bb0ffd66e852be866 Mon Sep 17 00:00:00 2001 From: Daniel Supernault Date: Mon, 23 Oct 2023 01:09:16 -0600 Subject: [PATCH 012/107] Update MediaDeletePipeline, handle HLS deletion --- .../MediaPipeline/MediaDeletePipeline.php | 41 ++++++++++++++++++- 1 file changed, 39 insertions(+), 2 deletions(-) diff --git a/app/Jobs/MediaPipeline/MediaDeletePipeline.php b/app/Jobs/MediaPipeline/MediaDeletePipeline.php index 4db76c9c7..55df84948 100644 --- a/app/Jobs/MediaPipeline/MediaDeletePipeline.php +++ b/app/Jobs/MediaPipeline/MediaDeletePipeline.php @@ -10,8 +10,11 @@ use Illuminate\Queue\InteractsWithQueue; use Illuminate\Queue\SerializesModels; use Illuminate\Support\Facades\Redis; use Illuminate\Support\Facades\Storage; +use App\Services\Media\MediaHlsService; +use Illuminate\Queue\Middleware\WithoutOverlapping; +use Illuminate\Contracts\Queue\ShouldBeUniqueUntilProcessing; -class MediaDeletePipeline implements ShouldQueue +class MediaDeletePipeline implements ShouldQueue, ShouldBeUniqueUntilProcessing { use Dispatchable, InteractsWithQueue, Queueable, SerializesModels; @@ -20,8 +23,34 @@ class MediaDeletePipeline implements ShouldQueue public $timeout = 300; public $tries = 3; public $maxExceptions = 1; + public $failOnTimeout = true; public $deleteWhenMissingModels = true; + /** + * The number of seconds after which the job's unique lock will be released. + * + * @var int + */ + public $uniqueFor = 3600; + + /** + * Get the unique ID for the job. + */ + public function uniqueId(): string + { + return 'media:purge-job:id-' . $this->media->id; + } + + /** + * Get the middleware the job should pass through. + * + * @return array + */ + public function middleware(): array + { + return [(new WithoutOverlapping("media:purge-job:id-{$this->media->id}"))->shared()->dontRelease()]; + } + public function __construct(Media $media) { $this->media = $media; @@ -63,9 +92,17 @@ class MediaDeletePipeline implements ShouldQueue $disk->delete($thumb); } + if($media->hls_path != null) { + $files = MediaHlsService::allFiles($media); + if($files && count($files)) { + foreach($files as $file) { + $disk->delete($file); + } + } + } + $media->delete(); return 1; } - } From 3f292459ffaf5e851fa932010c2dcb3b117df10d Mon Sep 17 00:00:00 2001 From: Daniel Supernault Date: Mon, 23 Oct 2023 01:12:40 -0600 Subject: [PATCH 013/107] Update VideoPipeline, add VideoHlsPipeline job for HLS generation --- app/Jobs/VideoPipeline/VideoHlsPipeline.php | 94 +++++++++++++++++++++ 1 file changed, 94 insertions(+) create mode 100644 app/Jobs/VideoPipeline/VideoHlsPipeline.php diff --git a/app/Jobs/VideoPipeline/VideoHlsPipeline.php b/app/Jobs/VideoPipeline/VideoHlsPipeline.php new file mode 100644 index 000000000..eb91ed78b --- /dev/null +++ b/app/Jobs/VideoPipeline/VideoHlsPipeline.php @@ -0,0 +1,94 @@ +media->id; + } + + /** + * Get the middleware the job should pass through. + * + * @return array + */ + public function middleware(): array + { + return [(new WithoutOverlapping("media:video-hls:id-{$this->media->id}"))->shared()->dontRelease()]; + } + + /** + * Create a new job instance. + */ + public function __construct($media) + { + $this->media = $media; + } + + /** + * Execute the job. + */ + public function handle(): void + { + $media = $this->media; + + $bitrate = (new X264)->setKiloBitrate(config('media.hls.bitrate') ?? 1000); + + $mp4 = $media->media_path; + $man = str_replace('.mp4', '.m3u8', $mp4); + + FFMpeg::fromDisk('local') + ->open($mp4) + ->exportForHLS() + ->setSegmentLength(16) + ->setKeyFrameInterval(48) + ->addFormat($bitrate) + ->save($man); + + $media->hls_path = $man; + $media->hls_transcoded_at = now(); + $media->save(); + + MediaService::del($media->status_id); + usleep(50000); + StatusService::del($media->status_id); + + return; + } +} From f0ba2dfc69163b6e499ea1f2095c9a290d88db7d Mon Sep 17 00:00:00 2001 From: Daniel Supernault Date: Mon, 23 Oct 2023 01:13:09 -0600 Subject: [PATCH 014/107] Update VideoThumbnail job, dispatch HLS job when applicable --- app/Jobs/VideoPipeline/VideoThumbnail.php | 40 +++++++++++++++++++++-- 1 file changed, 38 insertions(+), 2 deletions(-) diff --git a/app/Jobs/VideoPipeline/VideoThumbnail.php b/app/Jobs/VideoPipeline/VideoThumbnail.php index fed61e4fc..ebcb4cf7e 100644 --- a/app/Jobs/VideoPipeline/VideoThumbnail.php +++ b/app/Jobs/VideoPipeline/VideoThumbnail.php @@ -16,13 +16,46 @@ use App\Jobs\MediaPipeline\MediaStoragePipeline; use App\Util\Media\Blurhash; use App\Services\MediaService; use App\Services\StatusService; +use Illuminate\Queue\Middleware\WithoutOverlapping; +use Illuminate\Contracts\Queue\ShouldBeUniqueUntilProcessing; -class VideoThumbnail implements ShouldQueue +class VideoThumbnail implements ShouldQueue, ShouldBeUniqueUntilProcessing { use Dispatchable, InteractsWithQueue, Queueable, SerializesModels; protected $media; + public $timeout = 900; + public $tries = 3; + public $maxExceptions = 1; + public $failOnTimeout = true; + public $deleteWhenMissingModels = true; + + /** + * The number of seconds after which the job's unique lock will be released. + * + * @var int + */ + public $uniqueFor = 3600; + + /** + * Get the unique ID for the job. + */ + public function uniqueId(): string + { + return 'media:video-thumb:id-' . $this->media->id; + } + + /** + * Get the middleware the job should pass through. + * + * @return array + */ + public function middleware(): array + { + return [(new WithoutOverlapping("media:video-thumb:id-{$this->media->id}"))->shared()->dontRelease()]; + } + /** * Create a new job instance. * @@ -54,7 +87,7 @@ class VideoThumbnail implements ShouldQueue $path[$i] = $t; $save = implode('/', $path); $video = FFMpeg::open($base) - ->getFrameFromSeconds(0) + ->getFrameFromSeconds(1) ->export() ->toDisk('local') ->save($save); @@ -68,6 +101,9 @@ class VideoThumbnail implements ShouldQueue $media->save(); } + if(config('media.hls.enabled')) { + VideoHlsPipeline::dispatch($media)->onQueue('mmo'); + } } catch (Exception $e) { } From 6cf4363c507455782e03d300305c3d07e8405544 Mon Sep 17 00:00:00 2001 From: Daniel Supernault Date: Mon, 23 Oct 2023 01:14:33 -0600 Subject: [PATCH 015/107] Update MediaService, remove hls_manifest attribute for MastoAPI entities --- app/Services/MediaService.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/app/Services/MediaService.php b/app/Services/MediaService.php index 8ca90118f..e0a2576e0 100644 --- a/app/Services/MediaService.php +++ b/app/Services/MediaService.php @@ -18,7 +18,7 @@ class MediaService public static function get($statusId) { - return Cache::remember(self::CACHE_KEY.$statusId, 86400, function() use($statusId) { + return Cache::remember(self::CACHE_KEY.$statusId, 21600, function() use($statusId) { $media = Media::whereStatusId($statusId)->orderBy('order')->get(); if(!$media) { return []; @@ -46,7 +46,8 @@ class MediaService $media['orientation'], $media['filter_name'], $media['filter_class'], - $media['mime'] + $media['mime'], + $media['hls_manifest'] ); $media['type'] = $mime ? strtolower($mime[0]) : 'unknown'; From 5c358010b088e5f72a6218e148c4414963644cf9 Mon Sep 17 00:00:00 2001 From: Daniel Supernault Date: Mon, 23 Oct 2023 01:15:02 -0600 Subject: [PATCH 016/107] Update Config util, add hls attributes --- app/Util/Site/Config.php | 156 +++++++++++++++++++++------------------ 1 file changed, 85 insertions(+), 71 deletions(-) diff --git a/app/Util/Site/Config.php b/app/Util/Site/Config.php index 90631159f..e0916591d 100644 --- a/app/Util/Site/Config.php +++ b/app/Util/Site/Config.php @@ -7,86 +7,100 @@ use Illuminate\Support\Str; class Config { - const CACHE_KEY = 'api:site:configuration:_v0.8'; + const CACHE_KEY = 'api:site:configuration:_v0.8'; - public static function get() { - return Cache::remember(self::CACHE_KEY, 900, function() { - return [ - 'version' => config('pixelfed.version'), - 'open_registration' => (bool) config_cache('pixelfed.open_registration'), - 'uploader' => [ - 'max_photo_size' => (int) config('pixelfed.max_photo_size'), - 'max_caption_length' => (int) config('pixelfed.max_caption_length'), - 'max_altext_length' => (int) config('pixelfed.max_altext_length', 150), - 'album_limit' => (int) config_cache('pixelfed.max_album_length'), - 'image_quality' => (int) config_cache('pixelfed.image_quality'), + public static function get() { + return Cache::remember(self::CACHE_KEY, 900, function() { + $hls = [ + 'enabled' => config('media.hls.enabled'), + ]; + if(config('media.hls.enabled')) { + $hls = [ + 'enabled' => true, + 'debug' => (bool) config('media.hls.debug'), + 'p2p' => (bool) config('media.hls.p2p'), + 'p2p_debug' => (bool) config('media.hls.p2p_debug'), + 'tracker' => config('media.hls.tracker'), + 'ice' => config('media.hls.ice') + ]; + } + return [ + 'version' => config('pixelfed.version'), + 'open_registration' => (bool) config_cache('pixelfed.open_registration'), + 'uploader' => [ + 'max_photo_size' => (int) config('pixelfed.max_photo_size'), + 'max_caption_length' => (int) config('pixelfed.max_caption_length'), + 'max_altext_length' => (int) config('pixelfed.max_altext_length', 150), + 'album_limit' => (int) config_cache('pixelfed.max_album_length'), + 'image_quality' => (int) config_cache('pixelfed.image_quality'), - 'max_collection_length' => (int) config('pixelfed.max_collection_length', 18), + 'max_collection_length' => (int) config('pixelfed.max_collection_length', 18), - 'optimize_image' => (bool) config('pixelfed.optimize_image'), - 'optimize_video' => (bool) config('pixelfed.optimize_video'), + 'optimize_image' => (bool) config('pixelfed.optimize_image'), + 'optimize_video' => (bool) config('pixelfed.optimize_video'), - 'media_types' => config_cache('pixelfed.media_types'), - 'mime_types' => config_cache('pixelfed.media_types') ? explode(',', config_cache('pixelfed.media_types')) : [], - 'enforce_account_limit' => (bool) config_cache('pixelfed.enforce_account_limit') - ], + 'media_types' => config_cache('pixelfed.media_types'), + 'mime_types' => config_cache('pixelfed.media_types') ? explode(',', config_cache('pixelfed.media_types')) : [], + 'enforce_account_limit' => (bool) config_cache('pixelfed.enforce_account_limit') + ], - 'activitypub' => [ - 'enabled' => (bool) config_cache('federation.activitypub.enabled'), - 'remote_follow' => config('federation.activitypub.remoteFollow') - ], + 'activitypub' => [ + 'enabled' => (bool) config_cache('federation.activitypub.enabled'), + 'remote_follow' => config('federation.activitypub.remoteFollow') + ], - 'ab' => config('exp'), + 'ab' => config('exp'), - 'site' => [ - 'name' => config_cache('app.name'), - 'domain' => config('pixelfed.domain.app'), - 'url' => config('app.url'), - 'description' => config_cache('app.short_description') - ], + 'site' => [ + 'name' => config_cache('app.name'), + 'domain' => config('pixelfed.domain.app'), + 'url' => config('app.url'), + 'description' => config_cache('app.short_description') + ], - 'account' => [ - 'max_avatar_size' => config('pixelfed.max_avatar_size'), - 'max_bio_length' => config('pixelfed.max_bio_length'), - 'max_name_length' => config('pixelfed.max_name_length'), - 'min_password_length' => config('pixelfed.min_password_length'), - 'max_account_size' => config('pixelfed.max_account_size') - ], + 'account' => [ + 'max_avatar_size' => config('pixelfed.max_avatar_size'), + 'max_bio_length' => config('pixelfed.max_bio_length'), + 'max_name_length' => config('pixelfed.max_name_length'), + 'min_password_length' => config('pixelfed.min_password_length'), + 'max_account_size' => config('pixelfed.max_account_size') + ], - 'username' => [ - 'remote' => [ - 'formats' => config('instance.username.remote.formats'), - 'format' => config('instance.username.remote.format'), - 'custom' => config('instance.username.remote.custom') - ] - ], + 'username' => [ + 'remote' => [ + 'formats' => config('instance.username.remote.formats'), + 'format' => config('instance.username.remote.format'), + 'custom' => config('instance.username.remote.custom') + ] + ], - 'features' => [ - 'timelines' => [ - 'local' => true, - 'network' => (bool) config('federation.network_timeline'), - ], - 'mobile_apis' => (bool) config_cache('pixelfed.oauth_enabled'), - 'stories' => (bool) config_cache('instance.stories.enabled'), - 'video' => Str::contains(config_cache('pixelfed.media_types'), 'video/mp4'), - 'import' => [ - 'instagram' => (bool) config_cache('pixelfed.import.instagram.enabled'), - 'mastodon' => false, - 'pixelfed' => false - ], - 'label' => [ - 'covid' => [ - 'enabled' => (bool) config('instance.label.covid.enabled'), - 'org' => config('instance.label.covid.org'), - 'url' => config('instance.label.covid.url'), - ] - ] - ] - ]; - }); - } + 'features' => [ + 'timelines' => [ + 'local' => true, + 'network' => (bool) config('federation.network_timeline'), + ], + 'mobile_apis' => (bool) config_cache('pixelfed.oauth_enabled'), + 'stories' => (bool) config_cache('instance.stories.enabled'), + 'video' => Str::contains(config_cache('pixelfed.media_types'), 'video/mp4'), + 'import' => [ + 'instagram' => (bool) config_cache('pixelfed.import.instagram.enabled'), + 'mastodon' => false, + 'pixelfed' => false + ], + 'label' => [ + 'covid' => [ + 'enabled' => (bool) config('instance.label.covid.enabled'), + 'org' => config('instance.label.covid.org'), + 'url' => config('instance.label.covid.url'), + ] + ], + 'hls' => $hls + ] + ]; + }); + } - public static function json() { - return json_encode(self::get(), JSON_FORCE_OBJECT); - } + public static function json() { + return json_encode(self::get(), JSON_FORCE_OBJECT); + } } From e3f8cfb49e1d8f2ead142de284e248085793bfe7 Mon Sep 17 00:00:00 2001 From: Daniel Supernault Date: Mon, 23 Oct 2023 01:27:11 -0600 Subject: [PATCH 017/107] Add hls/p2p video player --- .../components/presenter/VideoPlayer.vue | 198 ++++++++++++++++++ 1 file changed, 198 insertions(+) create mode 100644 resources/assets/components/presenter/VideoPlayer.vue diff --git a/resources/assets/components/presenter/VideoPlayer.vue b/resources/assets/components/presenter/VideoPlayer.vue new file mode 100644 index 000000000..8f5ba0102 --- /dev/null +++ b/resources/assets/components/presenter/VideoPlayer.vue @@ -0,0 +1,198 @@ + + + From f11ce7009ff92d97b9868aaefa99702cc3b1d5ca Mon Sep 17 00:00:00 2001 From: Daniel Supernault Date: Mon, 23 Oct 2023 01:28:06 -0600 Subject: [PATCH 018/107] Update PostContent, add new video-player component --- .../components/partials/post/PostContent.vue | 30 +++++-------------- 1 file changed, 8 insertions(+), 22 deletions(-) diff --git a/resources/assets/components/partials/post/PostContent.vue b/resources/assets/components/partials/post/PostContent.vue index 057b07fea..0a88acb19 100644 --- a/resources/assets/components/partials/post/PostContent.vue +++ b/resources/assets/components/partials/post/PostContent.vue @@ -12,7 +12,7 @@
- +
@@ -108,27 +108,11 @@
- +
@@ -185,12 +169,14 @@