Add local API for Channel Info

This commit is contained in:
Preston 2020-06-23 22:40:34 -04:00
parent dd2bfc6970
commit 71fbb6dde6
4 changed files with 265 additions and 51 deletions

139
package-lock.json generated
View File

@ -4107,19 +4107,50 @@
} }
}, },
"@videojs/http-streaming": { "@videojs/http-streaming": {
"version": "1.10.6", "version": "1.13.2",
"resolved": "https://registry.npmjs.org/@videojs/http-streaming/-/http-streaming-1.10.6.tgz", "resolved": "https://registry.npmjs.org/@videojs/http-streaming/-/http-streaming-1.13.2.tgz",
"integrity": "sha512-uPBuunHnxWeFRYxRX0j6h1IIWv3+QKvSkZGmW9TvqxWBqeNGSrQymR6tm1nVjQ2HhMVxVphQTUhUTTPDVWqmQg==", "integrity": "sha512-U4Xhh+HxGpRBx9Gm0LlEadq85k9BwckzFgZmyhacauhK/27Mz0goKKFAt+BpxBNp2oHVdAdk8NHfneinsqni3Q==",
"requires": { "requires": {
"aes-decrypter": "3.0.0", "aes-decrypter": "3.0.0",
"global": "^4.3.0", "global": "^4.3.0",
"m3u8-parser": "4.4.0", "m3u8-parser": "4.4.0",
"mpd-parser": "0.8.1", "mpd-parser": "0.10.0",
"mux.js": "5.2.1", "mux.js": "5.5.1",
"url-toolkit": "^2.1.3", "url-toolkit": "^2.1.3",
"video.js": "^6.8.0 || ^7.0.0" "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": { "@vue/component-compiler-utils": {
"version": "3.1.2", "version": "3.1.2",
"resolved": "https://registry.npmjs.org/@vue/component-compiler-utils/-/component-compiler-utils-3.1.2.tgz", "resolved": "https://registry.npmjs.org/@vue/component-compiler-utils/-/component-compiler-utils-3.1.2.tgz",
@ -14935,12 +14966,14 @@
} }
}, },
"mpd-parser": { "mpd-parser": {
"version": "0.8.1", "version": "0.10.0",
"resolved": "https://registry.npmjs.org/mpd-parser/-/mpd-parser-0.8.1.tgz", "resolved": "https://registry.npmjs.org/mpd-parser/-/mpd-parser-0.10.0.tgz",
"integrity": "sha512-WBTJ1bKk8OLUIxBh6s1ju1e2yz/5CzhPbgi6P3F3kJHKhGy1Z+ElvEnuzEbtC/dnbRcJtMXazE3f93N5LLdp9Q==", "integrity": "sha512-eIqkH/2osPr7tIIjhRmDWqm2wdJ7Q8oPfWvdjealzsLV2D2oNe0a0ae2gyYYs1sw5e5hdssDA2V6Sz8MW+Uvvw==",
"requires": { "requires": {
"@babel/runtime": "^7.5.5",
"@videojs/vhs-utils": "^1.1.0",
"global": "^4.3.2", "global": "^4.3.2",
"url-toolkit": "^2.1.1" "xmldom": "^0.1.27"
} }
}, },
"ms": { "ms": {
@ -14965,9 +14998,9 @@
"dev": true "dev": true
}, },
"mux.js": { "mux.js": {
"version": "5.2.1", "version": "5.5.1",
"resolved": "https://registry.npmjs.org/mux.js/-/mux.js-5.2.1.tgz", "resolved": "https://registry.npmjs.org/mux.js/-/mux.js-5.5.1.tgz",
"integrity": "sha512-1t2payD3Y8izfZRq7tfUQlhL2fKzjeLr9v1/2qNCTkEQnd9Abtn1JgzsBgGZubEXh6lM5L8B0iLGoWQiukjtbQ==" "integrity": "sha512-5VmmjADBqS4++8pTI6poSRJ+chHdaoI4XErcQPM5w4QfwaDl+FQlSI0iOgWbYDn6CBCbDRKaSCcEiN2K5aHNGQ=="
}, },
"nan": { "nan": {
"version": "2.12.0", "version": "2.12.0",
@ -16523,8 +16556,7 @@
"process": { "process": {
"version": "0.11.10", "version": "0.11.10",
"resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz",
"integrity": "sha1-czIwDoQBYb2j5podHZGn1LwW8YI=", "integrity": "sha1-czIwDoQBYb2j5podHZGn1LwW8YI="
"dev": true
}, },
"process-nextick-args": { "process-nextick-args": {
"version": "2.0.0", "version": "2.0.0",
@ -16671,8 +16703,7 @@
"querystring": { "querystring": {
"version": "0.2.0", "version": "0.2.0",
"resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz", "resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz",
"integrity": "sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA=", "integrity": "sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA="
"dev": true
}, },
"querystring-es3": { "querystring-es3": {
"version": "0.2.1", "version": "0.2.1",
@ -19730,18 +19761,18 @@
} }
}, },
"video.js": { "video.js": {
"version": "7.6.6", "version": "7.8.2",
"resolved": "https://registry.npmjs.org/video.js/-/video.js-7.6.6.tgz", "resolved": "https://registry.npmjs.org/video.js/-/video.js-7.8.2.tgz",
"integrity": "sha512-AXzHwymhvMpS7c7rF29u0j0/3tSs+v2gIk5UY8OkiDHSEHL7T0+t3hid4JHW7aGvTruUUgwyf4C74cX2RDL1Pw==", "integrity": "sha512-NIxRWCpq5N9QFnwPtemgdBf3IE3GAqLUR6R/12+qv6Flc/o2hRvPw3aFQwytRvBAqgc6Wg2whrHCh8ltQ3RiRA==",
"requires": { "requires": {
"@babel/runtime": "^7.4.5", "@babel/runtime": "^7.9.2",
"@videojs/http-streaming": "1.10.6", "@videojs/http-streaming": "1.13.2",
"@videojs/xhr": "2.5.1",
"global": "4.3.2", "global": "4.3.2",
"keycode": "^2.2.0", "keycode": "^2.2.0",
"safe-json-parse": "4.0.0", "safe-json-parse": "4.0.0",
"videojs-font": "3.2.0", "videojs-font": "3.2.0",
"videojs-vtt.js": "^0.14.1", "videojs-vtt.js": "^0.15.2"
"xhr": "2.4.0"
} }
}, },
"videojs-abloop": { "videojs-abloop": {
@ -19877,9 +19908,9 @@
} }
}, },
"videojs-vtt.js": { "videojs-vtt.js": {
"version": "0.14.1", "version": "0.15.2",
"resolved": "https://registry.npmjs.org/videojs-vtt.js/-/videojs-vtt.js-0.14.1.tgz", "resolved": "https://registry.npmjs.org/videojs-vtt.js/-/videojs-vtt.js-0.15.2.tgz",
"integrity": "sha512-YxOiywx6N9t3J5nqsE5WN2Sw4CSqVe3zV+AZm2T4syOc2buNJaD6ZoexSdeszx2sHLU/RRo2r4BJAXFDQ7Qo2Q==", "integrity": "sha512-kEo4hNMvu+6KhPvVYPKwESruwhHC3oFis133LwhXHO9U7nRnx0RiJYMiqbgwjgazDEXHR6t8oGJiHM6wq5XlAw==",
"requires": { "requires": {
"global": "^4.3.1" "global": "^4.3.1"
} }
@ -20880,17 +20911,6 @@
"integrity": "sha512-PSNhEJDejZYV7h50BohL09Er9VaIefr2LMAf3OEmpCkjOi34eYyQYAXUTjEQtZJTKcF0E2UKTh+osDLsgNim9Q==", "integrity": "sha512-PSNhEJDejZYV7h50BohL09Er9VaIefr2LMAf3OEmpCkjOi34eYyQYAXUTjEQtZJTKcF0E2UKTh+osDLsgNim9Q==",
"dev": true "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": { "xml-name-validator": {
"version": "3.0.0", "version": "3.0.0",
"resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-3.0.0.tgz", "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==", "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==",
"dev": true "dev": true
}, },
"xmldom": {
"version": "0.1.31",
"resolved": "https://registry.npmjs.org/xmldom/-/xmldom-0.1.31.tgz",
"integrity": "sha512-yS2uJflVQs6n+CyjHoaBmVSqIDevTAWrzMmjG1Gc7h1qQ7uVozNhEPJAwZXWyGQ/Gafo3fCwrcaokezLPupVyQ=="
},
"xtend": { "xtend": {
"version": "4.0.2", "version": "4.0.2",
"resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz",
@ -21059,6 +21084,46 @@
"node-fetch": "^2.6.0" "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": { "yt-xml2vtt": {
"version": "1.1.1", "version": "1.1.1",
"resolved": "https://registry.npmjs.org/yt-xml2vtt/-/yt-xml2vtt-1.1.1.tgz", "resolved": "https://registry.npmjs.org/yt-xml2vtt/-/yt-xml2vtt-1.1.1.tgz",

View File

@ -38,6 +38,7 @@
"youtube-comments-fetch": "^1.0.1", "youtube-comments-fetch": "^1.0.1",
"youtube-comments-task": "^1.3.15", "youtube-comments-task": "^1.3.15",
"youtube-suggest": "^1.1.0", "youtube-suggest": "^1.1.0",
"yt-channel-info": "git+https://github.com/FreeTubeApp/yt-channel-info.git",
"yt-xml2vtt": "^1.1.1", "yt-xml2vtt": "^1.1.1",
"ytdl-core": "^3.1.1", "ytdl-core": "^3.1.1",
"ytpl": "^0.1.21", "ytpl": "^0.1.21",

View File

@ -8,6 +8,8 @@ import FtChannelBubble from '../../components/ft-channel-bubble/ft-channel-bubbl
import FtLoader from '../../components/ft-loader/ft-loader.vue' import FtLoader from '../../components/ft-loader/ft-loader.vue'
import FtElementList from '../../components/ft-element-list/ft-element-list.vue' import FtElementList from '../../components/ft-element-list/ft-element-list.vue'
import ytch from 'yt-channel-info'
export default Vue.extend({ export default Vue.extend({
name: 'Search', name: 'Search',
components: { components: {
@ -32,7 +34,9 @@ export default Vue.extend({
subCount: 0, subCount: 0,
latestVideosPage: 2, latestVideosPage: 2,
searchPage: 2, searchPage: 2,
videoContinuationString: '',
playlistContinuationString: '', playlistContinuationString: '',
searchContinuationString: '',
channelDescription: '', channelDescription: '',
videoSortBy: 'newest', videoSortBy: 'newest',
playlistSortBy: 'last', playlistSortBy: 'last',
@ -42,6 +46,7 @@ export default Vue.extend({
latestPlaylists: [], latestPlaylists: [],
searchResults: [], searchResults: [],
shownElementList: [], shownElementList: [],
apiUsed: '',
videoSelectNames: [ videoSelectNames: [
'Newest', 'Newest',
'Oldest', 'Oldest',
@ -65,6 +70,18 @@ export default Vue.extend({
} }
}, },
computed: { computed: {
usingElectron: function () {
return this.$store.getters.getUsingElectron
},
backendPreference: function () {
return this.$store.getters.getBackendPreference
},
backendFallback: function () {
return this.$store.getters.getBackendFallback
},
sessionSearchHistory: function () { sessionSearchHistory: function () {
return this.$store.getters.getSessionSearchHistory return this.$store.getters.getSessionSearchHistory
}, },
@ -77,25 +94,92 @@ export default Vue.extend({
videoSortBy () { videoSortBy () {
this.isElementListLoading = true this.isElementListLoading = true
this.latestVideos = [] this.latestVideos = []
switch (this.apiUsed) {
case 'local':
this.getChannelVideosLocal()
break
case 'invidious':
this.latestVideosPage = 1 this.latestVideosPage = 1
this.channelNextPage() this.channelInvidiousNextPage()
break
default:
this.getChannelVideosLocal()
}
}, },
playlistSortBy () { playlistSortBy () {
this.isElementListLoading = true this.isElementListLoading = true
this.latestPlaylists = [] this.latestPlaylists = []
this.playlistContinuationString = '' this.playlistContinuationString = ''
this.getPlaylists() switch (this.apiUsed) {
case 'local':
this.getPlaylistsLocal()
break
case 'invidious':
this.channelInvidiousNextPage()
break
default:
this.getPlaylistsLocal()
}
} }
}, },
mounted: function () { mounted: function () {
this.id = this.$route.params.id this.id = this.$route.params.id
this.isLoading = true
this.getChannelInfo() if (!this.usingElectron) {
this.getPlaylists() 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: { 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.isLoading = true
this.$store.dispatch('invidiousGetChannelInfo', this.id).then((response) => { this.$store.dispatch('invidiousGetChannelInfo', this.id).then((response) => {
@ -115,7 +199,7 @@ export default Vue.extend({
}) })
}, },
channelNextPage: function () { channelInvidiousNextPage: function () {
const payload = { const payload = {
resource: 'channels/videos', resource: 'channels/videos',
id: this.id, 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) { if (this.playlistContinuationString === null) {
console.log('There are no more playlists available for this channel') console.log('There are no more playlists available for this channel')
return return
@ -163,13 +264,34 @@ export default Vue.extend({
handleFetchMore: function () { handleFetchMore: function () {
switch (this.currentTab) { switch (this.currentTab) {
case 'videos': case 'videos':
this.channelNextPage() switch (this.apiUsed) {
case 'local':
this.channelLocalNextPage()
break
case 'invidious':
this.channelInvidiousNextPage()
break
}
break break
case 'playlists': case 'playlists':
this.getPlaylists() switch (this.apiUsed) {
case 'local':
this.getPlaylistsLocalMore()
break
case 'invidious':
this.getPlaylistsInvidious()
break
}
break break
case 'search': case 'search':
this.searchChannel() switch (this.apiUsed) {
case 'local':
this.searchChannelLocal()
break
case 'invidious':
this.searchChannelInvidious()
break
}
break break
} }
}, },
@ -180,14 +302,40 @@ export default Vue.extend({
newSearch: function (query) { newSearch: function (query) {
this.lastSearchQuery = query this.lastSearchQuery = query
this.searchContinuationString = ''
this.isElementListLoading = true this.isElementListLoading = true
this.searchPage = 1 this.searchPage = 1
this.searchResults = [] this.searchResults = []
this.changeTab('search') 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 = { const payload = {
resource: 'channels/search', resource: 'channels/search',
id: this.id, id: this.id,

View File

@ -109,7 +109,7 @@
:key="index" :key="index"
:channel-name="channel.author" :channel-name="channel.author"
:channel-id="channel.authorId" :channel-id="channel.authorId"
:channel-thumbnail="channel.authorThumbnails[3].url" :channel-thumbnail="channel.authorThumbnails[channel.authorThumbnails.length - 1].url"
/> />
</ft-flex-box> </ft-flex-box>
</div> </div>