diff --git a/THIRD-PARTY-NOTICES.md b/THIRD-PARTY-NOTICES.md new file mode 100644 index 00000000..72bfa529 --- /dev/null +++ b/THIRD-PARTY-NOTICES.md @@ -0,0 +1,55 @@ +# Third-Party Notices + +This project bundles third-party assets, listed below with their licenses. + +## Lucide icons + +The audio and video file-type icons in `frontend/src/main/resources/icons/` +(`audio.svg`, `audio_dark.svg`, `video.svg`, `video_dark.svg`) are adapted from +[Lucide](https://lucide.dev) — the `music` and `film` icons, recolored and +resized for use in the IDE. + +`film` is covered by Lucide's ISC license. `music` is one of Lucide's +Feather-derived icons and is covered by the MIT license. Both notices follow. + +### ISC License + +``` +Copyright (c) 2026 Lucide Icons and Contributors + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +``` + +### MIT License (for Feather-derived icons, including `music`) + +``` +Copyright (c) 2013-present Cole Bemis + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +``` diff --git a/frontend/src/main/kotlin/dev/twango/jetplay/editor/JetplayIcons.kt b/frontend/src/main/kotlin/dev/twango/jetplay/editor/JetplayIcons.kt new file mode 100644 index 00000000..66196123 --- /dev/null +++ b/frontend/src/main/kotlin/dev/twango/jetplay/editor/JetplayIcons.kt @@ -0,0 +1,13 @@ +package dev.twango.jetplay.editor + +import com.intellij.openapi.util.IconLoader +import javax.swing.Icon + +object JetplayIcons { + + @JvmField + val Audio: Icon = IconLoader.getIcon("/icons/audio.svg", JetplayIcons::class.java) + + @JvmField + val Video: Icon = IconLoader.getIcon("/icons/video.svg", JetplayIcons::class.java) +} diff --git a/frontend/src/main/kotlin/dev/twango/jetplay/editor/MediaFileIconProvider.kt b/frontend/src/main/kotlin/dev/twango/jetplay/editor/MediaFileIconProvider.kt new file mode 100644 index 00000000..d42cb3f7 --- /dev/null +++ b/frontend/src/main/kotlin/dev/twango/jetplay/editor/MediaFileIconProvider.kt @@ -0,0 +1,19 @@ +package dev.twango.jetplay.editor + +import com.intellij.ide.FileIconProvider +import com.intellij.openapi.project.DumbAware +import com.intellij.openapi.project.Project +import com.intellij.openapi.vfs.VirtualFile +import dev.twango.jetplay.media.MediaClassification +import javax.swing.Icon + +class MediaFileIconProvider : + FileIconProvider, + DumbAware { + + override fun getIcon(file: VirtualFile, flags: Int, project: Project?): Icon? { + if (file.fileType != MediaFileType.INSTANCE) return null + val extension = file.extension ?: return null + return if (MediaClassification.isVideo(extension)) JetplayIcons.Video else JetplayIcons.Audio + } +} diff --git a/frontend/src/main/resources/dev.twango.jetplay.frontend.xml b/frontend/src/main/resources/dev.twango.jetplay.frontend.xml index ff48d7ae..2c9c10f9 100644 --- a/frontend/src/main/resources/dev.twango.jetplay.frontend.xml +++ b/frontend/src/main/resources/dev.twango.jetplay.frontend.xml @@ -8,6 +8,7 @@ implementationClass="dev.twango.jetplay.editor.MediaFileType" fieldName="INSTANCE" extensions="mp4;m4v;mkv;avi;mov;wmv;flv;webm;ogv;mts;m2ts;m2t;3gp;ivf;mp3;wav;ogg;oga;opus;m4a;aac;wma;aiff;aif;flac;ac3;eac3;caf;adts;amr;au;pcmu;ulaw;pcma;alaw;g722;gsm;sln"/> + diff --git a/frontend/src/main/resources/icons/audio.svg b/frontend/src/main/resources/icons/audio.svg new file mode 100644 index 00000000..fc937895 --- /dev/null +++ b/frontend/src/main/resources/icons/audio.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/frontend/src/main/resources/icons/audio_dark.svg b/frontend/src/main/resources/icons/audio_dark.svg new file mode 100644 index 00000000..c8b7f8e7 --- /dev/null +++ b/frontend/src/main/resources/icons/audio_dark.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/frontend/src/main/resources/icons/video.svg b/frontend/src/main/resources/icons/video.svg new file mode 100644 index 00000000..5b290983 --- /dev/null +++ b/frontend/src/main/resources/icons/video.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/frontend/src/main/resources/icons/video_dark.svg b/frontend/src/main/resources/icons/video_dark.svg new file mode 100644 index 00000000..7ffca897 --- /dev/null +++ b/frontend/src/main/resources/icons/video_dark.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/frontend/src/test/kotlin/dev/twango/jetplay/editor/MediaFileIconResourcesTest.kt b/frontend/src/test/kotlin/dev/twango/jetplay/editor/MediaFileIconResourcesTest.kt new file mode 100644 index 00000000..c1a7120e --- /dev/null +++ b/frontend/src/test/kotlin/dev/twango/jetplay/editor/MediaFileIconResourcesTest.kt @@ -0,0 +1,19 @@ +package dev.twango.jetplay.editor + +import org.junit.Assert.assertNotNull +import org.junit.Test + +class MediaFileIconResourcesTest { + + @Test + fun audioAndVideoIconsArePresentInBothThemes() { + listOf( + "/icons/audio.svg", + "/icons/audio_dark.svg", + "/icons/video.svg", + "/icons/video_dark.svg", + ).forEach { path -> + assertNotNull("missing icon resource $path", javaClass.getResource(path)) + } + } +} diff --git a/shared/src/main/kotlin/dev/twango/jetplay/media/MediaClassification.kt b/shared/src/main/kotlin/dev/twango/jetplay/media/MediaClassification.kt index dd8fecc4..0c140d97 100644 --- a/shared/src/main/kotlin/dev/twango/jetplay/media/MediaClassification.kt +++ b/shared/src/main/kotlin/dev/twango/jetplay/media/MediaClassification.kt @@ -2,7 +2,8 @@ package dev.twango.jetplay.media object MediaClassification { - // Keep in sync with the video extensions in plugin.xml. + // Video extensions registered by the media file type in the frontend descriptor. + // .ts is excluded to avoid clobbering TypeScript files. private val VIDEO_EXTENSIONS = setOf( "mp4", "m4v", @@ -13,9 +14,9 @@ object MediaClassification { "flv", "webm", "ogv", - "ts", "mts", "m2ts", + "m2t", "3gp", "ivf", ) diff --git a/shared/src/test/kotlin/dev/twango/jetplay/media/MediaClassificationTest.kt b/shared/src/test/kotlin/dev/twango/jetplay/media/MediaClassificationTest.kt index fae46249..c444757f 100644 --- a/shared/src/test/kotlin/dev/twango/jetplay/media/MediaClassificationTest.kt +++ b/shared/src/test/kotlin/dev/twango/jetplay/media/MediaClassificationTest.kt @@ -62,6 +62,13 @@ class MediaClassificationTest { assertFalse(MediaClassification.isVideo("opus")) } + @Test + fun transportStreamContainersClassifyAsVideo() { + assertTrue(MediaClassification.isVideo("mts")) + assertTrue(MediaClassification.isVideo("m2ts")) + assertTrue(MediaClassification.isVideo("m2t")) + } + @Test fun rawAudioExtensionsNeedTranscoding() { MediaClassification.rawAudioExtensions.forEach {