From fd25f61a5261d2831a03998f7e00e93c2cf9b90d Mon Sep 17 00:00:00 2001 From: efb4f5ff-1298-471a-8973-3d47447115dc <73130443+efb4f5ff-1298-471a-8973-3d47447115dc@users.noreply.github.com> Date: Fri, 12 Jul 2024 04:18:06 +0000 Subject: [PATCH 001/489] Delete .github/workflows/report.yml (#5395) --- .github/workflows/report.yml | 70 ------------------------------------ 1 file changed, 70 deletions(-) delete mode 100644 .github/workflows/report.yml diff --git a/.github/workflows/report.yml b/.github/workflows/report.yml deleted file mode 100644 index 834da028dd957..0000000000000 --- a/.github/workflows/report.yml +++ /dev/null @@ -1,70 +0,0 @@ -# This is a basic workflow to help you get started with Actions - -name: Project Board Automation - -on: - issues: - types: [closed, deleted, reopened, opened] - -jobs: - assign-issues-to-projects: - runs-on: ubuntu-latest - steps: - - # For bug reports - - name: New bug issue - uses: alex-page/github-project-automation-plus@v0.9.0 - if: contains(github.event.issue.labels.*.name, 'bug') && github.event.action == 'opened' - with: - project: Bug Reports - column: To assign - repo-token: ${{ secrets.PUSH_TOKEN }} - action: update - - - name: Bug issue closed - uses: alex-page/github-project-automation-plus@v0.9.0 - if: github.event.action == 'closed' || github.event.action == 'deleted' - with: - action: delete - project: Bug Reports - column: To assign - repo-token: ${{ secrets.PUSH_TOKEN }} - - - name: Bug issue reopened - uses: alex-page/github-project-automation-plus@v0.9.0 - if: contains(github.event.issue.labels.*.name, 'bug') && github.event.action == 'reopened' - with: - project: Bug Reports - column: To assign - repo-token: ${{ secrets.PUSH_TOKEN }} - action: update - - # For feature requests - - name: New feature issue - uses: alex-page/github-project-automation-plus@v0.9.0 - if: contains(github.event.issue.labels.*.name, 'enhancement') && github.event.action == 'opened' - with: - project: Feature Requests - column: To assign - repo-token: ${{ secrets.PUSH_TOKEN }} - action: update - - - name: Feature request issue closed - uses: alex-page/github-project-automation-plus@v0.9.0 - if: github.event.action == 'closed' || github.event.action == 'deleted' - with: - action: delete - project: Feature Requests - column: To assign - repo-token: ${{ secrets.PUSH_TOKEN }} - - - name: Feature request issue reopened - uses: alex-page/github-project-automation-plus@v0.9.0 - if: contains(github.event.issue.labels.*.name, 'enhancement') && github.event.action == 'reopened' - with: - project: Feature Requests - column: To assign - repo-token: ${{ secrets.PUSH_TOKEN }} - action: update - - From e3f9d674bcce28acc1861bdc4f6e818d660650ca Mon Sep 17 00:00:00 2001 From: absidue <48293849+absidue@users.noreply.github.com> Date: Fri, 12 Jul 2024 10:47:26 +0200 Subject: [PATCH 002/489] Fix about page not reacting to locale changes (#5393) --- src/renderer/views/About/About.js | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/renderer/views/About/About.js b/src/renderer/views/About/About.js index 8a9e772b1e1e0..54b1c34fc8833 100644 --- a/src/renderer/views/About/About.js +++ b/src/renderer/views/About/About.js @@ -12,8 +12,12 @@ export default defineComponent({ }, data: function () { return { - versionNumber: `v${packageDetails.version}`, - chunks: [ + versionNumber: `v${packageDetails.version}` + } + }, + computed: { + chunks: function () { + return [ { icon: ['fab', 'github'], title: this.$t('About.Source code'), @@ -74,7 +78,7 @@ export default defineComponent({ title: `${this.$t('About.Donate')} - BTC`, content: `${ABOUT_BITCOIN_ADDRESS}` } - ], + ] } } }) From ad67d04c2fa3683285615e44706907df7ddff69d Mon Sep 17 00:00:00 2001 From: Emma Date: Fri, 12 Jul 2024 05:30:29 -0400 Subject: [PATCH 003/489] Add checking for new nightly versions within nightly (can still be disabled the same way as normal) --- src/renderer/App.js | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/src/renderer/App.js b/src/renderer/App.js index 628d37209a074..19a3bb993aacb 100644 --- a/src/renderer/App.js +++ b/src/renderer/App.js @@ -54,7 +54,8 @@ export default defineComponent({ externalLinkOpeningPromptValues: [ 'yes', 'no' - ] + ], + nightlyLink: '' } }, computed: { @@ -279,6 +280,23 @@ export default defineComponent({ .catch((error) => { console.error('errored while checking for updates', requestUrl, error) }) + } else { + // nightly check + fetch('https://api.github.com/repos/MarmadileManteater/FreetubeAndroid/actions/runs') + .then((response) => response.json()) + .then((json) => { + const currentAppWorkflowRun = packageDetails.version.split('-nightly-')[1] + const buildRuns = json.workflow_runs.filter(run => run.name === 'Build Android') + if (buildRuns.length > 0) { + if (currentAppWorkflowRun < buildRuns[0].run_number) { + this.updateChangelog = marked.parse(`latest commit:\r\n\`\`\`\r\n${buildRuns[0].head_commit.message}\r\n\`\`\``) + this.changeLogTitle = `Nightly ${buildRuns[0].run_number}` + this.updateBannerMessage = this.$t('Version $ is now available! Click for more details').replace('$', buildRuns[0].run_number) + this.nightlyLink = buildRuns[0].html_url + this.showUpdatesBanner = true + } + } + }) } } }, @@ -337,7 +355,9 @@ export default defineComponent({ }, openDownloadsPage: function () { - const url = 'https://github.com/MarmadileManteater/FreeTubeCordova/releases' + const url = packageDetails.version.indexOf('-nightly-') === -1 + ? 'https://github.com/MarmadileManteater/FreeTubeCordova/releases' + : this.nightlyLink openExternalLink(url) this.showReleaseNotes = false this.showUpdatesBanner = false From 08c4e8f040a0df4d6f8d1c4f92f1dc77953d0d65 Mon Sep 17 00:00:00 2001 From: Emma Date: Sat, 13 Jul 2024 11:24:06 -0400 Subject: [PATCH 004/489] Add in-app viewer for console log (only visible in non-release builds) --- .../freetube/FreeTubeJavaScriptInterface.kt | 12 ++ .../io/freetubeapp/freetube/MainActivity.kt | 18 +++ src/renderer/App.js | 4 +- src/renderer/App.vue | 1 + .../fta-log-viewer/fta-log-viewer.css | 93 +++++++++++++ .../fta-log-viewer/fta-log-viewer.js | 131 ++++++++++++++++++ .../fta-log-viewer/fta-log-viewer.vue | 53 +++++++ .../side-nav-more-options.js | 10 ++ .../side-nav-more-options.vue | 26 ++++ src/renderer/components/side-nav/side-nav.js | 14 ++ src/renderer/components/side-nav/side-nav.vue | 26 ++++ src/renderer/helpers/android.js | 4 + src/renderer/main.js | 6 + src/renderer/store/modules/utils.js | 17 +++ static/locales-android/en-US.yaml | 2 + 15 files changed, 416 insertions(+), 1 deletion(-) create mode 100644 src/renderer/components/fta-log-viewer/fta-log-viewer.css create mode 100644 src/renderer/components/fta-log-viewer/fta-log-viewer.js create mode 100644 src/renderer/components/fta-log-viewer/fta-log-viewer.vue diff --git a/android/app/src/main/java/io/freetubeapp/freetube/FreeTubeJavaScriptInterface.kt b/android/app/src/main/java/io/freetubeapp/freetube/FreeTubeJavaScriptInterface.kt index 32b39a42808c0..efa6bd85b619c 100644 --- a/android/app/src/main/java/io/freetubeapp/freetube/FreeTubeJavaScriptInterface.kt +++ b/android/app/src/main/java/io/freetubeapp/freetube/FreeTubeJavaScriptInterface.kt @@ -52,6 +52,18 @@ class FreeTubeJavaScriptInterface { lastState = PlaybackState.STATE_PLAYING } + @JavascriptInterface + fun getLogs(): String { + var logs = "[" + for (message in context.consoleMessages) { + logs += "${message}," + } + // get rid of trailing comma + logs = logs.substring(0, logs.length - 1) + logs += "]" + return logs + } + /** * @param directory a shortened directory uri * @return a full directory uri diff --git a/android/app/src/main/java/io/freetubeapp/freetube/MainActivity.kt b/android/app/src/main/java/io/freetubeapp/freetube/MainActivity.kt index 8c164b7728985..5994ef2340a1e 100644 --- a/android/app/src/main/java/io/freetubeapp/freetube/MainActivity.kt +++ b/android/app/src/main/java/io/freetubeapp/freetube/MainActivity.kt @@ -9,6 +9,7 @@ import android.os.Bundle import android.view.View import android.view.ViewGroup import android.view.ViewTreeObserver +import android.webkit.ConsoleMessage import android.webkit.WebChromeClient import android.webkit.WebResourceRequest import android.webkit.WebView @@ -24,8 +25,10 @@ import androidx.core.view.WindowCompat import androidx.core.view.WindowInsetsCompat import androidx.core.view.WindowInsetsControllerCompat import io.freetubeapp.freetube.databinding.ActivityMainBinding +import org.json.JSONObject import java.net.URLEncoder import java.util.Base64 +import java.util.UUID import java.util.concurrent.BlockingQueue import java.util.concurrent.LinkedBlockingQueue import java.util.concurrent.ThreadPoolExecutor @@ -44,6 +47,7 @@ class MainActivity : AppCompatActivity(), OnRequestPermissionsResultCallback { lateinit var jsInterface: FreeTubeJavaScriptInterface lateinit var activityResultLauncher: ActivityResultLauncher lateinit var content: View + var consoleMessages: MutableList = mutableListOf() var showSplashScreen: Boolean = true var darkMode: Boolean = false var paused: Boolean = false @@ -164,6 +168,20 @@ class MainActivity : AppCompatActivity(), OnRequestPermissionsResultCallback { webView.addJavascriptInterface(jsInterface, "Android") webView.webChromeClient = object: WebChromeClient() { + override fun onConsoleMessage(consoleMessage: ConsoleMessage): Boolean { + val messageData = JSONObject() + messageData.put("content", consoleMessage.message()) + messageData.put("level", consoleMessage.messageLevel()) + messageData.put("timestamp", System.currentTimeMillis()) + messageData.put("id", UUID.randomUUID()) + messageData.put("key", "${messageData["id"]}-${messageData["timestamp"]}") + messageData.put("sourceId", consoleMessage.sourceId()) + messageData.put("lineNumber", consoleMessage.lineNumber()) + consoleMessages.add(messageData) + webView.loadUrl("javascript: var event = new Event(\"console-message\"); event.data = JSON.parse(${btoa(messageData.toString())}); window.dispatchEvent(event)") + return super.onConsoleMessage(consoleMessage); + } + override fun onShowCustomView(view: View?, callback: CustomViewCallback?) { windowInsetsController.hide(WindowInsetsCompat.Type.systemBars()) fullscreenView = view!! diff --git a/src/renderer/App.js b/src/renderer/App.js index 19a3bb993aacb..40864ea1fd1ae 100644 --- a/src/renderer/App.js +++ b/src/renderer/App.js @@ -11,6 +11,7 @@ import FtProgressBar from './components/ft-progress-bar/ft-progress-bar.vue' import FtPlaylistAddVideoPrompt from './components/ft-playlist-add-video-prompt/ft-playlist-add-video-prompt.vue' import FtCreatePlaylistPrompt from './components/ft-create-playlist-prompt/ft-create-playlist-prompt.vue' import FtSearchFilters from './components/ft-search-filters/ft-search-filters.vue' +import FtaLogViewer from './components/fta-log-viewer/fta-log-viewer.vue' import { marked } from 'marked' import { IpcChannels } from '../constants' import packageDetails from '../../package.json' @@ -35,7 +36,8 @@ export default defineComponent({ FtProgressBar, FtPlaylistAddVideoPrompt, FtCreatePlaylistPrompt, - FtSearchFilters + FtSearchFilters, + FtaLogViewer }, data: function () { return { diff --git a/src/renderer/App.vue b/src/renderer/App.vue index 77392ea9defac..6d8880aa1a55a 100644 --- a/src/renderer/App.vue +++ b/src/renderer/App.vue @@ -56,6 +56,7 @@ + .log, +.logs > .warning, +.logs > .error { + padding: 10px; +} + +.logs > .log { + background-color: var(--card-bg-color); + border-block-end: 2px solid var(--secondary-card-bg-color); +} + +.logs > .warning { + background-color: #332b00; + color: #ee9836; + border-block-end: 1px solid #ee9836; +} + +.logs > .error { + background-color: #290000; + color: #e46962; + border-block-end: 1px solid #e46962; +} + +[data-theme="light"] .logs > .warning { + background-color: #fef6d5; + color: #3e2f00; + border-block-end: 2px solid var(--card-bg-color); +} + +.content { + overflow-wrap: break-word; +} + +.source { + display: block; + direction: rtl; + overflow: hidden; + text-wrap: nowrap; + text-overflow: ellipsis; +} + +.log .source { + font-weight: bold; +} + +.timestamp { + text-align: end; + display: block; +} + +.error .source, .warning .source { + color: #fff; +} + +[data-theme="light"] .source, +[data-theme="light"] .error { + color: #000; +} + +[data-theme="light"] .logs > .error { + background-color: #fcebeb; + color: #410e0b; + border-block-end: 2px solid var(--card-bg-color); +} + + +@media (width <= 420px) { + .logs-wrapper .actions-container { + padding: 23px; + flex-grow: 1; + } +} diff --git a/src/renderer/components/fta-log-viewer/fta-log-viewer.js b/src/renderer/components/fta-log-viewer/fta-log-viewer.js new file mode 100644 index 0000000000000..180f69057e40a --- /dev/null +++ b/src/renderer/components/fta-log-viewer/fta-log-viewer.js @@ -0,0 +1,131 @@ +import { defineComponent } from 'vue' +import { mapActions } from 'vuex' +import FtFlexBox from '../ft-flex-box/ft-flex-box.vue' +import FtPrompt from '../ft-prompt/ft-prompt.vue' +import FtButton from '../ft-button/ft-button.vue' +import { getConsoleLogs, isColourDark } from '../../helpers/android' +import { FontAwesomeIcon } from '@fortawesome/vue-fontawesome' +import packageDetails from '../../../../package.json' + +export default defineComponent({ + name: 'FtaLogViewer', + components: { + 'ft-flex-box': FtFlexBox, + 'ft-prompt': FtPrompt, + 'ft-button': FtButton, + 'font-awesome-icon': FontAwesomeIcon + }, + props: { + logLimit: { + type: Number, + default: 50 + } + }, + data() { + return { + usingAndroid: process.env.IS_ANDROID, + // release builds are the only ones with 3 periods in version numbers + usingRelease: packageDetails.version.split('.').length - 1 === 3, + theme: this.getThemeFromBody(), + logs: [] + } + }, + computed: { + baseTheme() { + return this.$store.getters.getBaseTheme + }, + shown() { + return this.$store.getters.getShowLogViewer + }, + hidden() { + return !this.$store.getters.getShowLogViewer + }, + logsReversed() { + const result = [] + for (let i = this.logs.length - 1; i >= 0; i--) { + result.push(this.logs[i]) + } + return result + } + }, + watch: { + baseTheme() { + this.theme = this.getThemeFromBody() + } + }, + mounted() { + window.addEventListener('enabled-light-mode', this.onLightModeEnabled) + window.addEventListener('enabled-dark-mode', this.onDarkModeEnabled) + // when mounted, backfill the logs so far + this.logs.push(...getConsoleLogs()) + window.addEventListener('console-message', this.onConsoleMessage) + }, + beforeDestroy() { + window.removeEventListener('enabled-light-mode', this.onLightModeEnabled) + window.removeEventListener('enabled-dark-mode', this.onDarkModeEnabled) + this.logs = [] + window.removeEventListener('console-message', this.onConsoleMessage) + }, + methods: { + getFaIconFromLevel(level) { + switch (level) { + case 'WARNING': + return 'triangle-exclamation' + case 'ERROR': + return 'circle-xmark' + default: + return null + } + }, + removeQueryString(path) { + if (path.indexOf('?') !== -1) { + return path.split('?')[0] + } else { + return path + } + }, + onLightModeEnabled() { + if (this.$store.getters.getBaseTheme === 'system') { + this.theme = 'light' + } + }, + onDarkModeEnabled() { + if (this.$store.getters.getBaseTheme === 'system') { + this.theme = 'dark' + } + }, + getThemeFromBody() { + const bodyStyle = getComputedStyle(document.body) + const text = bodyStyle.getPropertyValue('--primary-text-color') + const isDark = isColourDark(text) + return isDark ? 'dark' : 'light' + }, + onConsoleMessage({ data }) { + if ('content' in data && data.content !== null) { + if (data.content.indexOf('found in') === -1 && data.content.indexOf('---> ') === -1) { + // don't show errors related to the log viewer (creates infinite loop) + if (!this.logs.some(log => log.key === data.key)) { + if (this.logs.length > this.logLimit) { + this.logs = this.logs.slice(this.logs.length - this.logLimit) + } + data.content = data.content + // sanitise html + .replaceAll('&', '&') + .replaceAll('/', '/') + .replaceAll('<', '<') + .replaceAll('>', '>') + // format text line breaks and tabs into html (for youtube.js errors) + .replaceAll('\n', '
') + .replaceAll('\t', '  ') + .replaceAll(' ', '  ') + this.logs.push(data) + } + } + } + }, + ...mapActions([ + 'hideLogViewer', + 'showLogViewer', + ]) + } +}) diff --git a/src/renderer/components/fta-log-viewer/fta-log-viewer.vue b/src/renderer/components/fta-log-viewer/fta-log-viewer.vue new file mode 100644 index 0000000000000..9e682adf30b10 --- /dev/null +++ b/src/renderer/components/fta-log-viewer/fta-log-viewer.vue @@ -0,0 +1,53 @@ + + + + +