Compare commits
	
		
			1 Commits
		
	
	
		
			master
			...
			dependency
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 6e0928a97a | 
| @@ -25,7 +25,7 @@ func getActorsFromDB() { | |||||||
| 	 * @apiSuccess {string} .Thumbnail Portrait Thumbnail | 	 * @apiSuccess {string} .Thumbnail Portrait Thumbnail | ||||||
| 	 */ | 	 */ | ||||||
| 	api.AddHandler("getAllActors", api.ActorNode, api.PermUser, func(context api.Context) { | 	api.AddHandler("getAllActors", api.ActorNode, api.PermUser, func(context api.Context) { | ||||||
| 		query := "SELECT actor_id, name, thumbnail FROM actors ORDER BY name ASC" | 		query := "SELECT actor_id, name, thumbnail FROM actors" | ||||||
| 		context.Json(readActorsFromResultset(database.Query(query))) | 		context.Json(readActorsFromResultset(database.Query(query))) | ||||||
| 	}) | 	}) | ||||||
|  |  | ||||||
|   | |||||||
| @@ -7,6 +7,7 @@ import ( | |||||||
| 	"openmediacenter/apiGo/database" | 	"openmediacenter/apiGo/database" | ||||||
| 	"openmediacenter/apiGo/videoparser" | 	"openmediacenter/apiGo/videoparser" | ||||||
| 	"os" | 	"os" | ||||||
|  | 	"path/filepath" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| func addUploadHandler() { | func addUploadHandler() { | ||||||
| @@ -30,11 +31,11 @@ func addUploadHandler() { | |||||||
| 				break | 				break | ||||||
| 			} | 			} | ||||||
|  |  | ||||||
|  | 			// todo allow more video formats than mp4 | ||||||
| 			// only allow valid extensions | 			// only allow valid extensions | ||||||
| 			if !videoparser.ValidVideoSuffix(part.FileName()) { | 			if filepath.Ext(part.FileName()) != ".mp4" { | ||||||
| 				continue | 				continue | ||||||
| 			} | 			} | ||||||
|  |  | ||||||
| 			vidpath := PathPrefix + mSettings.VideoPath + part.FileName() | 			vidpath := PathPrefix + mSettings.VideoPath + part.FileName() | ||||||
| 			dst, err := os.OpenFile(vidpath, os.O_WRONLY|os.O_CREATE, 0644) | 			dst, err := os.OpenFile(vidpath, os.O_WRONLY|os.O_CREATE, 0644) | ||||||
| 			if err != nil { | 			if err != nil { | ||||||
|   | |||||||
| @@ -78,7 +78,7 @@ func getFromDB() { | |||||||
| 	 * @apiSuccess {string} TagName name of the Tag | 	 * @apiSuccess {string} TagName name of the Tag | ||||||
| 	 */ | 	 */ | ||||||
| 	api.AddHandler("getAllTags", api.TagNode, api.PermUser, func(context api.Context) { | 	api.AddHandler("getAllTags", api.TagNode, api.PermUser, func(context api.Context) { | ||||||
| 		query := "SELECT tag_id,tag_name from tags ORDER BY tag_name ASC" | 		query := "SELECT tag_id,tag_name from tags ORDER BY tag_name" | ||||||
| 		context.Json(readTagsFromResultset(database.Query(query))) | 		context.Json(readTagsFromResultset(database.Query(query))) | ||||||
| 	}) | 	}) | ||||||
| } | } | ||||||
|   | |||||||
| @@ -21,7 +21,7 @@ func (p Perm) String() string { | |||||||
| } | } | ||||||
|  |  | ||||||
| const SignKey = "89013f1753a6890c6090b09e3c23ff43" | const SignKey = "89013f1753a6890c6090b09e3c23ff43" | ||||||
| const TokenExpireHours = 8760 | const TokenExpireHours = 24 | ||||||
|  |  | ||||||
| type Token struct { | type Token struct { | ||||||
| 	Token     string | 	Token     string | ||||||
|   | |||||||
| @@ -5,6 +5,7 @@ import ( | |||||||
| 	"encoding/json" | 	"encoding/json" | ||||||
| 	"fmt" | 	"fmt" | ||||||
| 	"net/http" | 	"net/http" | ||||||
|  | 	"reflect" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| func Jsonify(v interface{}) []byte { | func Jsonify(v interface{}) []byte { | ||||||
| @@ -29,3 +30,45 @@ func DecodeRequest(request *http.Request, arg interface{}) error { | |||||||
|  |  | ||||||
| 	return err | 	return err | ||||||
| } | } | ||||||
|  |  | ||||||
|  | // setField set a specific field of an object with an object provided | ||||||
|  | func setField(obj interface{}, name string, value interface{}) error { | ||||||
|  | 	structValue := reflect.ValueOf(obj).Elem() | ||||||
|  | 	structFieldValue := structValue.FieldByName(name) | ||||||
|  |  | ||||||
|  | 	if !structFieldValue.IsValid() { | ||||||
|  | 		return fmt.Errorf("no such field: %s in obj", name) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	if !structFieldValue.CanSet() { | ||||||
|  | 		return fmt.Errorf("cannot set %s field value", name) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	structFieldType := structFieldValue.Type() | ||||||
|  | 	val := reflect.ValueOf(value) | ||||||
|  |  | ||||||
|  | 	if structFieldType != val.Type() { | ||||||
|  | 		if val.Type().ConvertibleTo(structFieldType) { | ||||||
|  | 			// if type is convertible - convert and set | ||||||
|  | 			structFieldValue.Set(val.Convert(structFieldType)) | ||||||
|  | 		} else { | ||||||
|  | 			return fmt.Errorf("provided value %s type didn't match obj field type and isn't convertible", name) | ||||||
|  | 		} | ||||||
|  | 	} else { | ||||||
|  | 		// set value if type is the same | ||||||
|  | 		structFieldValue.Set(val) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // FillStruct fill a custom struct with objects of a map | ||||||
|  | func FillStruct(i interface{}, m map[string]interface{}) error { | ||||||
|  | 	for k, v := range m { | ||||||
|  | 		err := setField(i, k, v) | ||||||
|  | 		if err != nil { | ||||||
|  | 			return err | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	return nil | ||||||
|  | } | ||||||
|   | |||||||
| @@ -25,18 +25,20 @@ func startTVShowReindex(files []Show) { | |||||||
| } | } | ||||||
|  |  | ||||||
| func insertEpisodesIfNotExisting(show Show) { | func insertEpisodesIfNotExisting(show Show) { | ||||||
| 	query := "SELECT filename FROM tvshow_episodes JOIN tvshow t on t.id = tvshow_episodes.tvshow_id WHERE t.name=?" | 	query := "SELECT tvshow_episodes.name, season, episode FROM tvshow_episodes JOIN tvshow t on t.id = tvshow_episodes.tvshow_id WHERE t.name=?" | ||||||
| 	rows := database.Query(query, show.Name) | 	rows := database.Query(query, show.Name) | ||||||
|  |  | ||||||
| 	var dbepisodes []string | 	var dbepisodes []string | ||||||
| 	for rows.Next() { | 	for rows.Next() { | ||||||
| 		var filename string | 		var epname string | ||||||
| 		err := rows.Scan(&filename) | 		var season int | ||||||
|  | 		var episode int | ||||||
|  | 		err := rows.Scan(&epname, &season, &episode) | ||||||
| 		if err != nil { | 		if err != nil { | ||||||
| 			fmt.Println(err.Error()) | 			fmt.Println(err.Error()) | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		dbepisodes = append(dbepisodes, filename) | 		dbepisodes = append(dbepisodes, fmt.Sprintf("%s S%02dE%02d.mp4", epname, season, episode)) | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	// get those episodes that are missing in db | 	// get those episodes that are missing in db | ||||||
| @@ -81,10 +83,6 @@ VALUES (?, ?, ?, (SELECT tvshow.id FROM tvshow WHERE tvshow.name=?), ?, ?)` | |||||||
|  |  | ||||||
| // difference returns the elements in `a` that aren't in `b`. | // difference returns the elements in `a` that aren't in `b`. | ||||||
| func difference(a, b []string) []string { | func difference(a, b []string) []string { | ||||||
| 	if b == nil || len(b) == 0 { |  | ||||||
| 		return a |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	mb := make(map[string]struct{}, len(b)) | 	mb := make(map[string]struct{}, len(b)) | ||||||
| 	for _, x := range b { | 	for _, x := range b { | ||||||
| 		mb[x] = struct{}{} | 		mb[x] = struct{}{} | ||||||
| @@ -131,10 +129,7 @@ func getAllTVShows() *[]string { | |||||||
| 	var res []string | 	var res []string | ||||||
| 	for rows.Next() { | 	for rows.Next() { | ||||||
| 		var show string | 		var show string | ||||||
| 		err := rows.Scan(&show) | 		rows.Scan(&show) | ||||||
| 		if err != nil { |  | ||||||
| 			continue |  | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		res = append(res, show) | 		res = append(res, show) | ||||||
| 	} | 	} | ||||||
|   | |||||||
| @@ -14,20 +14,6 @@ type StatusMessage struct { | |||||||
| 	ContentAvailable bool | 	ContentAvailable bool | ||||||
| } | } | ||||||
|  |  | ||||||
| func getVideoTypes() []string { |  | ||||||
| 	return []string{".mp4", ".mov", ".mkv", ".flv", ".avi", ".mpeg", ".m4v"} |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func ValidVideoSuffix(filename string) bool { |  | ||||||
| 	validExts := getVideoTypes() |  | ||||||
| 	for _, validExt := range validExts { |  | ||||||
| 		if strings.HasSuffix(filename, validExt) { |  | ||||||
| 			return true |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| 	return false |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func StartReindex() bool { | func StartReindex() bool { | ||||||
| 	fmt.Println("starting reindex..") | 	fmt.Println("starting reindex..") | ||||||
| 	SendEvent("start") | 	SendEvent("start") | ||||||
| @@ -54,7 +40,7 @@ func StartReindex() bool { | |||||||
|  |  | ||||||
| 	var files []string | 	var files []string | ||||||
| 	for _, file := range filelist { | 	for _, file := range filelist { | ||||||
| 		if !file.IsDir() && ValidVideoSuffix(file.Name()) { | 		if !file.IsDir() && strings.HasSuffix(file.Name(), ".mp4") { | ||||||
| 			files = append(files, file.Name()) | 			files = append(files, file.Name()) | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| @@ -117,7 +103,7 @@ func StartTVShowReindex() { | |||||||
| 			} | 			} | ||||||
|  |  | ||||||
| 			for _, epfile := range episodefiles { | 			for _, epfile := range episodefiles { | ||||||
| 				if ValidVideoSuffix(epfile.Name()) { | 				if strings.HasSuffix(epfile.Name(), ".mp4") { | ||||||
| 					elem.files = append(elem.files, epfile.Name()) | 					elem.files = append(elem.files, epfile.Name()) | ||||||
| 				} | 				} | ||||||
| 			} | 			} | ||||||
|   | |||||||
							
								
								
									
										52
									
								
								package.json
									
									
									
									
									
								
							
							
						
						
									
										52
									
								
								package.json
									
									
									
									
									
								
							| @@ -8,17 +8,17 @@ | |||||||
|     "url": "https://heili.eu" |     "url": "https://heili.eu" | ||||||
|   }, |   }, | ||||||
|   "dependencies": { |   "dependencies": { | ||||||
|     "@fortawesome/fontawesome-svg-core": "^1.2.32", |     "@fortawesome/fontawesome-svg-core": "^6.2.0", | ||||||
|     "@fortawesome/free-regular-svg-icons": "^5.15.1", |     "@fortawesome/free-regular-svg-icons": "^6.2.0", | ||||||
|     "@fortawesome/free-solid-svg-icons": "^5.15.1", |     "@fortawesome/free-solid-svg-icons": "^6.2.0", | ||||||
|     "@fortawesome/react-fontawesome": "^0.1.13", |     "@fortawesome/react-fontawesome": "^0.2.0", | ||||||
|     "bootstrap": "^5.0.2", |     "bootstrap": "^5.0.2", | ||||||
|     "plyr-react": "^3.0.7", |     "plyr-react": "^5.1.0", | ||||||
|     "react": "^17.0.1", |     "react": "^18.2.0", | ||||||
|     "react-bootstrap": "^1.4.0", |     "react-bootstrap": "^2.5.0", | ||||||
|     "react-dom": "^17.0.1", |     "react-dom": "^18.2.0", | ||||||
|     "react-router": "^5.2.0", |     "react-router": "^6.4.0", | ||||||
|     "react-router-dom": "^5.2.0", |     "react-router-dom": "^6.4.0", | ||||||
|     "typescript": "^4.3.5" |     "typescript": "^4.3.5" | ||||||
|   }, |   }, | ||||||
|   "scripts": { |   "scripts": { | ||||||
| @@ -54,31 +54,31 @@ | |||||||
|   }, |   }, | ||||||
|   "devDependencies": { |   "devDependencies": { | ||||||
|     "@testing-library/jest-dom": "^5.14.1", |     "@testing-library/jest-dom": "^5.14.1", | ||||||
|     "@testing-library/react": "^12.0.0", |     "@testing-library/react": "^13.4.0", | ||||||
|     "@testing-library/user-event": "^13.2.1", |     "@testing-library/user-event": "^14.4.3", | ||||||
|     "@types/jest": "^26.0.24", |     "@types/jest": "^29.0.3", | ||||||
|     "@types/node": "^16.4.7", |     "@types/node": "^18.7.18", | ||||||
|     "@types/react": "^17.0.15", |     "@types/react": "^18.0.20", | ||||||
|     "@types/react-dom": "^17.0.9", |     "@types/react-dom": "^18.0.6", | ||||||
|     "@types/react-router": "5.1.16", |     "@types/react-router": "5.1.19", | ||||||
|     "@types/react-router-dom": "^5.1.8", |     "@types/react-router-dom": "^5.1.8", | ||||||
|     "@typescript-eslint/eslint-plugin": "^4.28.5", |     "@typescript-eslint/eslint-plugin": "^5.38.0", | ||||||
|     "@typescript-eslint/parser": "^4.28.5", |     "@typescript-eslint/parser": "^5.38.0", | ||||||
|     "apidoc": "^0.28.1", |     "apidoc": "^0.53.0", | ||||||
|     "enzyme": "^3.11.0", |     "enzyme": "^3.11.0", | ||||||
|     "enzyme-adapter-react-16": "^1.15.5", |     "enzyme-adapter-react-16": "^1.15.5", | ||||||
|     "eslint": "^7.31.0", |     "eslint": "^8.23.1", | ||||||
|     "eslint-config-prettier": "^8.1.0", |     "eslint-config-prettier": "^8.1.0", | ||||||
|     "eslint-formatter-gitlab": "^2.2.0", |     "eslint-formatter-gitlab": "^3.0.0", | ||||||
|     "eslint-plugin-eslint-comments": "^3.2.0", |     "eslint-plugin-eslint-comments": "^3.2.0", | ||||||
|     "eslint-plugin-jest": "^24.4.0", |     "eslint-plugin-jest": "^27.0.4", | ||||||
|     "eslint-plugin-prettier": "^3.3.1", |     "eslint-plugin-prettier": "^4.2.1", | ||||||
|     "eslint-plugin-react": "^7.22.0", |     "eslint-plugin-react": "^7.22.0", | ||||||
|     "eslint-plugin-react-hooks": "^4.2.0", |     "eslint-plugin-react-hooks": "^4.2.0", | ||||||
|     "jest-junit": "^12.0.0", |     "jest-junit": "^14.0.1", | ||||||
|     "prettier": "^2.3.2", |     "prettier": "^2.3.2", | ||||||
|     "prettier-config": "^1.0.0", |     "prettier-config": "^1.0.0", | ||||||
|     "react-scripts": "4.0.3" |     "react-scripts": "5.0.1" | ||||||
|   }, |   }, | ||||||
|   "apidoc": { |   "apidoc": { | ||||||
|     "name": "OpenMediaCenter", |     "name": "OpenMediaCenter", | ||||||
|   | |||||||
| @@ -15,6 +15,10 @@ | |||||||
|     text-decoration: none; |     text-decoration: none; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | .navitem-active { | ||||||
|  |     opacity: 0.85; | ||||||
|  | } | ||||||
|  |  | ||||||
| .navitem:hover { | .navitem:hover { | ||||||
|     opacity: 1; |     opacity: 1; | ||||||
|     text-decoration: none; |     text-decoration: none; | ||||||
|   | |||||||
							
								
								
									
										35
									
								
								src/App.tsx
									
									
									
									
									
								
							
							
						
						
									
										35
									
								
								src/App.tsx
									
									
									
									
									
								
							| @@ -10,7 +10,7 @@ import style from './App.module.css'; | |||||||
| import SettingsPage from './pages/SettingsPage/SettingsPage'; | import SettingsPage from './pages/SettingsPage/SettingsPage'; | ||||||
| import CategoryPage from './pages/CategoryPage/CategoryPage'; | import CategoryPage from './pages/CategoryPage/CategoryPage'; | ||||||
|  |  | ||||||
| import {NavLink, Route, Switch, useRouteMatch} from 'react-router-dom'; | import {NavLink, Route, Routes} from 'react-router-dom'; | ||||||
| import Player from './pages/Player/Player'; | import Player from './pages/Player/Player'; | ||||||
| import ActorOverviewPage from './pages/ActorOverviewPage/ActorOverviewPage'; | import ActorOverviewPage from './pages/ActorOverviewPage/ActorOverviewPage'; | ||||||
| import ActorPage from './pages/ActorPage/ActorPage'; | import ActorPage from './pages/ActorPage/ActorPage'; | ||||||
| @@ -47,7 +47,7 @@ class App extends React.Component<{}, state> { | |||||||
|  |  | ||||||
|         return ( |         return ( | ||||||
|             <LoginContextProvider> |             <LoginContextProvider> | ||||||
|                 <Switch> |                 <Routes> | ||||||
|                     <Route path='/login'> |                     <Route path='/login'> | ||||||
|                         <AuthenticationPage /> |                         <AuthenticationPage /> | ||||||
|                     </Route> |                     </Route> | ||||||
| @@ -55,13 +55,19 @@ class App extends React.Component<{}, state> { | |||||||
|                         {this.navBar()} |                         {this.navBar()} | ||||||
|                         <MyRouter /> |                         <MyRouter /> | ||||||
|                     </Route> |                     </Route> | ||||||
|                 </Switch> |                 </Routes> | ||||||
|             </LoginContextProvider> |             </LoginContextProvider> | ||||||
|         ); |         ); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     static contextType = FeatureContext; |     static contextType = FeatureContext; | ||||||
|  |  | ||||||
|  |     activeTab(history, path) { | ||||||
|  |         if (history.location.pathname === path) { | ||||||
|  |             return { color: "red" }; | ||||||
|  |         } | ||||||
|  |     }; | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
|      * render the top navigation bar |      * render the top navigation bar | ||||||
|      */ |      */ | ||||||
| @@ -75,39 +81,34 @@ class App extends React.Component<{}, state> { | |||||||
|                     Home |                     Home | ||||||
|                 </NavLink> |                 </NavLink> | ||||||
|                 <NavLink |                 <NavLink | ||||||
|                     className={[style.navitem, themeStyle.navitem].join(' ')} |  | ||||||
|                     to={'/media/random'} |                     to={'/media/random'} | ||||||
|                     activeStyle={{opacity: '0.85'}}> |                     className={({ isActive }) => [style.navitem, themeStyle.navitem, (isActive ? 'navitem-active' : '')].join(' ')}> | ||||||
|                     Random Video |                     Random Video | ||||||
|                 </NavLink> |                 </NavLink> | ||||||
|  |  | ||||||
|                 <NavLink |                 <NavLink | ||||||
|                     className={[style.navitem, themeStyle.navitem].join(' ')} |                     className={({ isActive }) => [style.navitem, themeStyle.navitem, (isActive ? 'navitem-active' : '')].join(' ')} | ||||||
|                     to={'/media/categories'} |                     to={'/media/categories'}> | ||||||
|                     activeStyle={{opacity: '0.85'}}> |  | ||||||
|                     Categories |                     Categories | ||||||
|                 </NavLink> |                 </NavLink> | ||||||
|  |  | ||||||
|                 <NavLink |                 <NavLink | ||||||
|                     className={[style.navitem, themeStyle.navitem].join(' ')} |                     className={({ isActive }) => [style.navitem, themeStyle.navitem, (isActive ? 'navitem-active' : '')].join(' ')} | ||||||
|                     to={'/media/actors'} |                     to={'/media/actors'}> | ||||||
|                     activeStyle={{opacity: '0.85'}}> |  | ||||||
|                     Actors |                     Actors | ||||||
|                 </NavLink> |                 </NavLink> | ||||||
|  |  | ||||||
|                 {this.context.TVShowEnabled ? ( |                 {this.context.TVShowEnabled ? ( | ||||||
|                     <NavLink |                     <NavLink | ||||||
|                         className={[style.navitem, themeStyle.navitem].join(' ')} |                         className={({ isActive }) => [style.navitem, themeStyle.navitem, (isActive ? 'navitem-active' : '')].join(' ')} | ||||||
|                         to={'/media/tvshows'} |                         to={'/media/tvshows'}> | ||||||
|                         activeStyle={{opacity: '0.85'}}> |  | ||||||
|                         TV Shows |                         TV Shows | ||||||
|                     </NavLink> |                     </NavLink> | ||||||
|                 ) : null} |                 ) : null} | ||||||
|  |  | ||||||
|                 <NavLink |                 <NavLink | ||||||
|                     className={[style.navitem, themeStyle.navitem].join(' ')} |                     className={({ isActive }) => [style.navitem, themeStyle.navitem, (isActive ? 'navitem-active' : '')].join(' ')} | ||||||
|                     to={'/media/settings'} |                     to={'/media/settings'}> | ||||||
|                     activeStyle={{opacity: '0.85'}}> |  | ||||||
|                     Settings |                     Settings | ||||||
|                 </NavLink> |                 </NavLink> | ||||||
|             </div> |             </div> | ||||||
|   | |||||||
| @@ -1,8 +1,8 @@ | |||||||
| import React from 'react'; | import React, {PropsWithChildren} from 'react'; | ||||||
| import style from './SideBar.module.css'; | import style from './SideBar.module.css'; | ||||||
| import GlobalInfos from '../../utils/GlobalInfos'; | import GlobalInfos from '../../utils/GlobalInfos'; | ||||||
|  |  | ||||||
| interface SideBarProps { | interface SideBarProps extends  PropsWithChildren{ | ||||||
|     hiddenFrame?: boolean; |     hiddenFrame?: boolean; | ||||||
|     width?: string; |     width?: string; | ||||||
| } | } | ||||||
|   | |||||||
| @@ -58,7 +58,7 @@ export class HomePage extends React.Component<Props, state> { | |||||||
|         }; |         }; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     sortState = SortBy.random; |     sortState = SortBy.date; | ||||||
|     tagState = DefaultTags.all; |     tagState = DefaultTags.all; | ||||||
|  |  | ||||||
|     componentDidMount(): void { |     componentDidMount(): void { | ||||||
|   | |||||||
| @@ -66,7 +66,7 @@ export class EpisodePage extends React.Component<Props, State> { | |||||||
| export const EpisodeTile = (props: {episode: Episode}): JSX.Element => { | export const EpisodeTile = (props: {episode: Episode}): JSX.Element => { | ||||||
|     const themestyle = GlobalInfos.getThemeStyle(); |     const themestyle = GlobalInfos.getThemeStyle(); | ||||||
|     return ( |     return ( | ||||||
|         <Link to={'/media/tvplayer/' + props.episode.ID}> |         <Link to={'/tvplayer/' + props.episode.ID}> | ||||||
|             <div className={tileStyle.tile + ' ' + themestyle.secbackground + ' ' + themestyle.textcolor}> |             <div className={tileStyle.tile + ' ' + themestyle.secbackground + ' ' + themestyle.textcolor}> | ||||||
|                 <FontAwesomeIcon |                 <FontAwesomeIcon | ||||||
|                     style={{ |                     style={{ | ||||||
|   | |||||||
| @@ -94,7 +94,7 @@ export class TVPlayer extends React.Component<Props, State> { | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     private closebtn(): void { |     private closebtn(): void { | ||||||
|         this.props.history.goBack(); |         this.props.goBack(); | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -3,10 +3,11 @@ import Preview from '../../elements/Preview/Preview'; | |||||||
| import {APINode, callAPI, callAPIPlain} from '../../utils/Api'; | import {APINode, callAPI, callAPIPlain} from '../../utils/Api'; | ||||||
| import {TVShow} from '../../types/ApiTypes'; | import {TVShow} from '../../types/ApiTypes'; | ||||||
| import DynamicContentContainer from '../../elements/DynamicContentContainer/DynamicContentContainer'; | import DynamicContentContainer from '../../elements/DynamicContentContainer/DynamicContentContainer'; | ||||||
| import {Route, Switch, useRouteMatch} from 'react-router-dom'; | import {Route, Routes, useMatch} from 'react-router-dom'; | ||||||
| import EpisodePage from './EpisodePage'; | import EpisodePage from './EpisodePage'; | ||||||
| import PageTitle, {Line} from '../../elements/PageTitle/PageTitle'; | import PageTitle, {Line} from '../../elements/PageTitle/PageTitle'; | ||||||
| import SideBar, {SideBarItem, SideBarTitle} from '../../elements/SideBar/SideBar'; | import SideBar, {SideBarItem, SideBarTitle} from '../../elements/SideBar/SideBar'; | ||||||
|  | import {useLocation} from "react-router"; | ||||||
|  |  | ||||||
| interface State { | interface State { | ||||||
|     loading: boolean; |     loading: boolean; | ||||||
| @@ -68,16 +69,16 @@ export class TVShowPage extends React.Component<Props, State> { | |||||||
| } | } | ||||||
|  |  | ||||||
| export default function (): JSX.Element { | export default function (): JSX.Element { | ||||||
|     let match = useRouteMatch(); |     const { pathname } = useLocation(); | ||||||
|  |  | ||||||
|     return ( |     return ( | ||||||
|         <Switch> |         <Routes> | ||||||
|             <Route exact path={`${match.path}/:id`}> |             <Route path={`${pathname}/:id`}> | ||||||
|                 <EpisodePage /> |                 <EpisodePage /> | ||||||
|             </Route> |             </Route> | ||||||
|             <Route path={match.path}> |             <Route path={pathname}> | ||||||
|                 <TVShowPage /> |                 <TVShowPage /> | ||||||
|             </Route> |             </Route> | ||||||
|         </Switch> |         </Routes> | ||||||
|     ); |     ); | ||||||
| } | } | ||||||
|   | |||||||
| @@ -78,8 +78,8 @@ function generalAPICall<T>( | |||||||
|                 // decode json or text |                 // decode json or text | ||||||
|                 const data = json ? await response.json() : await response.text(); |                 const data = json ? await response.json() : await response.text(); | ||||||
|                 callback(data); |                 callback(data); | ||||||
|             } catch (e) { |             } catch (e: any) { | ||||||
|                 errorcallback(e); |                 errorcallback(e.toString()); | ||||||
|             } |             } | ||||||
|         } else if (response.status === 400) { |         } else if (response.status === 400) { | ||||||
|             // Bad Request --> invalid token |             // Bad Request --> invalid token | ||||||
|   | |||||||
| @@ -1,4 +1,4 @@ | |||||||
| import React, {FunctionComponent, useState} from 'react'; | import React, {FunctionComponent, PropsWithChildren, useState} from 'react'; | ||||||
|  |  | ||||||
| export interface FeatureContextType { | export interface FeatureContextType { | ||||||
|     setTVShowEnabled: (enabled: boolean) => void; |     setTVShowEnabled: (enabled: boolean) => void; | ||||||
| @@ -17,7 +17,7 @@ export const FeatureContext = React.createContext<FeatureContextType>({ | |||||||
|     VideosFullyDeleteable: false |     VideosFullyDeleteable: false | ||||||
| }); | }); | ||||||
|  |  | ||||||
| export const FeatureContextProvider: FunctionComponent = (props): JSX.Element => { | export const FeatureContextProvider: FunctionComponent<PropsWithChildren> = (props): JSX.Element => { | ||||||
|     const [tvshowenabled, settvshowenabled] = useState(false); |     const [tvshowenabled, settvshowenabled] = useState(false); | ||||||
|     const [fullydeletablevids, setfullydeleteable] = useState(false); |     const [fullydeletablevids, setfullydeleteable] = useState(false); | ||||||
|  |  | ||||||
|   | |||||||
| @@ -1,13 +1,13 @@ | |||||||
| import {LoginContext, LoginPerm, LoginState} from './LoginContext'; | import {LoginContext, LoginPerm, LoginState} from './LoginContext'; | ||||||
| import React, {FunctionComponent, useContext, useEffect, useState} from 'react'; | import React, {FunctionComponent, PropsWithChildren, useContext, useEffect, useState} from 'react'; | ||||||
| import {useHistory, useLocation} from 'react-router'; | import {useLocation, useNavigate} from 'react-router'; | ||||||
| import {cookie} from './Cookie'; | import {cookie} from './Cookie'; | ||||||
| import {APINode, callAPI} from '../Api'; | import {APINode, callAPI} from '../Api'; | ||||||
| import {SettingsTypes} from '../../types/ApiTypes'; | import {SettingsTypes} from '../../types/ApiTypes'; | ||||||
| import GlobalInfos from '../GlobalInfos'; | import GlobalInfos from '../GlobalInfos'; | ||||||
| import {FeatureContext} from './FeatureContext'; | import {FeatureContext} from './FeatureContext'; | ||||||
|  |  | ||||||
| export const LoginContextProvider: FunctionComponent = (props): JSX.Element => { | export const LoginContextProvider: FunctionComponent<PropsWithChildren> = (props): JSX.Element => { | ||||||
|     let initialLoginState = LoginState.LoggedIn; |     let initialLoginState = LoginState.LoggedIn; | ||||||
|     let initialUserPerm = LoginPerm.User; |     let initialUserPerm = LoginPerm.User; | ||||||
|  |  | ||||||
| @@ -50,7 +50,7 @@ export const LoginContextProvider: FunctionComponent = (props): JSX.Element => { | |||||||
|         ); |         ); | ||||||
|     }, [features, loginState]); |     }, [features, loginState]); | ||||||
|  |  | ||||||
|     const hist = useHistory(); |     const navigate = useNavigate(); | ||||||
|     const loc = useLocation(); |     const loc = useLocation(); | ||||||
|  |  | ||||||
|     // trigger redirect on loginstate change |     // trigger redirect on loginstate change | ||||||
| @@ -59,14 +59,14 @@ export const LoginContextProvider: FunctionComponent = (props): JSX.Element => { | |||||||
|             // if we arent already in dashboard tree we want to redirect to default dashboard page |             // if we arent already in dashboard tree we want to redirect to default dashboard page | ||||||
|             console.log('redirecting to dashboard' + loc.pathname); |             console.log('redirecting to dashboard' + loc.pathname); | ||||||
|             if (!loc.pathname.startsWith('/media')) { |             if (!loc.pathname.startsWith('/media')) { | ||||||
|                 hist.replace('/media'); |                 navigate('/media'); | ||||||
|             } |             } | ||||||
|         } else { |         } else { | ||||||
|             if (!loc.pathname.startsWith('/login')) { |             if (!loc.pathname.startsWith('/login')) { | ||||||
|                 hist.replace('/login'); |                 navigate('/login'); | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|     }, [hist, loc.pathname, loginState]); |     }, [navigate, loc.pathname, loginState]); | ||||||
|  |  | ||||||
|     const value = { |     const value = { | ||||||
|         logout: (): void => { |         logout: (): void => { | ||||||
| @@ -86,7 +86,7 @@ export const LoginContextProvider: FunctionComponent = (props): JSX.Element => { | |||||||
|     return <LoginContext.Provider value={value}>{props.children}</LoginContext.Provider>; |     return <LoginContext.Provider value={value}>{props.children}</LoginContext.Provider>; | ||||||
| }; | }; | ||||||
|  |  | ||||||
| interface Props { | interface Props extends PropsWithChildren{ | ||||||
|     perm: LoginPerm; |     perm: LoginPerm; | ||||||
| } | } | ||||||
|  |  | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user