Search option in watch history and favorite playlist (#1942)
* transition duration of 0.5s added to watched videos * small code reformating * extra white spaces deleted * typo in the word transition corrected * original whitespaces respected * transition added when hovering end * video stat components started and properties chosen * ft-video-stats integraded into the video player for dev and debugging * using a timer to get video stats and a method to update the statistic every second * getting statistic from vhs and adaptativeFormat * frame drop capture * stats capture in the form of event * useless comment deleted * stats render with a for loop in the template * stats correctly displayed * overlay stats added * video stats component deleted * video stats component deleted inside template video player * video stats component fully deleted * modal solution working need more styling and code messy * lint * modal working with stats * keyboard shortcut for stats * lint fix * network state is now a string * new line deleted * useless whitespace deleted * package-lock.json remove and ignore * keyboard shortcut restricted to up arrow * stats overlay made larger * align to left corner * useless formatting of string deleted * renaming of variable formatedStrats for formattedStats * keyboard shortcut made into a variable * lint-fix * key change for i * label translated * whitespace added for gitignore * lock file not ignored * videoId stat deleted * ft-video-player.js, en-US.yaml, fr-FR.yaml: changing percentage stats display changing the display for percentage stats for the format 'x%' instead of 'xx.xx' * ft-video-player.js, en-US.yaml, fr-FR.yaml: network state video statistic deleted * ft-video-player.js: made stats modal background color darker * ft-video-player.js, en-US.yaml, fr-FR.yaml: video id are now related to the one of youtube * ft-video-player.js, en-US.yaml, fr-FR.yaml: stats displayed made closet to the youtube implementation the name are capitalized, the order of display is changed and fps is combined with viewport * lint-fix * en-US.yaml, fr-FR.yaml: network state possibilities deleted because not used * package.json.lock: deleted * ft-video-player.js: formated_stats renamed for formatted_stats * lock file deleted * index.js, ft-video-player.js: handling of right click context menu via electon ipc bus an event is send to tell the vue component to show the stats modal * ft-video-player.js, index.js: renaming of video stats display event and definition of it as a variable * index.js, en-US.yaml: inconsistant capitalization of video statistics label solved * index.js: pluralized video stats * ft-video-player.js: fix right click undefined this.player change the arrow function inside the closure for a function with a bind to this * ft-video-player.js: handling of the case when this.player is not defined the property this.stats.display.activated as been added and manage when the to show the stats. In this way in the runtime (it is still refered in the run time but it is capture in an event loop) with dont have to refer to this.player so when it is not defined it doesnt affect the behavior. * lint fix * src/renderer/components/ft-video-player/ft-video-player.js: modal.close move into the display event of the statistic context * lint fix * src/renderer/components/ft-video-player/ft-video-player.js, static/locales/en-US.yaml, static/locales/fr-FR.yaml: better capitalization of the stats labels * static/locales/en-US.yaml: fps capitalized * static/locales/fr-FR.yaml, static/locales/en-US.yaml: capitalized label * src/renderer/views/History/History.js, src/renderer/store/datastores.js, src/renderer/store/modules/history.js: search history function added and indexing of history database * npm fix * src/renderer/views/History/History.js, src/renderer/store/modules/history.js: regex used to handle text search since their is no text indexing * src/renderer/views/History/History.js, src/renderer/views/History/History.vue: search bar added but not adapted for history search use case * src/renderer/views/History/History.js, src/renderer/views/History/History.vue: search bar added but not adapted for history search use case * src/renderer/views/History/History.js, src/renderer/store/modules/history.js, src/renderer/views/History/History.vue: search history working but order do not remain the same depending on search * src/renderer/views/History/History.js, src/renderer/store/modules/history.js, src/renderer/views/History/History.vue: search history working but order do not remain the same depending on search * src/renderer/views/History/History.js: loading added when query is empty to order the history * src/renderer/views/History/History.vue, src/renderer/views/History/History.js, static/locales/en-US.yaml, static/locales/fr-FR.yaml: translation added * src/renderer/components/ft-list-video/ft-list-video.js, src/renderer/views/History/History.vue, src/renderer/views/History/History.js: fix the bad history reconstruction problem by adding an update hook to ft-list-video component * lint fix * src/datastores/handlers/base.js, src/datastores/handlers/electron.js, src/datastores/handlers/web.js, src/datastores/index.js, src/renderer/store/modules/history.js, src/renderer/views/History/History.js, src/constants.js: history adapted to the new db * src/renderer/store/modules/history.js: print statement deleted * src/renderer/views/History/History.js, static/locales/en-US.yaml, static/locales/fr-FR.yaml: search history place holder renamed * search playlists backend * search bar added into the frontend, search method of playlist deleted because the document are the playlist and not the videos * src/renderer/store/modules/playlists.js: commment typo resolved * placeholder name of search bar only defined into the .vue file instead of in the .js file * src/renderer/components/ft-list-video/ft-list-video.js: fix the mecanism to modify a video card to reflect the current data * src/renderer/views/History/History.js: doesn't load when query is empty * src/renderer/components/ft-list-video/ft-list-video.js: fix problem date disapearing * video id query deleted from search in history and playlist
This commit is contained in:
parent
bb6ffe0a88
commit
6caa5da46c
|
@ -36,7 +36,8 @@ const DBActions = {
|
||||||
},
|
},
|
||||||
|
|
||||||
HISTORY: {
|
HISTORY: {
|
||||||
UPDATE_WATCH_PROGRESS: 'db-action-history-update-watch-progress'
|
UPDATE_WATCH_PROGRESS: 'db-action-history-update-watch-progress',
|
||||||
|
SEARCH: 'db-action-history-search'
|
||||||
},
|
},
|
||||||
|
|
||||||
PLAYLISTS: {
|
PLAYLISTS: {
|
||||||
|
|
|
@ -38,6 +38,11 @@ class History {
|
||||||
return db.history.find({}).sort({ timeWatched: -1 })
|
return db.history.find({}).sort({ timeWatched: -1 })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static search(query) {
|
||||||
|
const re = new RegExp(query, 'i')
|
||||||
|
return db.history.find({ $or: [{ author: { $regex: re } }, { title: { $regex: re } }] }).sort({ timeWatched: -1 })
|
||||||
|
}
|
||||||
|
|
||||||
static upsert(record) {
|
static upsert(record) {
|
||||||
return db.history.update({ videoId: record.videoId }, record, { upsert: true })
|
return db.history.update({ videoId: record.videoId }, record, { upsert: true })
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,6 +25,13 @@ class History {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static search(query) {
|
||||||
|
return ipcRenderer.invoke(
|
||||||
|
IpcChannels.DB_HISTORY,
|
||||||
|
{ action: DBActions.HISTORY.SEARCH, data: query }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
static upsert(record) {
|
static upsert(record) {
|
||||||
return ipcRenderer.invoke(
|
return ipcRenderer.invoke(
|
||||||
IpcChannels.DB_HISTORY,
|
IpcChannels.DB_HISTORY,
|
||||||
|
|
|
@ -25,6 +25,10 @@ class History {
|
||||||
return baseHandlers.history.find()
|
return baseHandlers.history.find()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static search(query) {
|
||||||
|
return baseHandlers.history.search(query)
|
||||||
|
}
|
||||||
|
|
||||||
static upsert(record) {
|
static upsert(record) {
|
||||||
return baseHandlers.history.upsert(record)
|
return baseHandlers.history.upsert(record)
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,4 +18,7 @@ db.profiles = Datastore.create({ filename: dbPath('profiles'), autoload: true })
|
||||||
db.playlists = Datastore.create({ filename: dbPath('playlists'), autoload: true })
|
db.playlists = Datastore.create({ filename: dbPath('playlists'), autoload: true })
|
||||||
db.history = Datastore.create({ filename: dbPath('history'), autoload: true })
|
db.history = Datastore.create({ filename: dbPath('history'), autoload: true })
|
||||||
|
|
||||||
|
db.history.ensureIndex({ fieldName: 'author' })
|
||||||
|
db.history.ensureIndex({ fieldName: 'title' })
|
||||||
|
db.history.ensureIndex({ fieldName: 'videoId' })
|
||||||
export default db
|
export default db
|
||||||
|
|
|
@ -445,6 +445,9 @@ function runApp() {
|
||||||
)
|
)
|
||||||
return null
|
return null
|
||||||
|
|
||||||
|
case DBActions.HISTORY.SEARCH:
|
||||||
|
return await baseHandlers.history.search(data)
|
||||||
|
|
||||||
case DBActions.GENERAL.DELETE:
|
case DBActions.GENERAL.DELETE:
|
||||||
await baseHandlers.history.delete(data)
|
await baseHandlers.history.delete(data)
|
||||||
syncOtherWindows(
|
syncOtherWindows(
|
||||||
|
|
|
@ -208,6 +208,12 @@ export default Vue.extend({
|
||||||
return this.$store.getters.getSaveWatchedProgress
|
return this.$store.getters.getSaveWatchedProgress
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
watch: {
|
||||||
|
data: function () {
|
||||||
|
this.parseVideoData()
|
||||||
|
this.checkIfWatched()
|
||||||
|
}
|
||||||
|
},
|
||||||
mounted: function () {
|
mounted: function () {
|
||||||
this.parseVideoData()
|
this.parseVideoData()
|
||||||
this.checkIfWatched()
|
this.checkIfWatched()
|
||||||
|
|
|
@ -0,0 +1,51 @@
|
||||||
|
import Datastore from 'nedb-promises'
|
||||||
|
|
||||||
|
// Initialize all datastores and export their references
|
||||||
|
// Current dbs:
|
||||||
|
// `settings.db`
|
||||||
|
// `profiles.db`
|
||||||
|
// `playlists.db`
|
||||||
|
// `history.db`
|
||||||
|
|
||||||
|
let buildFileName = null
|
||||||
|
|
||||||
|
// Check if using Electron
|
||||||
|
const usingElectron = window?.process?.type === 'renderer'
|
||||||
|
if (usingElectron) {
|
||||||
|
const { ipcRenderer } = require('electron')
|
||||||
|
const userDataPath = ipcRenderer.sendSync('getUserDataPathSync')
|
||||||
|
buildFileName = (dbName) => userDataPath + '/' + dbName + '.db'
|
||||||
|
} else {
|
||||||
|
buildFileName = (dbName) => dbName + '.db'
|
||||||
|
}
|
||||||
|
|
||||||
|
const settingsDb = Datastore.create({
|
||||||
|
filename: buildFileName('settings'),
|
||||||
|
autoload: true
|
||||||
|
})
|
||||||
|
|
||||||
|
const playlistsDb = Datastore.create({
|
||||||
|
filename: buildFileName('playlists'),
|
||||||
|
autoload: true
|
||||||
|
})
|
||||||
|
|
||||||
|
const profilesDb = Datastore.create({
|
||||||
|
filename: buildFileName('profiles'),
|
||||||
|
autoload: true
|
||||||
|
})
|
||||||
|
|
||||||
|
const historyDb = Datastore.create({
|
||||||
|
filename: buildFileName('history'),
|
||||||
|
autoload: true
|
||||||
|
})
|
||||||
|
|
||||||
|
historyDb.ensureIndex({ fieldName: 'author' })
|
||||||
|
historyDb.ensureIndex({ fieldName: 'title' })
|
||||||
|
historyDb.ensureIndex({ fieldName: 'videoId' })
|
||||||
|
|
||||||
|
export {
|
||||||
|
settingsDb,
|
||||||
|
profilesDb,
|
||||||
|
playlistsDb,
|
||||||
|
historyDb
|
||||||
|
}
|
|
@ -1,12 +1,16 @@
|
||||||
import { DBHistoryHandlers } from '../../../datastores/handlers/index'
|
import { DBHistoryHandlers } from '../../../datastores/handlers/index'
|
||||||
|
|
||||||
const state = {
|
const state = {
|
||||||
historyCache: []
|
historyCache: [],
|
||||||
|
searchHistoryCache: []
|
||||||
}
|
}
|
||||||
|
|
||||||
const getters = {
|
const getters = {
|
||||||
getHistoryCache: () => {
|
getHistoryCache: () => {
|
||||||
return state.historyCache
|
return state.historyCache
|
||||||
|
},
|
||||||
|
getSearchHistoryCache: () => {
|
||||||
|
return state.searchHistoryCache
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -47,6 +51,15 @@ const actions = {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
async searchHistory({ commit }, query) {
|
||||||
|
try {
|
||||||
|
const results = await DBHistoryHandlers.search(query)
|
||||||
|
commit('setSearchHistoryCache', results)
|
||||||
|
} catch (errMessage) {
|
||||||
|
console.error(errMessage)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
async updateWatchProgress({ commit }, { videoId, watchProgress }) {
|
async updateWatchProgress({ commit }, { videoId, watchProgress }) {
|
||||||
try {
|
try {
|
||||||
await DBHistoryHandlers.updateWatchProgress(videoId, watchProgress)
|
await DBHistoryHandlers.updateWatchProgress(videoId, watchProgress)
|
||||||
|
@ -66,6 +79,10 @@ const mutations = {
|
||||||
state.historyCache = historyCache
|
state.historyCache = historyCache
|
||||||
},
|
},
|
||||||
|
|
||||||
|
setSearchHistoryCache(state, result) {
|
||||||
|
state.searchHistoryCache = result
|
||||||
|
},
|
||||||
|
|
||||||
hoistEntryToTopOfHistoryCache(state, { currentIndex, updatedEntry }) {
|
hoistEntryToTopOfHistoryCache(state, { currentIndex, updatedEntry }) {
|
||||||
state.historyCache.splice(currentIndex, 1)
|
state.historyCache.splice(currentIndex, 1)
|
||||||
state.historyCache.unshift(updatedEntry)
|
state.historyCache.unshift(updatedEntry)
|
||||||
|
|
|
@ -13,14 +13,20 @@ const state = {
|
||||||
removeOnWatched: true,
|
removeOnWatched: true,
|
||||||
videos: []
|
videos: []
|
||||||
}
|
}
|
||||||
]
|
],
|
||||||
|
searchPlaylistCache: {
|
||||||
|
videos: []
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const getters = {
|
const getters = {
|
||||||
getAllPlaylists: () => state.playlists,
|
getAllPlaylists: () => state.playlists,
|
||||||
getFavorites: () => state.playlists[0],
|
getFavorites: () => state.playlists[0],
|
||||||
getPlaylist: (playlistId) => state.playlists.find(playlist => playlist._id === playlistId),
|
getPlaylist: (playlistId) => state.playlists.find(playlist => playlist._id === playlistId),
|
||||||
getWatchLater: () => state.playlists[1]
|
getWatchLater: () => state.playlists[1],
|
||||||
|
getSearchPlaylistCache: () => {
|
||||||
|
return state.searchPlaylistCache
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const actions = {
|
const actions = {
|
||||||
|
@ -130,10 +136,25 @@ const actions = {
|
||||||
} catch (errMessage) {
|
} catch (errMessage) {
|
||||||
console.error(errMessage)
|
console.error(errMessage)
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
async searchFavoritePlaylist({ commit }, query) {
|
||||||
|
const re = new RegExp(query, 'i')
|
||||||
|
// filtering in the frontend because the documents are the playlists and not the videos
|
||||||
|
const results = state.playlists[0].videos.slice()
|
||||||
|
.filter((video) => {
|
||||||
|
return video.author.match(re) ||
|
||||||
|
video.title.match(re)
|
||||||
|
})
|
||||||
|
commit('setPlaylistCache', results)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const mutations = {
|
const mutations = {
|
||||||
|
setPlaylistCache(state, result) {
|
||||||
|
state.searchPlaylistCache = {
|
||||||
|
videos: result
|
||||||
|
}
|
||||||
|
},
|
||||||
addPlaylist(state, payload) {
|
addPlaylist(state, payload) {
|
||||||
state.playlists.push(payload)
|
state.playlists.push(payload)
|
||||||
},
|
},
|
||||||
|
|
|
@ -4,6 +4,7 @@ import FtCard from '../../components/ft-card/ft-card.vue'
|
||||||
import FtFlexBox from '../../components/ft-flex-box/ft-flex-box.vue'
|
import FtFlexBox from '../../components/ft-flex-box/ft-flex-box.vue'
|
||||||
import FtElementList from '../../components/ft-element-list/ft-element-list.vue'
|
import FtElementList from '../../components/ft-element-list/ft-element-list.vue'
|
||||||
import FtButton from '../../components/ft-button/ft-button.vue'
|
import FtButton from '../../components/ft-button/ft-button.vue'
|
||||||
|
import FtInput from '../../components/ft-input/ft-input.vue'
|
||||||
|
|
||||||
export default Vue.extend({
|
export default Vue.extend({
|
||||||
name: 'History',
|
name: 'History',
|
||||||
|
@ -12,17 +13,23 @@ export default Vue.extend({
|
||||||
'ft-card': FtCard,
|
'ft-card': FtCard,
|
||||||
'ft-flex-box': FtFlexBox,
|
'ft-flex-box': FtFlexBox,
|
||||||
'ft-element-list': FtElementList,
|
'ft-element-list': FtElementList,
|
||||||
'ft-button': FtButton
|
'ft-button': FtButton,
|
||||||
|
'ft-input': FtInput
|
||||||
},
|
},
|
||||||
data: function () {
|
data: function () {
|
||||||
return {
|
return {
|
||||||
isLoading: false,
|
isLoading: false,
|
||||||
dataLimit: 100
|
dataLimit: 100,
|
||||||
|
hasQuery: false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
historyCache: function () {
|
historyCache: function () {
|
||||||
|
if (!this.hasQuery) {
|
||||||
return this.$store.getters.getHistoryCache
|
return this.$store.getters.getHistoryCache
|
||||||
|
} else {
|
||||||
|
return this.$store.getters.getSearchHistoryCache
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
activeData: function () {
|
activeData: function () {
|
||||||
|
@ -33,14 +40,7 @@ export default Vue.extend({
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
watch: {
|
|
||||||
historyCache() {
|
|
||||||
this.isLoading = true
|
|
||||||
setTimeout(() => {
|
|
||||||
this.isLoading = false
|
|
||||||
}, 100)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
mounted: function () {
|
mounted: function () {
|
||||||
console.log(this.historyCache)
|
console.log(this.historyCache)
|
||||||
|
|
||||||
|
@ -54,6 +54,16 @@ export default Vue.extend({
|
||||||
increaseLimit: function () {
|
increaseLimit: function () {
|
||||||
this.dataLimit += 100
|
this.dataLimit += 100
|
||||||
sessionStorage.setItem('historyLimit', this.dataLimit)
|
sessionStorage.setItem('historyLimit', this.dataLimit)
|
||||||
|
},
|
||||||
|
filterHistory: function(query) {
|
||||||
|
this.hasQuery = query !== ''
|
||||||
|
this.$store.dispatch('searchHistory', query)
|
||||||
|
},
|
||||||
|
load: function() {
|
||||||
|
this.isLoading = true
|
||||||
|
setTimeout(() => {
|
||||||
|
this.isLoading = false
|
||||||
|
}, 100)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
|
@ -9,6 +9,13 @@
|
||||||
class="card"
|
class="card"
|
||||||
>
|
>
|
||||||
<h3>{{ $t("History.History") }}</h3>
|
<h3>{{ $t("History.History") }}</h3>
|
||||||
|
<ft-input
|
||||||
|
ref="searchBar"
|
||||||
|
:placeholder="$t('History.Search bar placeholder')"
|
||||||
|
:show-clear-text-button="true"
|
||||||
|
:show-action-button="false"
|
||||||
|
@input="filterHistory"
|
||||||
|
/>
|
||||||
<ft-flex-box
|
<ft-flex-box
|
||||||
v-if="activeData.length === 0"
|
v-if="activeData.length === 0"
|
||||||
>
|
>
|
||||||
|
|
|
@ -5,6 +5,7 @@ import FtTooltip from '../../components/ft-tooltip/ft-tooltip.vue'
|
||||||
import FtLoader from '../../components/ft-loader/ft-loader.vue'
|
import FtLoader from '../../components/ft-loader/ft-loader.vue'
|
||||||
import FtButton from '../../components/ft-button/ft-button.vue'
|
import FtButton from '../../components/ft-button/ft-button.vue'
|
||||||
import FtElementList from '../../components/ft-element-list/ft-element-list.vue'
|
import FtElementList from '../../components/ft-element-list/ft-element-list.vue'
|
||||||
|
import FtInput from '../../components/ft-input/ft-input.vue'
|
||||||
|
|
||||||
export default Vue.extend({
|
export default Vue.extend({
|
||||||
name: 'UserPlaylists',
|
name: 'UserPlaylists',
|
||||||
|
@ -14,17 +15,23 @@ export default Vue.extend({
|
||||||
'ft-tooltip': FtTooltip,
|
'ft-tooltip': FtTooltip,
|
||||||
'ft-loader': FtLoader,
|
'ft-loader': FtLoader,
|
||||||
'ft-button': FtButton,
|
'ft-button': FtButton,
|
||||||
'ft-element-list': FtElementList
|
'ft-element-list': FtElementList,
|
||||||
|
'ft-input': FtInput
|
||||||
},
|
},
|
||||||
data: function () {
|
data: function () {
|
||||||
return {
|
return {
|
||||||
isLoading: false,
|
isLoading: false,
|
||||||
dataLimit: 100
|
dataLimit: 100,
|
||||||
|
hasQuery: false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
favoritesPlaylist: function () {
|
favoritesPlaylist: function () {
|
||||||
|
if (!this.hasQuery) {
|
||||||
return this.$store.getters.getFavorites
|
return this.$store.getters.getFavorites
|
||||||
|
} else {
|
||||||
|
return this.$store.getters.getSearchPlaylistCache
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
activeData: function () {
|
activeData: function () {
|
||||||
|
@ -59,6 +66,10 @@ export default Vue.extend({
|
||||||
increaseLimit: function () {
|
increaseLimit: function () {
|
||||||
this.dataLimit += 100
|
this.dataLimit += 100
|
||||||
sessionStorage.setItem('favoritesLimit', this.dataLimit)
|
sessionStorage.setItem('favoritesLimit', this.dataLimit)
|
||||||
|
},
|
||||||
|
filterPlaylist: function(query) {
|
||||||
|
this.hasQuery = query !== ''
|
||||||
|
this.$store.dispatch('searchFavoritePlaylist', query)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
|
@ -16,6 +16,13 @@
|
||||||
:tooltip="$t('User Playlists.Playlist Message')"
|
:tooltip="$t('User Playlists.Playlist Message')"
|
||||||
/>
|
/>
|
||||||
</h3>
|
</h3>
|
||||||
|
<ft-input
|
||||||
|
ref="searchBar"
|
||||||
|
:placeholder="$t('User Playlists.Search bar placeholder')"
|
||||||
|
:show-clear-text-button="true"
|
||||||
|
:show-action-button="false"
|
||||||
|
@input="filterPlaylist"
|
||||||
|
/>
|
||||||
<ft-flex-box
|
<ft-flex-box
|
||||||
v-if="activeData.length === 0"
|
v-if="activeData.length === 0"
|
||||||
>
|
>
|
||||||
|
|
|
@ -103,11 +103,13 @@ User Playlists:
|
||||||
videos currently here will be migrated to a 'Favorites' playlist.
|
videos currently here will be migrated to a 'Favorites' playlist.
|
||||||
Your saved videos are empty. Click on the save button on the corner of a video to have it listed here: Your saved videos are empty. Click on the save button on the corner of a video to have
|
Your saved videos are empty. Click on the save button on the corner of a video to have it listed here: Your saved videos are empty. Click on the save button on the corner of a video to have
|
||||||
it listed here
|
it listed here
|
||||||
|
Search bar placeholder: Search in Playlist
|
||||||
History:
|
History:
|
||||||
# On History Page
|
# On History Page
|
||||||
History: History
|
History: History
|
||||||
Watch History: Watch History
|
Watch History: Watch History
|
||||||
Your history list is currently empty.: Your history list is currently empty.
|
Your history list is currently empty.: Your history list is currently empty.
|
||||||
|
Search bar placeholder: "Search in History"
|
||||||
Settings:
|
Settings:
|
||||||
# On Settings Page
|
# On Settings Page
|
||||||
Settings: Settings
|
Settings: Settings
|
||||||
|
|
|
@ -98,11 +98,13 @@ User Playlists:
|
||||||
Elle ne répertorie que les vidéos que vous avez enregistrées ou mises en favoris.
|
Elle ne répertorie que les vidéos que vous avez enregistrées ou mises en favoris.
|
||||||
Une fois le travail terminé, toutes les vidéos actuellement présentes ici seront
|
Une fois le travail terminé, toutes les vidéos actuellement présentes ici seront
|
||||||
migrées vers une liste de lecture « Favoris ».
|
migrées vers une liste de lecture « Favoris ».
|
||||||
|
Search bar placeholder: Recherche dans la liste de lecture
|
||||||
History:
|
History:
|
||||||
# On History Page
|
# On History Page
|
||||||
History: 'Historique'
|
History: 'Historique'
|
||||||
Watch History: 'Historique de visionnage'
|
Watch History: 'Historique de visionnage'
|
||||||
Your history list is currently empty.: 'Votre historique est vide.'
|
Your history list is currently empty.: 'Votre historique est vide.'
|
||||||
|
Search bar placeholder: "Recherche dans l'historique"
|
||||||
Settings:
|
Settings:
|
||||||
# On Settings Page
|
# On Settings Page
|
||||||
Settings: 'Paramètres'
|
Settings: 'Paramètres'
|
||||||
|
|
Loading…
Reference in New Issue