diff --git a/package-lock.json b/package-lock.json index 4c2c3f6e..249f757a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -4107,19 +4107,50 @@ } }, "@videojs/http-streaming": { - "version": "1.10.6", - "resolved": "https://registry.npmjs.org/@videojs/http-streaming/-/http-streaming-1.10.6.tgz", - "integrity": "sha512-uPBuunHnxWeFRYxRX0j6h1IIWv3+QKvSkZGmW9TvqxWBqeNGSrQymR6tm1nVjQ2HhMVxVphQTUhUTTPDVWqmQg==", + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@videojs/http-streaming/-/http-streaming-1.13.2.tgz", + "integrity": "sha512-U4Xhh+HxGpRBx9Gm0LlEadq85k9BwckzFgZmyhacauhK/27Mz0goKKFAt+BpxBNp2oHVdAdk8NHfneinsqni3Q==", "requires": { "aes-decrypter": "3.0.0", "global": "^4.3.0", "m3u8-parser": "4.4.0", - "mpd-parser": "0.8.1", - "mux.js": "5.2.1", + "mpd-parser": "0.10.0", + "mux.js": "5.5.1", "url-toolkit": "^2.1.3", "video.js": "^6.8.0 || ^7.0.0" } }, + "@videojs/vhs-utils": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@videojs/vhs-utils/-/vhs-utils-1.3.0.tgz", + "integrity": "sha512-oiqXDtHQqDPun7JseWkirUHGrgdYdeF12goUut5z7vwAj4DmUufEPFJ4xK5hYGXGFDyDhk2rSFOR122Ze6qXyQ==", + "requires": { + "@babel/runtime": "^7.5.5", + "global": "^4.3.2", + "url-toolkit": "^2.1.6" + } + }, + "@videojs/xhr": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@videojs/xhr/-/xhr-2.5.1.tgz", + "integrity": "sha512-wV9nGESHseSK+S9ePEru2+OJZ1jq/ZbbzniGQ4weAmTIepuBMSYPx5zrxxQA0E786T5ykpO8ts+LayV+3/oI2w==", + "requires": { + "@babel/runtime": "^7.5.5", + "global": "~4.4.0", + "is-function": "^1.0.1" + }, + "dependencies": { + "global": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/global/-/global-4.4.0.tgz", + "integrity": "sha512-wv/LAoHdRE3BeTGz53FAamhGlPLhlssK45usmGFThIi4XqnBmjKQ16u+RNbP7WvigRZDxUsM0J3gcQ5yicaL0w==", + "requires": { + "min-document": "^2.19.0", + "process": "^0.11.10" + } + } + } + }, "@vue/component-compiler-utils": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/@vue/component-compiler-utils/-/component-compiler-utils-3.1.2.tgz", @@ -14935,12 +14966,14 @@ } }, "mpd-parser": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/mpd-parser/-/mpd-parser-0.8.1.tgz", - "integrity": "sha512-WBTJ1bKk8OLUIxBh6s1ju1e2yz/5CzhPbgi6P3F3kJHKhGy1Z+ElvEnuzEbtC/dnbRcJtMXazE3f93N5LLdp9Q==", + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/mpd-parser/-/mpd-parser-0.10.0.tgz", + "integrity": "sha512-eIqkH/2osPr7tIIjhRmDWqm2wdJ7Q8oPfWvdjealzsLV2D2oNe0a0ae2gyYYs1sw5e5hdssDA2V6Sz8MW+Uvvw==", "requires": { + "@babel/runtime": "^7.5.5", + "@videojs/vhs-utils": "^1.1.0", "global": "^4.3.2", - "url-toolkit": "^2.1.1" + "xmldom": "^0.1.27" } }, "ms": { @@ -14965,9 +14998,9 @@ "dev": true }, "mux.js": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/mux.js/-/mux.js-5.2.1.tgz", - "integrity": "sha512-1t2payD3Y8izfZRq7tfUQlhL2fKzjeLr9v1/2qNCTkEQnd9Abtn1JgzsBgGZubEXh6lM5L8B0iLGoWQiukjtbQ==" + "version": "5.5.1", + "resolved": "https://registry.npmjs.org/mux.js/-/mux.js-5.5.1.tgz", + "integrity": "sha512-5VmmjADBqS4++8pTI6poSRJ+chHdaoI4XErcQPM5w4QfwaDl+FQlSI0iOgWbYDn6CBCbDRKaSCcEiN2K5aHNGQ==" }, "nan": { "version": "2.12.0", @@ -16523,8 +16556,7 @@ "process": { "version": "0.11.10", "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", - "integrity": "sha1-czIwDoQBYb2j5podHZGn1LwW8YI=", - "dev": true + "integrity": "sha1-czIwDoQBYb2j5podHZGn1LwW8YI=" }, "process-nextick-args": { "version": "2.0.0", @@ -16671,8 +16703,7 @@ "querystring": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz", - "integrity": "sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA=", - "dev": true + "integrity": "sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA=" }, "querystring-es3": { "version": "0.2.1", @@ -19730,18 +19761,18 @@ } }, "video.js": { - "version": "7.6.6", - "resolved": "https://registry.npmjs.org/video.js/-/video.js-7.6.6.tgz", - "integrity": "sha512-AXzHwymhvMpS7c7rF29u0j0/3tSs+v2gIk5UY8OkiDHSEHL7T0+t3hid4JHW7aGvTruUUgwyf4C74cX2RDL1Pw==", + "version": "7.8.2", + "resolved": "https://registry.npmjs.org/video.js/-/video.js-7.8.2.tgz", + "integrity": "sha512-NIxRWCpq5N9QFnwPtemgdBf3IE3GAqLUR6R/12+qv6Flc/o2hRvPw3aFQwytRvBAqgc6Wg2whrHCh8ltQ3RiRA==", "requires": { - "@babel/runtime": "^7.4.5", - "@videojs/http-streaming": "1.10.6", + "@babel/runtime": "^7.9.2", + "@videojs/http-streaming": "1.13.2", + "@videojs/xhr": "2.5.1", "global": "4.3.2", "keycode": "^2.2.0", "safe-json-parse": "4.0.0", "videojs-font": "3.2.0", - "videojs-vtt.js": "^0.14.1", - "xhr": "2.4.0" + "videojs-vtt.js": "^0.15.2" } }, "videojs-abloop": { @@ -19877,9 +19908,9 @@ } }, "videojs-vtt.js": { - "version": "0.14.1", - "resolved": "https://registry.npmjs.org/videojs-vtt.js/-/videojs-vtt.js-0.14.1.tgz", - "integrity": "sha512-YxOiywx6N9t3J5nqsE5WN2Sw4CSqVe3zV+AZm2T4syOc2buNJaD6ZoexSdeszx2sHLU/RRo2r4BJAXFDQ7Qo2Q==", + "version": "0.15.2", + "resolved": "https://registry.npmjs.org/videojs-vtt.js/-/videojs-vtt.js-0.15.2.tgz", + "integrity": "sha512-kEo4hNMvu+6KhPvVYPKwESruwhHC3oFis133LwhXHO9U7nRnx0RiJYMiqbgwjgazDEXHR6t8oGJiHM6wq5XlAw==", "requires": { "global": "^4.3.1" } @@ -20880,17 +20911,6 @@ "integrity": "sha512-PSNhEJDejZYV7h50BohL09Er9VaIefr2LMAf3OEmpCkjOi34eYyQYAXUTjEQtZJTKcF0E2UKTh+osDLsgNim9Q==", "dev": true }, - "xhr": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/xhr/-/xhr-2.4.0.tgz", - "integrity": "sha1-4W5mpF+GmGHu76tBbV7/ci3ECZM=", - "requires": { - "global": "~4.3.0", - "is-function": "^1.0.1", - "parse-headers": "^2.0.0", - "xtend": "^4.0.0" - } - }, "xml-name-validator": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-3.0.0.tgz", @@ -20913,6 +20933,11 @@ "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==", "dev": true }, + "xmldom": { + "version": "0.1.31", + "resolved": "https://registry.npmjs.org/xmldom/-/xmldom-0.1.31.tgz", + "integrity": "sha512-yS2uJflVQs6n+CyjHoaBmVSqIDevTAWrzMmjG1Gc7h1qQ7uVozNhEPJAwZXWyGQ/Gafo3fCwrcaokezLPupVyQ==" + }, "xtend": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", @@ -21059,6 +21084,46 @@ "node-fetch": "^2.6.0" } }, + "yt-channel-info": { + "version": "git+https://github.com/FreeTubeApp/yt-channel-info.git#b9710442bf9ce9e34aed7c1d0e3dddc988d4dd73", + "from": "git+https://github.com/FreeTubeApp/yt-channel-info.git", + "requires": { + "axios": "^0.18.0", + "querystring": "^0.2.0" + }, + "dependencies": { + "axios": { + "version": "0.18.1", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.18.1.tgz", + "integrity": "sha512-0BfJq4NSfQXd+SkFdrvFbG7addhYSBA2mQwISr46pD6E5iqkWg02RAs8vyTT/j0RTnoYmeXauBuSv1qKwR179g==", + "requires": { + "follow-redirects": "1.5.10", + "is-buffer": "^2.0.2" + } + }, + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "requires": { + "ms": "2.0.0" + } + }, + "follow-redirects": { + "version": "1.5.10", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.5.10.tgz", + "integrity": "sha512-0V5l4Cizzvqt5D44aTXbFZz+FtyXV1vrDN6qrelxtfYQKW0KO0W2T/hkE8xvGa/540LkZlkaUjO4ailYTFtHVQ==", + "requires": { + "debug": "=3.1.0" + } + }, + "is-buffer": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.4.tgz", + "integrity": "sha512-Kq1rokWXOPXWuaMAqZiJW4XxsmD9zGx9q4aePabbn3qCRGedtH7Cm+zV8WETitMfu1wdh+Rvd6w5egwSngUX2A==" + } + } + }, "yt-xml2vtt": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/yt-xml2vtt/-/yt-xml2vtt-1.1.1.tgz", diff --git a/package.json b/package.json index f94a8aab..5acc7de7 100644 --- a/package.json +++ b/package.json @@ -38,6 +38,7 @@ "youtube-comments-fetch": "^1.0.1", "youtube-comments-task": "^1.3.15", "youtube-suggest": "^1.1.0", + "yt-channel-info": "git+https://github.com/FreeTubeApp/yt-channel-info.git", "yt-xml2vtt": "^1.1.1", "ytdl-core": "^3.1.1", "ytpl": "^0.1.21", diff --git a/src/renderer/views/Channel/Channel.js b/src/renderer/views/Channel/Channel.js index 88acaf34..2f7e6897 100644 --- a/src/renderer/views/Channel/Channel.js +++ b/src/renderer/views/Channel/Channel.js @@ -8,6 +8,8 @@ import FtChannelBubble from '../../components/ft-channel-bubble/ft-channel-bubbl import FtLoader from '../../components/ft-loader/ft-loader.vue' import FtElementList from '../../components/ft-element-list/ft-element-list.vue' +import ytch from 'yt-channel-info' + export default Vue.extend({ name: 'Search', components: { @@ -32,7 +34,9 @@ export default Vue.extend({ subCount: 0, latestVideosPage: 2, searchPage: 2, + videoContinuationString: '', playlistContinuationString: '', + searchContinuationString: '', channelDescription: '', videoSortBy: 'newest', playlistSortBy: 'last', @@ -42,6 +46,7 @@ export default Vue.extend({ latestPlaylists: [], searchResults: [], shownElementList: [], + apiUsed: '', videoSelectNames: [ 'Newest', 'Oldest', @@ -65,6 +70,18 @@ export default Vue.extend({ } }, computed: { + usingElectron: function () { + return this.$store.getters.getUsingElectron + }, + + backendPreference: function () { + return this.$store.getters.getBackendPreference + }, + + backendFallback: function () { + return this.$store.getters.getBackendFallback + }, + sessionSearchHistory: function () { return this.$store.getters.getSessionSearchHistory }, @@ -77,25 +94,92 @@ export default Vue.extend({ videoSortBy () { this.isElementListLoading = true this.latestVideos = [] - this.latestVideosPage = 1 - this.channelNextPage() + switch (this.apiUsed) { + case 'local': + this.getChannelVideosLocal() + break + case 'invidious': + this.latestVideosPage = 1 + this.channelInvidiousNextPage() + break + default: + this.getChannelVideosLocal() + } }, playlistSortBy () { this.isElementListLoading = true this.latestPlaylists = [] this.playlistContinuationString = '' - this.getPlaylists() + switch (this.apiUsed) { + case 'local': + this.getPlaylistsLocal() + break + case 'invidious': + this.channelInvidiousNextPage() + break + default: + this.getPlaylistsLocal() + } } }, mounted: function () { this.id = this.$route.params.id + this.isLoading = true - this.getChannelInfo() - this.getPlaylists() + if (!this.usingElectron) { + this.getVideoInformationInvidious() + } else { + switch (this.backendPreference) { + case 'local': + this.apiUsed = 'local' + this.getChannelInfoLocal() + this.getChannelVideosLocal() + this.getPlaylistsLocal() + break + case 'invidious': + this.apiUsed = 'invidious' + this.getChannelInfoInvidious() + this.getPlaylistsInvidious() + break + } + } }, methods: { - getChannelInfo: function () { + getChannelInfoLocal: function () { + ytch.getChannelInfo(this.id).then((response) => { + this.id = response.authorId + this.channelName = response.author + this.subCount = response.subscriberCount + this.thumbnailUrl = response.authorThumbnails[2].url + this.bannerUrl = response.authorBanners[response.authorBanners.length - 1].url + this.channelDescription = response.description + this.relatedChannels = response.relatedChannels + this.isLoading = false + }).catch((err) => { + console.log(err) + }) + }, + + getChannelVideosLocal: function () { + this.isElementListLoading = true + ytch.getChannelVideos(this.id, this.videoSortBy).then((response) => { + this.latestVideos = response.items + this.videoContinuationString = response.continuation + this.isElementListLoading = false + }) + }, + + channelLocalNextPage: function () { + console.log(this.videoContinuationString) + ytch.getChannelVideosMore(this.id, this.videoContinuationString).then((response) => { + this.latestVideos = this.latestVideos.concat(response.items) + this.videoContinuationString = response.continuation + console.log(this.videoContinuationString) + }) + }, + + getChannelInfoInvidious: function () { this.isLoading = true this.$store.dispatch('invidiousGetChannelInfo', this.id).then((response) => { @@ -115,7 +199,7 @@ export default Vue.extend({ }) }, - channelNextPage: function () { + channelInvidiousNextPage: function () { const payload = { resource: 'channels/videos', id: this.id, @@ -132,7 +216,24 @@ export default Vue.extend({ }) }, - getPlaylists: function () { + getPlaylistsLocal: function () { + ytch.getChannelPlaylistInfo(this.id, this.playlistSortBy).then((response) => { + console.log(response) + this.latestPlaylists = response.items + this.playlistContinuationString = response.continuation + this.isElementListLoading = false + }) + }, + + getPlaylistsLocalMore: function () { + ytch.getChannelPlaylistsMore(this.id, this.playlistContinuationString).then((response) => { + console.log(response) + this.latestPlaylists = this.latestPlaylists.concat(response.items) + this.playlistContinuationString = response.continuation + }) + }, + + getPlaylistsInvidious: function () { if (this.playlistContinuationString === null) { console.log('There are no more playlists available for this channel') return @@ -163,13 +264,34 @@ export default Vue.extend({ handleFetchMore: function () { switch (this.currentTab) { case 'videos': - this.channelNextPage() + switch (this.apiUsed) { + case 'local': + this.channelLocalNextPage() + break + case 'invidious': + this.channelInvidiousNextPage() + break + } break case 'playlists': - this.getPlaylists() + switch (this.apiUsed) { + case 'local': + this.getPlaylistsLocalMore() + break + case 'invidious': + this.getPlaylistsInvidious() + break + } break case 'search': - this.searchChannel() + switch (this.apiUsed) { + case 'local': + this.searchChannelLocal() + break + case 'invidious': + this.searchChannelInvidious() + break + } break } }, @@ -180,14 +302,40 @@ export default Vue.extend({ newSearch: function (query) { this.lastSearchQuery = query + this.searchContinuationString = '' this.isElementListLoading = true this.searchPage = 1 this.searchResults = [] this.changeTab('search') - this.searchChannel() + switch (this.apiUsed) { + case 'local': + this.searchChannelLocal() + break + case 'invidious': + this.searchChannelInvidious() + break + } }, - searchChannel: function () { + searchChannelLocal: function () { + if (this.searchContinuationString === '') { + ytch.searchChannel(this.id, this.lastSearchQuery).then((response) => { + console.log(response) + this.searchResults = response.items + this.isElementListLoading = false + this.searchContinuationString = response.continuation + }) + } else { + ytch.searchChannelMore(this.id, this.searchContinuationString).then((response) => { + console.log(response) + this.searchResults = this.searchResults.concat(response.items) + this.isElementListLoading = false + this.searchContinuationString = response.continuation + }) + } + }, + + searchChannelInvidious: function () { const payload = { resource: 'channels/search', id: this.id, diff --git a/src/renderer/views/Channel/Channel.vue b/src/renderer/views/Channel/Channel.vue index 03dcfa01..b5660d3b 100644 --- a/src/renderer/views/Channel/Channel.vue +++ b/src/renderer/views/Channel/Channel.vue @@ -109,7 +109,7 @@ :key="index" :channel-name="channel.author" :channel-id="channel.authorId" - :channel-thumbnail="channel.authorThumbnails[3].url" + :channel-thumbnail="channel.authorThumbnails[channel.authorThumbnails.length - 1].url" />