Merge branch 'layout'
This commit is contained in:
commit
ca49ab170f
18
settings.py
18
settings.py
@ -66,6 +66,24 @@ For security reasons, enabling this is not recommended.''',
|
|||||||
1 to sort by newest''',
|
1 to sort by newest''',
|
||||||
}),
|
}),
|
||||||
|
|
||||||
|
('theater_mode', {
|
||||||
|
'type': bool,
|
||||||
|
'default': True,
|
||||||
|
'comment': '',
|
||||||
|
}),
|
||||||
|
|
||||||
|
('default_resolution', {
|
||||||
|
'type': int,
|
||||||
|
'default': 720,
|
||||||
|
'comment': '',
|
||||||
|
}),
|
||||||
|
|
||||||
|
('theme', {
|
||||||
|
'type': int,
|
||||||
|
'default': 0,
|
||||||
|
'comment': '',
|
||||||
|
}),
|
||||||
|
|
||||||
('gather_googlevideo_domains', {
|
('gather_googlevideo_domains', {
|
||||||
'type': bool,
|
'type': bool,
|
||||||
'default': False,
|
'default': False,
|
||||||
|
@ -1,7 +1,22 @@
|
|||||||
import flask
|
import flask
|
||||||
|
import settings
|
||||||
yt_app = flask.Flask(__name__)
|
yt_app = flask.Flask(__name__)
|
||||||
yt_app.url_map.strict_slashes = False
|
yt_app.url_map.strict_slashes = False
|
||||||
|
|
||||||
@yt_app.route('/')
|
@yt_app.route('/')
|
||||||
def homepage():
|
def homepage():
|
||||||
return flask.render_template('base.html', title="Youtube local")
|
return flask.render_template('home.html', title="Youtube local")
|
||||||
|
|
||||||
|
|
||||||
|
theme_names = {
|
||||||
|
0: 'light_theme',
|
||||||
|
1: 'gray_theme',
|
||||||
|
2: 'dark_theme',
|
||||||
|
}
|
||||||
|
|
||||||
|
@yt_app.context_processor
|
||||||
|
def inject_theme_preference():
|
||||||
|
return {
|
||||||
|
'theme_path': '/youtube.com/static/' + theme_names[settings.theme] + '.css',
|
||||||
|
}
|
||||||
|
|
||||||
|
@ -82,7 +82,6 @@ def get_local_playlist_videos(name, offset=0, amount=50):
|
|||||||
else:
|
else:
|
||||||
info['thumbnail'] = util.get_thumbnail_url(info['id'])
|
info['thumbnail'] = util.get_thumbnail_url(info['id'])
|
||||||
missing_thumbnails.append(info['id'])
|
missing_thumbnails.append(info['id'])
|
||||||
info['item_size'] = 'small'
|
|
||||||
info['type'] = 'video'
|
info['type'] = 'video'
|
||||||
yt_data_extract.add_extra_html_info(info)
|
yt_data_extract.add_extra_html_info(info)
|
||||||
videos.append(info)
|
videos.append(info)
|
||||||
|
@ -69,7 +69,7 @@
|
|||||||
display:grid;
|
display:grid;
|
||||||
grid-template-columns: auto auto 100px 1fr;
|
grid-template-columns: auto auto 100px 1fr;
|
||||||
grid-template-rows: 0fr 0fr 0fr 0fr;
|
grid-template-rows: 0fr 0fr 0fr 0fr;
|
||||||
background-color: #dadada;
|
background-color: var(--interface-color);
|
||||||
justify-content: start;
|
justify-content: start;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -102,8 +102,6 @@
|
|||||||
grid-column: 3;
|
grid-column: 3;
|
||||||
grid-row: 1;
|
grid-row: 1;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
color: black;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -126,4 +124,5 @@
|
|||||||
.more-comments{
|
.more-comments{
|
||||||
justify-self:center;
|
justify-self:center;
|
||||||
margin-top:10px;
|
margin-top:10px;
|
||||||
|
margin-bottom: 10px;
|
||||||
}
|
}
|
||||||
|
21
youtube/static/dark_theme.css
Normal file
21
youtube/static/dark_theme.css
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
body{
|
||||||
|
--interface-color: #333333;
|
||||||
|
--text-color: #cccccc;
|
||||||
|
--background-color: #000000;
|
||||||
|
}
|
||||||
|
|
||||||
|
a:link {
|
||||||
|
color: #22aaff;
|
||||||
|
}
|
||||||
|
|
||||||
|
a:visited {
|
||||||
|
color: ##7755ff;
|
||||||
|
}
|
||||||
|
|
||||||
|
a:not([href]){
|
||||||
|
color: var(--text-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.comment .permalink{
|
||||||
|
color: #ffffff;
|
||||||
|
}
|
9
youtube/static/gray_theme.css
Normal file
9
youtube/static/gray_theme.css
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
body{
|
||||||
|
--interface-color: #dadada;
|
||||||
|
--text-color: #222222;
|
||||||
|
--background-color: #bcbcbc;
|
||||||
|
}
|
||||||
|
|
||||||
|
.comment .permalink{
|
||||||
|
color: #000000;
|
||||||
|
}
|
9
youtube/static/light_theme.css
Normal file
9
youtube/static/light_theme.css
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
body{
|
||||||
|
--interface-color: #ffffff;
|
||||||
|
--text-color: #222222;
|
||||||
|
--background-color: #f8f8f8;
|
||||||
|
}
|
||||||
|
|
||||||
|
.comment .permalink{
|
||||||
|
color: #000000;
|
||||||
|
}
|
@ -4,93 +4,114 @@ h1, h2, h3, h4, h5, h6, div, button{
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
body{
|
|
||||||
margin:0;
|
|
||||||
padding: 0;
|
|
||||||
color:#222;
|
|
||||||
|
|
||||||
|
|
||||||
background-color:#cccccc;
|
|
||||||
|
|
||||||
min-height:100vh;
|
|
||||||
|
|
||||||
display:grid;
|
|
||||||
grid-template-rows: 50px 1fr;
|
|
||||||
}
|
|
||||||
|
|
||||||
header{
|
|
||||||
background-color:#333333;
|
|
||||||
|
|
||||||
grid-row: 1;
|
|
||||||
|
|
||||||
display:grid;
|
|
||||||
grid-template-columns: minmax(0px, 3fr) 640px 40px 500px minmax(0px,2fr);
|
|
||||||
}
|
|
||||||
|
|
||||||
main{
|
|
||||||
grid-row: 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
address{
|
address{
|
||||||
font-style:normal;
|
font-style:normal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
body{
|
||||||
|
margin:0;
|
||||||
|
padding: 0;
|
||||||
|
color:var(--text-color);
|
||||||
|
|
||||||
|
|
||||||
#site-search{
|
background-color:var(--background-color);
|
||||||
grid-column: 2;
|
|
||||||
display: grid;
|
|
||||||
grid-template-columns: 1fr auto auto;
|
|
||||||
|
|
||||||
|
min-height:100vh;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
header{
|
||||||
|
background-color:#333333;
|
||||||
|
height: 50px;
|
||||||
|
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
#site-search .search-box{
|
#home-link{
|
||||||
align-self:center;
|
align-self: center;
|
||||||
height:25px;
|
margin-left:10px;
|
||||||
border:0;
|
color: #ffffff;
|
||||||
|
}
|
||||||
|
|
||||||
grid-column: 1;
|
|
||||||
}
|
|
||||||
#site-search .search-button{
|
|
||||||
grid-column: 2;
|
|
||||||
align-self:center;
|
|
||||||
height:25px;
|
|
||||||
|
|
||||||
border-style:solid;
|
#site-search{
|
||||||
border-width:1px;
|
max-width: 600px;
|
||||||
|
margin-left:10px;
|
||||||
|
display: flex;
|
||||||
|
flex-grow: 1;
|
||||||
}
|
}
|
||||||
#site-search .dropdown{
|
|
||||||
margin-left:5px;
|
#site-search .search-box{
|
||||||
grid-column: 3;
|
align-self:center;
|
||||||
align-self:center;
|
height:25px;
|
||||||
height:25px;
|
border:0;
|
||||||
}
|
|
||||||
#site-search .dropdown button{
|
flex-grow: 1;
|
||||||
|
}
|
||||||
|
#site-search .search-button{
|
||||||
align-self:center;
|
align-self:center;
|
||||||
height:25px;
|
height:25px;
|
||||||
|
|
||||||
border-style:solid;
|
border-style:solid;
|
||||||
border-width:1px;
|
border-width:1px;
|
||||||
}
|
}
|
||||||
#site-search .css-sucks{
|
#site-search .dropdown{
|
||||||
width:0px;
|
margin-left:5px;
|
||||||
height:0px;
|
align-self:center;
|
||||||
|
height:25px;
|
||||||
}
|
}
|
||||||
#site-search .dropdown-content{
|
#site-search .dropdown button{
|
||||||
grid-template-columns: auto auto;
|
align-self:center;
|
||||||
white-space: nowrap;
|
height:25px;
|
||||||
|
|
||||||
|
border-style:solid;
|
||||||
|
border-width:1px;
|
||||||
}
|
}
|
||||||
#site-search .dropdown-content h3{
|
#site-search .css-sucks{
|
||||||
grid-column:1 / span 2;
|
width:0px;
|
||||||
|
height:0px;
|
||||||
|
}
|
||||||
|
#site-search .dropdown-content{
|
||||||
|
grid-template-columns: auto auto;
|
||||||
|
white-space: nowrap;
|
||||||
}
|
}
|
||||||
|
#site-search .dropdown-content h3{
|
||||||
|
grid-column:1 / span 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
#playlist-edit{
|
||||||
|
margin-left: 10px;
|
||||||
|
align-self: center;
|
||||||
|
}
|
||||||
|
#local-playlists{
|
||||||
|
margin-right:5px;
|
||||||
|
color: #ffffff;
|
||||||
|
}
|
||||||
|
#playlist-name-selection{
|
||||||
|
}
|
||||||
|
#playlist-add-button{
|
||||||
|
padding-left: 10px;
|
||||||
|
padding-right: 10px;
|
||||||
|
}
|
||||||
|
#item-selection-reset{
|
||||||
|
padding-left: 10px;
|
||||||
|
padding-right: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
main{
|
||||||
|
flex-grow: 1;
|
||||||
|
padding-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
.dropdown{
|
.dropdown{
|
||||||
z-index:1;
|
z-index:1;
|
||||||
}
|
}
|
||||||
.dropdown-content{
|
.dropdown-content{
|
||||||
display:none;
|
display:none;
|
||||||
background-color: #e9e9e9;
|
background-color: var(--interface-color);
|
||||||
}
|
}
|
||||||
.dropdown:hover .dropdown-content{
|
.dropdown:hover .dropdown-content{
|
||||||
/* For some reason, if this is just grid, it will insist on being 0px wide just like its 0px by 0px parent */
|
/* For some reason, if this is just grid, it will insist on being 0px wide just like its 0px by 0px parent */
|
||||||
@ -98,281 +119,179 @@ address{
|
|||||||
display:inline-grid;
|
display:inline-grid;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#header-right{
|
|
||||||
grid-column:4;
|
|
||||||
|
|
||||||
display:grid;
|
|
||||||
grid-template-columns:auto auto auto 1fr;
|
|
||||||
grid-template-rows: 1fr;
|
|
||||||
width: 540px;
|
|
||||||
}
|
|
||||||
#playlist-edit{
|
|
||||||
display:contents;
|
|
||||||
}
|
|
||||||
#local-playlists{
|
|
||||||
grid-column: 1;
|
|
||||||
grid-row:1;
|
|
||||||
align-self: center;
|
|
||||||
margin-right:5px;
|
|
||||||
color: #ffffff;
|
|
||||||
}
|
|
||||||
#playlist-name-selection{
|
|
||||||
grid-column:2;
|
|
||||||
grid-row:1;
|
|
||||||
justify-self:start;
|
|
||||||
align-self: center;
|
|
||||||
}
|
|
||||||
#playlist-add-button{
|
|
||||||
grid-column:3;
|
|
||||||
grid-row:1;
|
|
||||||
align-self: center;
|
|
||||||
padding-left: 10px;
|
|
||||||
padding-right: 10px;
|
|
||||||
}
|
|
||||||
#item-selection-reset{
|
|
||||||
grid-column:4;
|
|
||||||
grid-row:1;
|
|
||||||
align-self: center;
|
|
||||||
justify-self:start;
|
|
||||||
padding-left: 10px;
|
|
||||||
padding-right: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
.item-list{
|
.item-list{
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-auto-rows: 138px;
|
|
||||||
grid-row-gap: 10px;
|
grid-row-gap: 10px;
|
||||||
|
|
||||||
}
|
}
|
||||||
.item-list .video-thumbnail-box{
|
|
||||||
width:246px;
|
|
||||||
}
|
|
||||||
.item-list .playlist-thumbnail-box{
|
|
||||||
width:246px;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
.item-grid{
|
.item-grid{
|
||||||
display:grid;
|
display: flex;
|
||||||
grid-template-columns: repeat(auto-fill, 400px);
|
flex-wrap: wrap;
|
||||||
grid-auto-rows: 94px;
|
|
||||||
grid-row-gap: 10px;
|
|
||||||
}
|
}
|
||||||
.item-grid .video-thumbnail-box{
|
.item-grid > .playlist-item-box{
|
||||||
width:168px;
|
margin-right: 10px;
|
||||||
}
|
}
|
||||||
.item-grid .playlist-thumbnail-box{
|
.item-grid > * {
|
||||||
width:168px;
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
.item-grid .horizontal-item-box .item{
|
||||||
|
width:370px;
|
||||||
|
}
|
||||||
|
.item-grid .vertical-item-box .item{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.item-box{
|
||||||
|
display: inline-flex;
|
||||||
.medium-item-box{
|
flex-direction: row;
|
||||||
|
|
||||||
display:grid;
|
|
||||||
grid-template-columns: 1fr 30px;
|
|
||||||
}
|
}
|
||||||
.medium-item{
|
.vertical-item-box{
|
||||||
background-color:#bcbcbc;
|
|
||||||
text-decoration:none;
|
|
||||||
font-size: 12px;
|
|
||||||
color: #767676;
|
|
||||||
|
|
||||||
display: grid;
|
|
||||||
align-content: start;
|
|
||||||
grid-template-columns: auto 1fr auto;
|
|
||||||
grid-template-rows: auto auto auto auto auto 1fr;
|
|
||||||
}
|
}
|
||||||
.medium-item .title{
|
.horizontal-item-box{
|
||||||
grid-column:2 / span 2;
|
|
||||||
grid-row:1;
|
|
||||||
justify-self:start;
|
|
||||||
min-width: 0;
|
|
||||||
max-height:3.6em;
|
|
||||||
overflow:hidden;
|
|
||||||
|
|
||||||
color: #333;
|
|
||||||
font-size: 16px;
|
|
||||||
font-weight: 500;
|
|
||||||
text-decoration:initial;
|
|
||||||
}
|
|
||||||
.medium-item address{
|
|
||||||
display:inline;
|
|
||||||
}
|
|
||||||
/*.medium-item .views{
|
|
||||||
grid-column: 3;
|
|
||||||
grid-row: 2;
|
|
||||||
justify-self:end;
|
|
||||||
}
|
|
||||||
.medium-item time{
|
|
||||||
grid-column: 2;
|
|
||||||
grid-row: 3;
|
|
||||||
justify-self:start;
|
|
||||||
}*/
|
|
||||||
.medium-item .stats{
|
|
||||||
grid-column: 2 / span 2;
|
|
||||||
grid-row: 2;
|
|
||||||
max-height:2.4em;
|
|
||||||
overflow:hidden;
|
|
||||||
}
|
|
||||||
.medium-item .stats > *::after{
|
|
||||||
content: " | ";
|
|
||||||
}
|
|
||||||
.medium-item .stats > *:last-child::after{
|
|
||||||
content: "";
|
|
||||||
}
|
|
||||||
|
|
||||||
.medium-item .description{
|
|
||||||
grid-column: 2 / span 2;
|
|
||||||
grid-row: 4;
|
|
||||||
}
|
|
||||||
.medium-item .badges{
|
|
||||||
grid-column: 2 / span 2;
|
|
||||||
grid-row: 5;
|
|
||||||
}
|
|
||||||
/* thumbnail size */
|
|
||||||
.medium-item img{
|
|
||||||
/*height:138px;
|
|
||||||
width:246px;*/
|
|
||||||
height:100%;
|
|
||||||
justify-self:center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.small-item-box{
|
|
||||||
color: #767676;
|
|
||||||
font-size: 12px;
|
|
||||||
|
|
||||||
display:grid;
|
|
||||||
grid-template-columns: 1fr 30px;
|
|
||||||
grid-template-rows: 94px;
|
|
||||||
}
|
}
|
||||||
|
.item{
|
||||||
.small-item{
|
background-color:var(--interface-color);
|
||||||
background-color:#bcbcbc;
|
text-decoration:none;
|
||||||
align-content: start;
|
|
||||||
text-decoration:none;
|
|
||||||
|
|
||||||
display: grid;
|
|
||||||
grid-template-columns: 168px 1fr;
|
|
||||||
grid-column-gap: 5px;
|
|
||||||
grid-template-rows: auto auto auto 1fr;
|
|
||||||
}
|
|
||||||
.small-item .title{
|
|
||||||
grid-column:2;
|
|
||||||
grid-row:1;
|
|
||||||
margin:0;
|
|
||||||
|
|
||||||
color: #333;
|
|
||||||
font-size: 16px;
|
|
||||||
font-weight: 500;
|
|
||||||
text-decoration:initial;
|
|
||||||
min-width: 0;
|
|
||||||
justify-self:start;
|
|
||||||
|
|
||||||
overflow:hidden;
|
|
||||||
max-height: 3.3em;
|
|
||||||
line-height: 1.1em;
|
|
||||||
}
|
|
||||||
.small-item address{
|
|
||||||
grid-column: 2;
|
|
||||||
grid-row: 2;
|
|
||||||
justify-self: start;
|
|
||||||
}
|
|
||||||
|
|
||||||
.small-item .views{
|
|
||||||
grid-column: 2;
|
|
||||||
grid-row: 3;
|
|
||||||
justify-self:start;
|
|
||||||
}
|
|
||||||
/* thumbnail size */
|
|
||||||
.small-item img{
|
|
||||||
/*height:94px;
|
|
||||||
width:168px;*/
|
|
||||||
height:100%;
|
|
||||||
justify-self:center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.item-checkbox{
|
|
||||||
justify-self:start;
|
|
||||||
align-self:center;
|
|
||||||
height:30px;
|
|
||||||
width:30px;
|
|
||||||
|
|
||||||
grid-column: 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ---Thumbnails for videos---- */
|
|
||||||
.video-thumbnail-box{
|
|
||||||
max-height:100%;
|
|
||||||
|
|
||||||
grid-column:1;
|
|
||||||
grid-row:1 / span 6;
|
|
||||||
|
|
||||||
display:grid;
|
|
||||||
grid-template-columns: 1fr 0fr;
|
|
||||||
}
|
|
||||||
.video-thumbnail-img{
|
|
||||||
grid-column:1 / span 2;
|
|
||||||
grid-row:1;
|
|
||||||
}
|
|
||||||
.video-duration{
|
|
||||||
grid-column: 2;
|
|
||||||
grid-row: 1;
|
|
||||||
align-self: end;
|
|
||||||
opacity: .8;
|
|
||||||
color: #ffffff;
|
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
background-color: #000000;
|
color: #767676;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ---Thumbnails for playlists---- */
|
.horizontal-item-box .item {
|
||||||
.playlist-thumbnail-box{
|
flex-grow: 1;
|
||||||
max-height:100%;
|
|
||||||
|
|
||||||
grid-column:1;
|
|
||||||
grid-row:1 / span 6;
|
|
||||||
|
|
||||||
display:grid;
|
|
||||||
grid-template-columns: 3fr 2fr;
|
|
||||||
}
|
|
||||||
.playlist-thumbnail-img{
|
|
||||||
grid-column:1 / span 2;
|
|
||||||
grid-row:1;
|
|
||||||
}
|
|
||||||
.playlist-thumbnail-info{
|
|
||||||
grid-column:2;
|
|
||||||
grid-row:1;
|
|
||||||
|
|
||||||
display: grid;
|
display: grid;
|
||||||
align-items:center;
|
align-content: start;
|
||||||
|
grid-template-columns: auto 1fr;
|
||||||
text-align:center;
|
grid-template-rows: auto auto auto auto 1fr;
|
||||||
white-space: pre-line;
|
|
||||||
opacity: .8;
|
|
||||||
color: #cfcfcf;
|
|
||||||
background-color: #000000;
|
|
||||||
}
|
}
|
||||||
|
.vertical-item-box .item{
|
||||||
|
width: 168px;
|
||||||
|
}
|
||||||
|
.thumbnail-box{
|
||||||
|
font-size: 0px; /* prevent newlines and blank space from creating gaps */
|
||||||
|
position: relative;
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
.horizontal-item-box .thumbnail-box{
|
||||||
|
grid-row: 1 / span 5;
|
||||||
|
margin-right: 4px;
|
||||||
|
}
|
||||||
|
.no-description .thumbnail-box{
|
||||||
|
width: 168px;
|
||||||
|
height:94px;
|
||||||
|
}
|
||||||
|
.has-description .thumbnail-box{
|
||||||
|
width: 246px;
|
||||||
|
height:138px;
|
||||||
|
}
|
||||||
|
.video-item .thumbnail-info{
|
||||||
|
position: absolute;
|
||||||
|
bottom: 2px;
|
||||||
|
right: 2px;
|
||||||
|
opacity: .8;
|
||||||
|
color: #ffffff;
|
||||||
|
font-size: 12px;
|
||||||
|
background-color: #000000;
|
||||||
|
}
|
||||||
|
.playlist-item .thumbnail-info{
|
||||||
|
position: absolute;
|
||||||
|
right: 0px;
|
||||||
|
bottom: 0px;
|
||||||
|
height: 100%;
|
||||||
|
width: 50%;
|
||||||
|
text-align:center;
|
||||||
|
white-space: pre-line;
|
||||||
|
opacity: .8;
|
||||||
|
color: #cfcfcf;
|
||||||
|
font-size: 12px;
|
||||||
|
background-color: #000000;
|
||||||
|
}
|
||||||
|
.playlist-item .thumbnail-info span{ /* trick to vertically center the text */
|
||||||
|
position: absolute;
|
||||||
|
top: 50%;
|
||||||
|
transform: translate(-50%, -50%);
|
||||||
|
}
|
||||||
|
.thumbnail-img{ /* center it */
|
||||||
|
margin: auto;
|
||||||
|
display: block;
|
||||||
|
max-height: 100%;
|
||||||
|
}
|
||||||
|
.horizontal-item-box .thumbnail-img{
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.item .title{
|
||||||
|
min-width: 0;
|
||||||
|
max-height:3.6em;
|
||||||
|
overflow:hidden;
|
||||||
|
|
||||||
|
color: var(--text-color);
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: 500;
|
||||||
|
text-decoration:initial;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stats{
|
||||||
|
list-style: none;
|
||||||
|
padding: 0px;
|
||||||
|
margin: 0px;
|
||||||
|
}
|
||||||
|
.horizontal-stats{
|
||||||
|
max-height:2.4em;
|
||||||
|
overflow:hidden;
|
||||||
|
}
|
||||||
|
.horizontal-stats > li{
|
||||||
|
display: inline;
|
||||||
|
}
|
||||||
|
|
||||||
|
.horizontal-stats > li::after{
|
||||||
|
content: " | ";
|
||||||
|
}
|
||||||
|
.horizontal-stats > li:last-child::after{
|
||||||
|
content: "";
|
||||||
|
}
|
||||||
|
|
||||||
|
.vertical-stats{
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
.stats address{
|
||||||
|
display: inline;
|
||||||
|
}
|
||||||
|
.vertical-stats li{
|
||||||
|
max-height: 1.3em;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.item-checkbox{
|
||||||
|
justify-self:start;
|
||||||
|
align-self:center;
|
||||||
|
height:30px;
|
||||||
|
width:30px;
|
||||||
|
min-width:30px;
|
||||||
|
margin: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
.page-button-row{
|
.page-button-row{
|
||||||
|
margin-top: 10px;
|
||||||
|
margin-bottom: 10px;
|
||||||
justify-self:center;
|
justify-self:center;
|
||||||
|
justify-content: center;
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-auto-columns: 40px;
|
grid-auto-columns: 40px;
|
||||||
grid-auto-flow: column;
|
grid-auto-flow: column;
|
||||||
height: 40px;
|
height: 40px;
|
||||||
}
|
}
|
||||||
.page-button{
|
.page-button{
|
||||||
background-color: #e9e9e9;
|
background-color: var(--interface-color);
|
||||||
border-style: outset;
|
border-style: outset;
|
||||||
border-width: 2px;
|
border-width: 2px;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
.sort-button{
|
.sort-button{
|
||||||
background-color: #d0d0d0;
|
background-color: var(--interface-color);
|
||||||
padding: 2px;
|
padding: 2px;
|
||||||
justify-self: start;
|
justify-self: start;
|
||||||
}
|
}
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<title>{{ page_title }}</title>
|
<title>{{ page_title }}</title>
|
||||||
<meta http-equiv="Content-Security-Policy" content="default-src 'self' 'unsafe-inline'; script-src 'none'; media-src 'self' https://*.googlevideo.com">
|
<meta http-equiv="Content-Security-Policy" content="default-src 'self' 'unsafe-inline'; script-src 'none'; media-src 'self' https://*.googlevideo.com">
|
||||||
|
<link href="{{ theme_path }}" type="text/css" rel="stylesheet">
|
||||||
<link href="/youtube.com/static/shared.css" type="text/css" rel="stylesheet">
|
<link href="/youtube.com/static/shared.css" type="text/css" rel="stylesheet">
|
||||||
<link href="/youtube.com/static/comments.css" type="text/css" rel="stylesheet">
|
<link href="/youtube.com/static/comments.css" type="text/css" rel="stylesheet">
|
||||||
<link href="/youtube.com/static/favicon.ico" type="image/x-icon" rel="icon">
|
<link href="/youtube.com/static/favicon.ico" type="image/x-icon" rel="icon">
|
||||||
@ -16,6 +17,7 @@
|
|||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<header>
|
<header>
|
||||||
|
<a href="/youtube.com" id="home-link">Home</a>
|
||||||
<form id="site-search" action="/youtube.com/search">
|
<form id="site-search" action="/youtube.com/search">
|
||||||
<input type="search" name="query" class="search-box" value="{{ search_box_value }}">
|
<input type="search" name="query" class="search-box" value="{{ search_box_value }}">
|
||||||
<button type="submit" value="Search" class="search-button">Search</button>
|
<button type="submit" value="Search" class="search-button">Search</button>
|
||||||
@ -91,19 +93,16 @@
|
|||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
<div id="header-right">
|
<form id="playlist-edit" action="/youtube.com/edit_playlist" method="post" target="_self">
|
||||||
<form id="playlist-edit" action="/youtube.com/edit_playlist" method="post" target="_self">
|
<input name="playlist_name" id="playlist-name-selection" list="playlist-options" type="text">
|
||||||
<input name="playlist_name" id="playlist-name-selection" list="playlist-options" type="text">
|
<datalist id="playlist-options">
|
||||||
<datalist id="playlist-options">
|
{% for playlist_name in header_playlist_names %}
|
||||||
{% for playlist_name in header_playlist_names %}
|
<option value="{{ playlist_name }}">{{ playlist_name }}</option>
|
||||||
<option value="{{ playlist_name }}">{{ playlist_name }}</option>
|
{% endfor %}
|
||||||
{% endfor %}
|
</datalist>
|
||||||
</datalist>
|
<button type="submit" id="playlist-add-button" name="action" value="add">Add to playlist</button>
|
||||||
<button type="submit" id="playlist-add-button" name="action" value="add">Add to playlist</button>
|
<button type="reset" id="item-selection-reset">Clear selection</button>
|
||||||
<button type="reset" id="item-selection-reset">Clear selection</button>
|
</form>
|
||||||
</form>
|
|
||||||
<a href="/youtube.com/playlists" id="local-playlists">Local playlists</a>
|
|
||||||
</div>
|
|
||||||
</header>
|
</header>
|
||||||
<main>
|
<main>
|
||||||
{% block main %}
|
{% block main %}
|
||||||
|
@ -31,7 +31,7 @@
|
|||||||
grid-auto-flow: column;
|
grid-auto-flow: column;
|
||||||
justify-content:start;
|
justify-content:start;
|
||||||
|
|
||||||
background-color: #aaaaaa;
|
background-color: var(--interface-color);
|
||||||
padding: 3px;
|
padding: 3px;
|
||||||
padding-left: 6px;
|
padding-left: 6px;
|
||||||
}
|
}
|
||||||
@ -44,7 +44,6 @@
|
|||||||
padding-top: 8px;
|
padding-top: 8px;
|
||||||
padding-bottom: 8px;
|
padding-bottom: 8px;
|
||||||
padding-left: 6px;
|
padding-left: 6px;
|
||||||
background-color: #bababa;
|
|
||||||
margin-bottom: 10px;
|
margin-bottom: 10px;
|
||||||
}
|
}
|
||||||
#number-of-results{
|
#number-of-results{
|
||||||
|
@ -29,21 +29,19 @@
|
|||||||
{% endmacro %}
|
{% endmacro %}
|
||||||
|
|
||||||
{% macro video_comments(comments_info) %}
|
{% macro video_comments(comments_info) %}
|
||||||
<section class="comments-area">
|
<div class="comment-links">
|
||||||
<div class="comment-links">
|
{% for link_text, link_url in comments_info['comment_links'] %}
|
||||||
{% for link_text, link_url in comments_info['comment_links'] %}
|
<a class="sort-button" href="{{ link_url }}">{{ link_text }}</a>
|
||||||
<a class="sort-button" href="{{ link_url }}">{{ link_text }}</a>
|
{% endfor %}
|
||||||
{% endfor %}
|
</div>
|
||||||
</div>
|
<div class="comments">
|
||||||
<div class="comments">
|
{% for comment in comments_info['comments'] %}
|
||||||
{% for comment in comments_info['comments'] %}
|
{{ render_comment(comment, comments_info['include_avatars']) }}
|
||||||
{{ render_comment(comment, comments_info['include_avatars']) }}
|
{% endfor %}
|
||||||
{% endfor %}
|
</div>
|
||||||
</div>
|
{% if 'more_comments_url' is in comments_info %}
|
||||||
{% if 'more_comments_url' is in comments_info %}
|
<a class="page-button more-comments" href="{{ comments_info['more_comments_url'] }}">More comments</a>
|
||||||
<a class="page-button more-comments" href="{{ comments_info['more_comments_url'] }}">More comments</a>
|
{% endif %}
|
||||||
{% endif %}
|
|
||||||
</section>
|
|
||||||
{% endmacro %}
|
{% endmacro %}
|
||||||
|
|
||||||
{% macro comment_posting_box(info) %}
|
{% macro comment_posting_box(info) %}
|
||||||
|
@ -3,63 +3,46 @@
|
|||||||
{% import "comments.html" as comments %}
|
{% import "comments.html" as comments %}
|
||||||
|
|
||||||
{% block style %}
|
{% block style %}
|
||||||
main{
|
.comments-area{
|
||||||
display:grid;
|
margin: auto;
|
||||||
grid-template-columns: 3fr 2fr;
|
width:640px;
|
||||||
}
|
}
|
||||||
#left{
|
|
||||||
background-color:#bcbcbc;
|
|
||||||
|
|
||||||
display: grid;
|
|
||||||
grid-column: 1;
|
|
||||||
grid-row: 1;
|
|
||||||
grid-template-columns: 1fr 640px;
|
|
||||||
grid-template-rows: 0fr 0fr 0fr;
|
|
||||||
}
|
|
||||||
.comments-area{
|
|
||||||
grid-column:2;
|
|
||||||
}
|
|
||||||
.comment{
|
|
||||||
width:640px;
|
|
||||||
}
|
|
||||||
{% endblock style %}
|
{% endblock style %}
|
||||||
|
|
||||||
|
|
||||||
{% block main %}
|
{% block main %}
|
||||||
<div id="left">
|
<section class="comments-area">
|
||||||
<section class="comments-area">
|
{% if not comments_info['is_replies'] %}
|
||||||
{% if not comments_info['is_replies'] %}
|
<section class="video-metadata">
|
||||||
<section class="video-metadata">
|
<a class="video-metadata-thumbnail-box" href="{{ comments_info['video_url'] }}" title="{{ comments_info['video_title'] }}">
|
||||||
<a class="video-metadata-thumbnail-box" href="{{ comments_info['video_url'] }}" title="{{ comments_info['video_title'] }}">
|
<img class="video-metadata-thumbnail-img" src="{{ comments_info['video_thumbnail'] }}" height="180px" width="320px">
|
||||||
<img class="video-metadata-thumbnail-img" src="{{ comments_info['video_thumbnail'] }}" height="180px" width="320px">
|
</a>
|
||||||
</a>
|
<a class="title" href="{{ comments_info['video_url'] }}" title="{{ comments_info['video_title'] }}">{{ comments_info['video_title'] }}</a>
|
||||||
<a class="title" href="{{ comments_info['video_url'] }}" title="{{ comments_info['video_title'] }}">{{ comments_info['video_title'] }}</a>
|
|
||||||
|
|
||||||
<h2>Comments page {{ comments_info['page_number'] }}</h2>
|
<h2>Comments page {{ comments_info['page_number'] }}</h2>
|
||||||
<span>Sorted by {{ comments_info['sort_text'] }}</span>
|
<span>Sorted by {{ comments_info['sort_text'] }}</span>
|
||||||
</section>
|
</section>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
{{ comments.comment_posting_box(comment_posting_box_info) }}
|
{{ comments.comment_posting_box(comment_posting_box_info) }}
|
||||||
|
|
||||||
{% if not comments_info['is_replies'] %}
|
{% if not comments_info['is_replies'] %}
|
||||||
<div class="comment-links">
|
<div class="comment-links">
|
||||||
{% for link_text, link_url in comments_info['comment_links'] %}
|
{% for link_text, link_url in comments_info['comment_links'] %}
|
||||||
<a class="sort-button" href="{{ link_url }}">{{ link_text }}</a>
|
<a class="sort-button" href="{{ link_url }}">{{ link_text }}</a>
|
||||||
{% endfor %}
|
|
||||||
</div>
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
<div class="comments">
|
|
||||||
{% for comment in comments_info['comments'] %}
|
|
||||||
{{ comments.render_comment(comment, comments_info['include_avatars']) }}
|
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</div>
|
</div>
|
||||||
{% if 'more_comments_url' is in comments_info %}
|
{% endif %}
|
||||||
<a class="page-button more-comments" href="{{ comments_info['more_comments_url'] }}">More comments</a>
|
|
||||||
{% endif %}
|
<div class="comments">
|
||||||
</section>
|
{% for comment in comments_info['comments'] %}
|
||||||
</div>
|
{{ comments.render_comment(comment, comments_info['include_avatars']) }}
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
{% if 'more_comments_url' is in comments_info %}
|
||||||
|
<a class="page-button more-comments" href="{{ comments_info['more_comments_url'] }}">More comments</a>
|
||||||
|
{% endif %}
|
||||||
|
</section>
|
||||||
{% endblock main %}
|
{% endblock main %}
|
||||||
|
|
||||||
|
|
||||||
|
@ -14,121 +14,53 @@
|
|||||||
{%- endif -%}
|
{%- endif -%}
|
||||||
{% endmacro %}
|
{% endmacro %}
|
||||||
|
|
||||||
{% macro small_item(info, include_author=true) %}
|
{% macro item(info, description=false, horizontal=true, include_author=true) %}
|
||||||
<div class="small-item-box">
|
<div class="item-box {{ info['type'] + '-item-box' }} {{'horizontal-item-box' if horizontal else 'vertical-item-box'}} {{'has-description' if description else 'no-description'}}">
|
||||||
<div class="small-item">
|
<div class="item {{ info['type'] + '-item' }}">
|
||||||
{% if info['type'] == 'video' %}
|
<a class="thumbnail-box" href="{{ info['url'] }}" title="{{ info['title'] }}">
|
||||||
<a class="video-thumbnail-box" href="{{ info['url'] }}" title="{{ info['title'] }}">
|
<img class="thumbnail-img" src="{{ info['thumbnail'] }}">
|
||||||
<img class="video-thumbnail-img" src="{{ info['thumbnail'] }}">
|
{% if info['type'] != 'channel' %}
|
||||||
<span class="video-duration">{{ info['duration'] }}</span>
|
<div class="thumbnail-info">
|
||||||
</a>
|
<span>{{ info['size'] if info['type'] == 'playlist' else info['duration'] }}</span>
|
||||||
<a class="title" href="{{ info['url'] }}" title="{{ info['title'] }}">{{ info['title'] }}</a>
|
|
||||||
|
|
||||||
<address>{{ info['author'] }}</address>
|
|
||||||
<span class="views">{{ info['views'] }}</span>
|
|
||||||
|
|
||||||
{% elif info['type'] == 'playlist' %}
|
|
||||||
<a class="playlist-thumbnail-box" href="{{ info['url'] }}" title="{{ info['title'] }}">
|
|
||||||
<img class="playlist-thumbnail-img" src="{{ info['thumbnail'] }}">
|
|
||||||
<div class="playlist-thumbnail-info">
|
|
||||||
<span>{{ info['size'] }}</span>
|
|
||||||
</div>
|
</div>
|
||||||
</a>
|
{% endif %}
|
||||||
<a class="title" href="{{ info['url'] }}" title="{{ info['title'] }}">{{ info['title'] }}</a>
|
</a>
|
||||||
|
|
||||||
<address>{{ info['author'] }}</address>
|
<div class="title"><a class="title" href="{{ info['url'] }}" title="{{ info['title'] }}">{{ info['title'] }}</a></div>
|
||||||
{% else %}
|
|
||||||
Error: unsupported item type
|
<ul class="stats {{'vertical-stats' if horizontal and not description and include_author else 'horizontal-stats'}}">
|
||||||
|
{% if info['type'] == 'channel' %}
|
||||||
|
<li><span>{{ info['subscriber_count'] }} subscribers</span></li>
|
||||||
|
<li><span>{{ info['size'] }} videos</span></li>
|
||||||
|
{% else %}
|
||||||
|
{% if include_author %}
|
||||||
|
{% if 'author_url' is in(info) %}
|
||||||
|
<li><address title="{{ info['author'] }}">By <a href="{{ info['author_url'] }}">{{ info['author'] }}</a></address></li>
|
||||||
|
{% else %}
|
||||||
|
<li><address title="{{ info['author'] }}"><b>{{ info['author'] }}</b></address></li>
|
||||||
|
{% endif %}
|
||||||
|
{% endif %}
|
||||||
|
{% if 'views' is in(info) %}
|
||||||
|
<li><span class="views">{{ info['views'] }}</span></li>
|
||||||
|
{% endif %}
|
||||||
|
{% if 'published' is in(info) %}
|
||||||
|
<li><time>{{ info['published'] }}</time></li>
|
||||||
|
{% endif %}
|
||||||
|
{% endif %}
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
{% if description %}
|
||||||
|
<span class="description">{{ text_runs(info.get('description', '')) }}</span>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
<span class="badges">{{ info['badges']|join(' | ') }}</span>
|
||||||
</div>
|
</div>
|
||||||
{% if info['type'] == 'video' %}
|
{% if info['type'] == 'video' %}
|
||||||
<input class="item-checkbox" type="checkbox" name="video_info_list" value="{{ info['video_info'] }}" form="playlist-edit">
|
<input class="item-checkbox" type="checkbox" name="video_info_list" value="{{ info['video_info'] }}" form="playlist-edit">
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{% endmacro %}
|
{% endmacro %}
|
||||||
|
|
||||||
{% macro get_stats(info, include_author=true) %}
|
|
||||||
{% if include_author %}
|
|
||||||
{% if 'author_url' is in(info) %}
|
|
||||||
<address>By <a href="{{ info['author_url'] }}">{{ info['author'] }}</a></address>
|
|
||||||
{% else %}
|
|
||||||
<address><b>{{ info['author'] }}</b></address>
|
|
||||||
{% endif %}
|
|
||||||
{% endif %}
|
|
||||||
{% if 'views' is in(info) %}
|
|
||||||
<span class="views">{{ info['views'] }}</span>
|
|
||||||
{% endif %}
|
|
||||||
{% if 'published' is in(info) %}
|
|
||||||
<time>{{ info['published'] }}</time>
|
|
||||||
{% endif %}
|
|
||||||
{% endmacro %}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
{% macro medium_item(info, include_author=true) %}
|
|
||||||
<div class="medium-item-box">
|
|
||||||
<div class="medium-item">
|
|
||||||
{% if info['type'] == 'video' %}
|
|
||||||
<a class="video-thumbnail-box" href="{{ info['url'] }}" title="{{ info['title'] }}">
|
|
||||||
<img class="video-thumbnail-img" src="{{ info['thumbnail'] }}">
|
|
||||||
<span class="video-duration">{{ info['duration'] }}</span>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<a class="title" href="{{ info['url'] }}" title="{{ info['title'] }}">{{ info['title'] }}</a>
|
|
||||||
|
|
||||||
<div class="stats">
|
|
||||||
{{ get_stats(info, include_author) }}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<span class="description">{{ text_runs(info.get('description', '')) }}</span>
|
|
||||||
<span class="badges">{{ info['badges']|join(' | ') }}</span>
|
|
||||||
{% elif info['type'] == 'playlist' %}
|
|
||||||
<a class="playlist-thumbnail-box" href="{{ info['url'] }}" title="{{ info['title'] }}">
|
|
||||||
<img class="playlist-thumbnail-img" src="{{ info['thumbnail'] }}">
|
|
||||||
<div class="playlist-thumbnail-info">
|
|
||||||
<span>{{ info['size'] }}</span>
|
|
||||||
</div>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<a class="title" href="{{ info['url'] }}" title="{{ info['title'] }}">{{ info['title'] }}</a>
|
|
||||||
|
|
||||||
<div class="stats">
|
|
||||||
{{ get_stats(info, include_author) }}
|
|
||||||
</div>
|
|
||||||
{% elif info['type'] == 'channel' %}
|
|
||||||
<a class="video-thumbnail-box" href="{{ info['url'] }}" title="{{ info['title'] }}">
|
|
||||||
<img class="video-thumbnail-img" src="{{ info['thumbnail'] }}">
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<a class="title" href="{{ info['url'] }}">{{ info['title'] }}</a>
|
|
||||||
|
|
||||||
<span>{{ info['subscriber_count'] }} subscribers</span>
|
|
||||||
<span>{{ info['size'] }} videos</span>
|
|
||||||
|
|
||||||
<span class="description">{{ text_runs(info.get('description', '')) }}</span>
|
|
||||||
{% else %}
|
|
||||||
Error: unsupported item type
|
|
||||||
{% endif %}
|
|
||||||
</div>
|
|
||||||
{% if info['type'] == 'video' %}
|
|
||||||
<input class="item-checkbox" type="checkbox" name="video_info_list" value="{{ info['video_info'] }}" form="playlist-edit">
|
|
||||||
{% endif %}
|
|
||||||
</div>
|
|
||||||
{% endmacro %}
|
|
||||||
|
|
||||||
|
|
||||||
{% macro item(info, include_author=true) %}
|
|
||||||
{% if info['item_size'] == 'small' %}
|
|
||||||
{{ small_item(info, include_author) }}
|
|
||||||
{% elif info['item_size'] == 'medium' %}
|
|
||||||
{{ medium_item(info, include_author) }}
|
|
||||||
{% else %}
|
|
||||||
Error: Unknown item size
|
|
||||||
{% endif %}
|
|
||||||
{% endmacro %}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
{% macro page_buttons(estimated_pages, url, parameters_dictionary) %}
|
{% macro page_buttons(estimated_pages, url, parameters_dictionary) %}
|
||||||
{% set current_page = parameters_dictionary.get('page', 1)|int %}
|
{% set current_page = parameters_dictionary.get('page', 1)|int %}
|
||||||
{% set parameters_dictionary = parameters_dictionary.to_dict() %}
|
{% set parameters_dictionary = parameters_dictionary.to_dict() %}
|
||||||
|
@ -2,14 +2,10 @@
|
|||||||
{% extends "base.html" %}
|
{% extends "base.html" %}
|
||||||
|
|
||||||
{% block style %}
|
{% block style %}
|
||||||
main{
|
|
||||||
display: grid;
|
|
||||||
grid-template-columns: minmax(0px, 3fr) 640px 40px 500px minmax(0px,2fr);
|
|
||||||
align-content: start;
|
|
||||||
}
|
|
||||||
main > div, main > form{
|
main > div, main > form{
|
||||||
|
margin: auto;
|
||||||
margin-top:20px;
|
margin-top:20px;
|
||||||
grid-column:2;
|
width: 640px;
|
||||||
}
|
}
|
||||||
{% endblock style %}
|
{% endblock style %}
|
||||||
|
|
||||||
|
22
youtube/templates/home.html
Normal file
22
youtube/templates/home.html
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
{% set page_title = title %}
|
||||||
|
{% extends "base.html" %}
|
||||||
|
{% block style %}
|
||||||
|
ul {
|
||||||
|
background-color: var(--interface-color);
|
||||||
|
padding: 20px;
|
||||||
|
width: 400px;
|
||||||
|
margin: auto;
|
||||||
|
margin-top: 20px;
|
||||||
|
}
|
||||||
|
li {
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
{% endblock style %}
|
||||||
|
{% block main %}
|
||||||
|
<ul>
|
||||||
|
<li><a href="/youtube.com/playlists">Local playlists</a></li>
|
||||||
|
<li><a href="/youtube.com/subscriptions">Subscriptions</a></li>
|
||||||
|
<li><a href="/youtube.com/subscription_manager">Subscription Manager</a></li>
|
||||||
|
<li><a href="/youtube.com/settings">Settings</a></li>
|
||||||
|
</ul>
|
||||||
|
{% endblock main %}
|
@ -2,59 +2,41 @@
|
|||||||
{% extends "base.html" %}
|
{% extends "base.html" %}
|
||||||
{% import "common_elements.html" as common_elements %}
|
{% import "common_elements.html" as common_elements %}
|
||||||
{% block style %}
|
{% block style %}
|
||||||
main{
|
main > *{
|
||||||
display:grid;
|
width: 800px;
|
||||||
grid-template-columns: 3fr 1fr;
|
margin: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.playlist-metadata{
|
||||||
|
display: flex;
|
||||||
#left{
|
flex-direction: row;
|
||||||
grid-column: 1;
|
justify-content: space-between;
|
||||||
grid-row: 1;
|
|
||||||
|
|
||||||
display: grid;
|
|
||||||
grid-template-columns: 1fr 800px auto;
|
|
||||||
grid-template-rows: 0fr 1fr 0fr;
|
|
||||||
}
|
}
|
||||||
.playlist-title{
|
.playlist-title{
|
||||||
grid-column:2;
|
|
||||||
}
|
}
|
||||||
#playlist-remove-button{
|
#playlist-remove-button{
|
||||||
grid-column:3;
|
|
||||||
align-self: center;
|
align-self: center;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
}
|
}
|
||||||
#results{
|
#results{
|
||||||
|
|
||||||
grid-row: 2;
|
|
||||||
grid-column: 2 / span 2;
|
|
||||||
|
|
||||||
|
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-auto-rows: 0fr;
|
grid-auto-rows: 0fr;
|
||||||
grid-row-gap: 10px;
|
grid-row-gap: 10px;
|
||||||
|
|
||||||
}
|
|
||||||
.page-button-row{
|
|
||||||
grid-row: 3;
|
|
||||||
grid-column: 2;
|
|
||||||
justify-self: center;
|
|
||||||
}
|
}
|
||||||
{% endblock style %}
|
{% endblock style %}
|
||||||
|
|
||||||
{% block main %}
|
{% block main %}
|
||||||
<div id="left">
|
<div class="playlist-metadata">
|
||||||
<h2 class="playlist-title">{{ playlist_name }}</h2>
|
<h2 class="playlist-title">{{ playlist_name }}</h2>
|
||||||
<input type="hidden" name="playlist_page" value="{{ playlist_name }}" form="playlist-edit">
|
<input type="hidden" name="playlist_page" value="{{ playlist_name }}" form="playlist-edit">
|
||||||
<button type="submit" id="playlist-remove-button" name="action" value="remove" form="playlist-edit" formaction="">Remove from playlist</button>
|
<button type="submit" id="playlist-remove-button" name="action" value="remove" form="playlist-edit" formaction="">Remove from playlist</button>
|
||||||
<div id="results">
|
|
||||||
{% for video_info in videos %}
|
|
||||||
{{ common_elements.item(video_info) }}
|
|
||||||
{% endfor %}
|
|
||||||
</div>
|
|
||||||
<nav class="page-button-row">
|
|
||||||
{{ common_elements.page_buttons(num_pages, '/https://www.youtube.com/playlists/' + playlist_name, parameters_dictionary) }}
|
|
||||||
</nav>
|
|
||||||
</div>
|
</div>
|
||||||
|
<div id="results">
|
||||||
|
{% for video_info in videos %}
|
||||||
|
{{ common_elements.item(video_info) }}
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
<nav class="page-button-row">
|
||||||
|
{{ common_elements.page_buttons(num_pages, '/https://www.youtube.com/playlists/' + playlist_name, parameters_dictionary) }}
|
||||||
|
</nav>
|
||||||
{% endblock main %}
|
{% endblock main %}
|
||||||
|
@ -2,16 +2,14 @@
|
|||||||
{% extends "base.html" %}
|
{% extends "base.html" %}
|
||||||
|
|
||||||
{% block style %}
|
{% block style %}
|
||||||
main{
|
main > * {
|
||||||
display: grid;
|
width: 640px;
|
||||||
grid-template-columns: minmax(0px, 3fr) 640px 40px 500px minmax(0px,2fr);
|
margin: auto;
|
||||||
align-content: start;
|
|
||||||
grid-row-gap: 40px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
main form{
|
main form{
|
||||||
|
background-color: var(--interface-color);
|
||||||
|
padding: 10px;
|
||||||
margin-top:20px;
|
margin-top:20px;
|
||||||
grid-column:2;
|
|
||||||
display:grid;
|
display:grid;
|
||||||
justify-items: start;
|
justify-items: start;
|
||||||
align-content: start;
|
align-content: start;
|
||||||
@ -26,10 +24,9 @@
|
|||||||
margin-top:20px;
|
margin-top:20px;
|
||||||
}
|
}
|
||||||
#tor-note{
|
#tor-note{
|
||||||
grid-row:2;
|
background-color: var(--interface-color);
|
||||||
grid-column:2;
|
|
||||||
background-color: #dddddd;
|
|
||||||
padding: 10px;
|
padding: 10px;
|
||||||
|
margin-top: 40px;
|
||||||
}
|
}
|
||||||
{% endblock style %}
|
{% endblock style %}
|
||||||
|
|
||||||
|
@ -2,70 +2,43 @@
|
|||||||
{% extends "base.html" %}
|
{% extends "base.html" %}
|
||||||
{% import "common_elements.html" as common_elements %}
|
{% import "common_elements.html" as common_elements %}
|
||||||
{% block style %}
|
{% block style %}
|
||||||
main{
|
main > * {
|
||||||
|
width: 800px;
|
||||||
|
margin:auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.playlist-metadata{
|
||||||
display:grid;
|
display:grid;
|
||||||
grid-template-columns: 3fr 1fr;
|
grid-template-columns: 0fr 1fr;
|
||||||
}
|
}
|
||||||
|
.playlist-thumbnail{
|
||||||
|
grid-row: 1 / span 5;
|
||||||
|
grid-column:1;
|
||||||
#left{
|
justify-self:start;
|
||||||
grid-column: 1;
|
width:250px;
|
||||||
grid-row: 1;
|
margin-right: 10px;
|
||||||
|
}
|
||||||
display: grid;
|
.playlist-title{
|
||||||
grid-template-columns: 1fr 800px;
|
grid-row: 1;
|
||||||
grid-template-rows: 0fr 1fr 0fr;
|
|
||||||
}
|
|
||||||
.playlist-metadata{
|
|
||||||
grid-column:2;
|
grid-column:2;
|
||||||
grid-row:1;
|
|
||||||
|
|
||||||
display:grid;
|
|
||||||
grid-template-columns: 0fr 1fr;
|
|
||||||
}
|
}
|
||||||
.playlist-thumbnail{
|
.playlist-author{
|
||||||
grid-row: 1 / span 5;
|
grid-row:2;
|
||||||
grid-column:1;
|
grid-column:2;
|
||||||
justify-self:start;
|
}
|
||||||
width:250px;
|
.playlist-stats{
|
||||||
margin-right: 10px;
|
grid-row:3;
|
||||||
}
|
grid-column:2;
|
||||||
.playlist-title{
|
|
||||||
grid-row: 1;
|
|
||||||
grid-column:2;
|
|
||||||
}
|
|
||||||
.playlist-author{
|
|
||||||
grid-row:2;
|
|
||||||
grid-column:2;
|
|
||||||
}
|
|
||||||
.playlist-stats{
|
|
||||||
grid-row:3;
|
|
||||||
grid-column:2;
|
|
||||||
}
|
|
||||||
|
|
||||||
.playlist-description{
|
|
||||||
grid-row:4;
|
|
||||||
grid-column:2;
|
|
||||||
min-width:0px;
|
|
||||||
white-space: pre-line;
|
|
||||||
}
|
|
||||||
.page-button-row{
|
|
||||||
grid-row: 3;
|
|
||||||
grid-column: 2;
|
|
||||||
justify-self: center;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.playlist-description{
|
||||||
|
grid-row:4;
|
||||||
|
grid-column:2;
|
||||||
|
min-width:0px;
|
||||||
|
white-space: pre-line;
|
||||||
|
}
|
||||||
|
|
||||||
#right{
|
|
||||||
grid-column: 2;
|
|
||||||
grid-row: 1;
|
|
||||||
|
|
||||||
}
|
|
||||||
#results{
|
#results{
|
||||||
|
|
||||||
grid-row: 2;
|
|
||||||
grid-column: 2;
|
|
||||||
margin-top:10px;
|
margin-top:10px;
|
||||||
|
|
||||||
display: grid;
|
display: grid;
|
||||||
@ -76,27 +49,25 @@
|
|||||||
{% endblock style %}
|
{% endblock style %}
|
||||||
|
|
||||||
{% block main %}
|
{% block main %}
|
||||||
<div id="left">
|
<div class="playlist-metadata">
|
||||||
<div class="playlist-metadata">
|
<img class="playlist-thumbnail" src="{{ thumbnail }}">
|
||||||
<img class="playlist-thumbnail" src="{{ thumbnail }}">
|
<h2 class="playlist-title">{{ title }}</h2>
|
||||||
<h2 class="playlist-title">{{ title }}</h2>
|
<a class="playlist-author" href="{{ author_url }}">{{ author }}</a>
|
||||||
<a class="playlist-author" href="{{ author_url }}">{{ author }}</a>
|
<div class="playlist-stats">
|
||||||
<div class="playlist-stats">
|
<div>{{ views }}</div>
|
||||||
<div>{{ views }}</div>
|
<div>{{ size }}</div>
|
||||||
<div>{{ size }}</div>
|
|
||||||
</div>
|
|
||||||
<div class="playlist-description">{{ common_elements.text_runs(description) }}</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
<div class="playlist-description">{{ common_elements.text_runs(description) }}</div>
|
||||||
<div id="results">
|
|
||||||
{% for info in video_list %}
|
|
||||||
{{ common_elements.item(info) }}
|
|
||||||
{% endfor %}
|
|
||||||
</div>
|
|
||||||
<nav class="page-button-row">
|
|
||||||
{{ common_elements.page_buttons(num_pages, '/https://www.youtube.com/playlist', parameters_dictionary) }}
|
|
||||||
</nav>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div id="results">
|
||||||
|
{% for info in video_list %}
|
||||||
|
{{ common_elements.item(info) }}
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
<nav class="page-button-row">
|
||||||
|
{{ common_elements.page_buttons(num_pages, '/https://www.youtube.com/playlist', parameters_dictionary) }}
|
||||||
|
</nav>
|
||||||
{% endblock main %}
|
{% endblock main %}
|
||||||
|
|
||||||
|
|
||||||
|
@ -3,27 +3,18 @@
|
|||||||
{% import "comments.html" as comments %}
|
{% import "comments.html" as comments %}
|
||||||
|
|
||||||
{% block style %}
|
{% block style %}
|
||||||
main{
|
|
||||||
display: grid;
|
|
||||||
grid-template-columns: 3fr 2fr;
|
|
||||||
}
|
|
||||||
.left{
|
|
||||||
display:grid;
|
|
||||||
grid-template-columns: 1fr 640px;
|
|
||||||
}
|
|
||||||
textarea{
|
|
||||||
width: 460px;
|
|
||||||
height: 85px;
|
|
||||||
}
|
|
||||||
.comment-form{
|
.comment-form{
|
||||||
grid-column:2;
|
width: 640px;
|
||||||
|
margin: auto;
|
||||||
justify-content:start;
|
justify-content:start;
|
||||||
}
|
}
|
||||||
|
textarea{
|
||||||
|
width: 460px;
|
||||||
|
height: 85px;
|
||||||
|
}
|
||||||
{% endblock style %}
|
{% endblock style %}
|
||||||
|
|
||||||
{% block main %}
|
{% block main %}
|
||||||
<div class="left">
|
{{ comments.comment_posting_box(comment_posting_box_info) }}
|
||||||
{{ comments.comment_posting_box(comment_posting_box_info) }}
|
|
||||||
</div>
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
|
@ -3,31 +3,19 @@
|
|||||||
{% extends "base.html" %}
|
{% extends "base.html" %}
|
||||||
{% import "common_elements.html" as common_elements %}
|
{% import "common_elements.html" as common_elements %}
|
||||||
{% block style %}
|
{% block style %}
|
||||||
main{
|
main > * {
|
||||||
display:grid;
|
max-width: 800px;
|
||||||
grid-template-columns: minmax(0px, 1fr) 800px minmax(0px,2fr);
|
margin: auto;
|
||||||
max-width:100vw;
|
}
|
||||||
}
|
#result-info{
|
||||||
|
}
|
||||||
|
|
||||||
#number-of-results{
|
#number-of-results{
|
||||||
font-weight:bold;
|
font-weight:bold;
|
||||||
}
|
}
|
||||||
#result-info{
|
.item-list{
|
||||||
grid-row: 1;
|
padding-left: 10px;
|
||||||
grid-column:2;
|
padding-right: 10px;
|
||||||
align-self:center;
|
}
|
||||||
}
|
|
||||||
.page-button-row{
|
|
||||||
grid-column: 2;
|
|
||||||
justify-self: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
.item-list{
|
|
||||||
grid-row: 2;
|
|
||||||
grid-column: 2;
|
|
||||||
}
|
|
||||||
.badge{
|
.badge{
|
||||||
background-color:#cccccc;
|
background-color:#cccccc;
|
||||||
}
|
}
|
||||||
@ -45,7 +33,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="item-list">
|
<div class="item-list">
|
||||||
{% for info in results %}
|
{% for info in results %}
|
||||||
{{ common_elements.item(info) }}
|
{{ common_elements.item(info, description=true) }}
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</div>
|
</div>
|
||||||
<nav class="page-button-row">
|
<nav class="page-button-row">
|
||||||
|
@ -3,96 +3,116 @@
|
|||||||
{% import "common_elements.html" as common_elements %}
|
{% import "common_elements.html" as common_elements %}
|
||||||
{% import "comments.html" as comments %}
|
{% import "comments.html" as comments %}
|
||||||
{% block style %}
|
{% block style %}
|
||||||
main{
|
details > summary{
|
||||||
display:grid;
|
background-color: var(--interface-color);
|
||||||
grid-template-columns: minmax(0px, 3fr) 640px 40px 500px minmax(0px,2fr);
|
border-style: outset;
|
||||||
background-color:#cccccc;
|
border-width: 2px;
|
||||||
}
|
font-weight: bold;
|
||||||
|
padding-bottom: 2px;
|
||||||
|
}
|
||||||
|
details > summary:hover{
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
|
||||||
#left{
|
{% if theater_mode %}
|
||||||
background-color:#bcbcbc;
|
video{
|
||||||
|
grid-column: 1 / span 5;
|
||||||
|
justify-self: center;
|
||||||
|
max-width: 100%;
|
||||||
|
width: {{ theater_video_target_width }}px;
|
||||||
|
max-height: {{ video_height }}px;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
background-color: var(--background-color);
|
||||||
|
}
|
||||||
|
.related-videos-outer{
|
||||||
|
grid-row: 2 /span 3;
|
||||||
|
width: 400px;
|
||||||
|
}
|
||||||
|
.video-info{
|
||||||
|
width: 640px;
|
||||||
|
}
|
||||||
|
{% else %}
|
||||||
|
video{
|
||||||
|
height: 360px;
|
||||||
|
width: 640px;
|
||||||
|
grid-column: 2;
|
||||||
|
}
|
||||||
|
.related-videos-outer{
|
||||||
|
grid-row: 1 /span 4;
|
||||||
|
}
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
main{
|
||||||
|
display:grid;
|
||||||
|
grid-template-columns: 1fr 640px 40px 400px 1fr;
|
||||||
|
grid-template-rows: auto auto auto auto;
|
||||||
|
align-content: start;
|
||||||
|
}
|
||||||
|
|
||||||
|
.video-info{
|
||||||
|
grid-column: 2;
|
||||||
|
grid-row: 2;
|
||||||
|
display: grid;
|
||||||
|
grid-template-rows: 0fr 0fr 0fr 20px 0fr 0fr;
|
||||||
|
grid-template-columns: 1fr 1fr;
|
||||||
|
align-content: start;
|
||||||
|
}
|
||||||
|
.video-info > .title{
|
||||||
|
grid-column: 1 / span 2;
|
||||||
|
min-width: 0;
|
||||||
|
}
|
||||||
|
.video-info > .is-unlisted{
|
||||||
|
background-color: var(--interface-color);
|
||||||
|
justify-self:start;
|
||||||
|
padding-left:2px;
|
||||||
|
padding-right:2px;
|
||||||
|
}
|
||||||
|
.video-info > address{
|
||||||
grid-column: 1;
|
grid-column: 1;
|
||||||
|
grid-row: 3;
|
||||||
|
justify-self: start;
|
||||||
}
|
}
|
||||||
.full-item{
|
.video-info > .views{
|
||||||
display: grid;
|
grid-column: 2;
|
||||||
grid-column: 2;
|
grid-row: 3;
|
||||||
grid-template-rows: 0fr 0fr 0fr 0fr 20px 0fr 0fr;
|
justify-self:end;
|
||||||
grid-template-columns: 1fr 1fr;
|
}
|
||||||
align-content: start;
|
.video-info > time{
|
||||||
background-color:#bcbcbc;
|
grid-column: 1;
|
||||||
}
|
grid-row: 4;
|
||||||
.full-item > video{
|
justify-self:start;
|
||||||
grid-column: 1 / span 2;
|
}
|
||||||
grid-row: 1;
|
.video-info > .likes-dislikes{
|
||||||
}
|
grid-column: 2;
|
||||||
.full-item > .title{
|
grid-row: 4;
|
||||||
grid-column: 1 / span 2;
|
justify-self:end;
|
||||||
grid-row:2;
|
}
|
||||||
min-width: 0;
|
.video-info > .download-dropdown{
|
||||||
}
|
grid-column:1 / span 2;
|
||||||
.full-item > .is-unlisted{
|
grid-row: 6;
|
||||||
background-color: #d0d0d0;
|
}
|
||||||
justify-self:start;
|
.video-info > .checkbox{
|
||||||
padding-left:2px;
|
justify-self:end;
|
||||||
padding-right:2px;
|
align-self: start;
|
||||||
}
|
|
||||||
.full-item > address{
|
|
||||||
grid-column: 1;
|
|
||||||
grid-row: 4;
|
|
||||||
justify-self: start;
|
|
||||||
}
|
|
||||||
.full-item > .views{
|
|
||||||
grid-column: 2;
|
|
||||||
grid-row: 4;
|
|
||||||
justify-self:end;
|
|
||||||
}
|
|
||||||
.full-item > time{
|
|
||||||
grid-column: 1;
|
|
||||||
grid-row: 5;
|
|
||||||
justify-self:start;
|
|
||||||
}
|
|
||||||
.full-item > .likes-dislikes{
|
|
||||||
grid-column: 2;
|
|
||||||
grid-row: 5;
|
|
||||||
justify-self:end;
|
|
||||||
}
|
|
||||||
.full-item > .download-dropdown{
|
|
||||||
grid-column:1;
|
|
||||||
grid-row: 6;
|
|
||||||
}
|
|
||||||
.full-item > .checkbox{
|
|
||||||
justify-self:end;
|
|
||||||
|
|
||||||
grid-row: 6;
|
grid-row: 5;
|
||||||
grid-column: 2;
|
grid-column: 2;
|
||||||
}
|
}
|
||||||
.full-item > .description{
|
.video-info > .description{
|
||||||
background-color:#d0d0d0;
|
background-color:var(--interface-color);
|
||||||
margin-top:8px;
|
margin-top:8px;
|
||||||
white-space: pre-wrap;
|
white-space: pre-wrap;
|
||||||
min-width: 0;
|
min-width: 0;
|
||||||
word-wrap: break-word;
|
word-wrap: break-word;
|
||||||
grid-column: 1 / span 2;
|
grid-column: 1 / span 2;
|
||||||
grid-row: 7;
|
grid-row: 7;
|
||||||
}
|
}
|
||||||
.full-item .music-list{
|
|
||||||
grid-row:8;
|
|
||||||
grid-column: 1 / span 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
.full-item .comments-area{
|
.music-list{
|
||||||
grid-column: 1 / span 2;
|
grid-row:8;
|
||||||
grid-row: 9;
|
grid-column: 1 / span 2;
|
||||||
margin-top:10px;
|
background-color: var(--interface-color);
|
||||||
}
|
}
|
||||||
.comment{
|
|
||||||
width:640px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.music-list{
|
|
||||||
background-color: #d0d0d0;
|
|
||||||
}
|
|
||||||
.music-list table,th,td{
|
.music-list table,th,td{
|
||||||
border: 1px solid;
|
border: 1px solid;
|
||||||
}
|
}
|
||||||
@ -105,126 +125,161 @@
|
|||||||
font-weight:bold;
|
font-weight:bold;
|
||||||
margin-bottom:5px;
|
margin-bottom:5px;
|
||||||
}
|
}
|
||||||
|
.comments-area-outer{
|
||||||
#related{
|
grid-column: 2;
|
||||||
grid-column: 4;
|
grid-row: 3;
|
||||||
display: grid;
|
margin-top:10px;
|
||||||
grid-auto-rows: 90px;
|
}
|
||||||
grid-row-gap: 10px;
|
.comments-area-inner{
|
||||||
}
|
padding-top: 10px;
|
||||||
#related .medium-item{
|
}
|
||||||
grid-template-columns: 160px 1fr 0fr;
|
.comment{
|
||||||
}
|
width:640px;
|
||||||
|
|
||||||
.download-dropdown{
|
|
||||||
z-index:1;
|
|
||||||
justify-self:start;
|
|
||||||
min-width:0px;
|
|
||||||
height:0px;
|
|
||||||
}
|
}
|
||||||
|
.related-videos-outer{
|
||||||
|
grid-column: 4;
|
||||||
|
max-width: 640px;
|
||||||
|
}
|
||||||
|
.related-videos-inner{
|
||||||
|
padding-top: 10px;
|
||||||
|
display: grid;
|
||||||
|
grid-auto-rows: 94px;
|
||||||
|
grid-row-gap: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
.download-dropdown-label{
|
/* Put related vids below videos when window is too small */
|
||||||
background-color: #e9e9e9;
|
/* 1100px instead of 1080 because W3C is full of idiots who include scrollbar width */
|
||||||
border-style: outset;
|
@media (max-width:1100px){
|
||||||
border-width: 2px;
|
main{
|
||||||
font-weight: bold;
|
grid-template-columns: 1fr 640px 40px 1fr;
|
||||||
}
|
}
|
||||||
|
.related-videos-outer{
|
||||||
|
margin-top: 10px;
|
||||||
|
grid-column: 2;
|
||||||
|
grid-row: 3;
|
||||||
|
width: initial;
|
||||||
|
}
|
||||||
|
.comments-area-outer{
|
||||||
|
grid-row: 4;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.download-dropdown-content{
|
.download-dropdown-content{
|
||||||
display:none;
|
background-color: var(--interface-color);
|
||||||
background-color: #e9e9e9;
|
padding: 10px;
|
||||||
|
list-style: none;
|
||||||
|
margin: 0px;
|
||||||
|
}
|
||||||
|
li.download-format{
|
||||||
|
margin-bottom: 7px;
|
||||||
|
}
|
||||||
|
.format-attributes{
|
||||||
|
list-style: none;
|
||||||
|
padding: 0px;
|
||||||
|
margin: 0px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
}
|
||||||
|
.format-attributes li{
|
||||||
|
white-space: nowrap;
|
||||||
|
max-height: 1.2em;
|
||||||
}
|
}
|
||||||
.download-dropdown:hover .download-dropdown-content {
|
.format-ext{
|
||||||
display: grid;
|
width: 60px;
|
||||||
grid-auto-rows:30px;
|
}
|
||||||
padding-bottom: 50px;
|
.format-res{
|
||||||
|
width:90px;
|
||||||
}
|
}
|
||||||
.download-dropdown-content a{
|
|
||||||
white-space: nowrap;
|
|
||||||
display:grid;
|
|
||||||
grid-template-columns: 60px 90px auto;
|
|
||||||
max-height: 1.2em;
|
|
||||||
}
|
|
||||||
{% endblock style %}
|
{% endblock style %}
|
||||||
|
|
||||||
{% block main %}
|
{% block main %}
|
||||||
<div id="left">
|
<video controls autofocus>
|
||||||
</div>
|
{% for video_source in video_sources %}
|
||||||
<article class="full-item">
|
<source src="{{ video_source['src'] }}" type="{{ video_source['type'] }}">
|
||||||
|
{% endfor %}
|
||||||
|
|
||||||
<video width="640" height="360" controls autofocus>
|
{% for source in subtitle_sources %}
|
||||||
{% for video_source in video_sources %}
|
{% if source['on'] %}
|
||||||
<source src="{{ video_source['src'] }}" type="{{ video_source['type'] }}">
|
<track label="{{ source['label'] }}" src="{{ source['url'] }}" kind="subtitles" srclang="{{ source['srclang'] }}" default>
|
||||||
{% endfor %}
|
{% else %}
|
||||||
|
<track label="{{ source['label'] }}" src="{{ source['url'] }}" kind="subtitles" srclang="{{ source['srclang'] }}">
|
||||||
|
{% endif %}
|
||||||
|
{% endfor %}
|
||||||
|
|
||||||
{% for source in subtitle_sources %}
|
</video>
|
||||||
{% if source['on'] %}
|
|
||||||
<track label="{{ source['label'] }}" src="{{ source['url'] }}" kind="subtitles" srclang="{{ source['srclang'] }}" default>
|
<div class="video-info">
|
||||||
{% else %}
|
<h2 class="title">{{ title }}</h2>
|
||||||
<track label="{{ source['label'] }}" src="{{ source['url'] }}" kind="subtitles" srclang="{{ source['srclang'] }}">
|
{% if unlisted %}
|
||||||
|
<span class="is-unlisted">Unlisted</span>
|
||||||
|
{% endif %}
|
||||||
|
<address>Uploaded by <a href="{{ uploader_channel_url }}">{{ uploader }}</a></address>
|
||||||
|
<span class="views">{{ views }} views</span>
|
||||||
|
|
||||||
|
|
||||||
|
<time datetime="$upload_date">Published on {{ upload_date }}</time>
|
||||||
|
<span class="likes-dislikes">{{ likes }} likes {{ dislikes }} dislikes</span>
|
||||||
|
<details class="download-dropdown">
|
||||||
|
<summary class="download-dropdown-label">Download</summary>
|
||||||
|
<ul class="download-dropdown-content">
|
||||||
|
{% for format in download_formats %}
|
||||||
|
<li class="download-format">
|
||||||
|
<a class="download-link" href="{{ format['url'] }}">
|
||||||
|
<ol class="format-attributes">
|
||||||
|
<li class="format-ext">{{ format['ext'] }}</li>
|
||||||
|
<li class="format-res">{{ format['resolution'] }}</li>
|
||||||
|
<li class="format-note">{{ format['note'] }}</li>
|
||||||
|
</ol>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
</details>
|
||||||
|
<input class="checkbox" name="video_info_list" value="{{ video_info }}" form="playlist-edit" type="checkbox">
|
||||||
|
|
||||||
|
|
||||||
|
<span class="description">{{ description }}</span>
|
||||||
|
<div class="music-list">
|
||||||
|
{% if music_list.__len__() != 0 %}
|
||||||
|
<hr>
|
||||||
|
<table>
|
||||||
|
<caption>Music</caption>
|
||||||
|
<tr>
|
||||||
|
{% for attribute in music_attributes %}
|
||||||
|
<th>{{ attribute }}</th>
|
||||||
|
{% endfor %}
|
||||||
|
</tr>
|
||||||
|
{% for track in music_list %}
|
||||||
|
<tr>
|
||||||
|
{% for attribute in music_attributes %}
|
||||||
|
<td>{{ track.get(attribute.lower(), '') }}</td>
|
||||||
|
{% endfor %}
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</table>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{% if related_videos_mode != 0 %}
|
||||||
|
<details class="related-videos-outer" {{'open' if related_videos_mode == 1 else ''}}>
|
||||||
|
<summary>Related Videos</summary>
|
||||||
|
<nav class="related-videos-inner">
|
||||||
|
{% for info in related %}
|
||||||
|
{{ common_elements.item(info) }}
|
||||||
|
{% endfor %}
|
||||||
|
</nav>
|
||||||
|
</details>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% endfor %}
|
|
||||||
|
|
||||||
</video>
|
|
||||||
|
|
||||||
<h2 class="title">{{ title }}</h2>
|
|
||||||
{% if unlisted %}
|
|
||||||
<span class="is-unlisted">Unlisted</span>
|
|
||||||
{% endif %}
|
|
||||||
<address>Uploaded by <a href="{{ uploader_channel_url }}">{{ uploader }}</a></address>
|
|
||||||
<span class="views">{{ views }} views</span>
|
|
||||||
|
|
||||||
|
|
||||||
<time datetime="$upload_date">Published on {{ upload_date }}</time>
|
|
||||||
<span class="likes-dislikes">{{ likes }} likes {{ dislikes }} dislikes</span>
|
|
||||||
<div class="download-dropdown">
|
|
||||||
<button class="download-dropdown-label">Download</button>
|
|
||||||
<div class="download-dropdown-content">
|
|
||||||
{% for format in download_formats %}
|
|
||||||
<a href="{{ format['url'] }}">
|
|
||||||
<span>{{ format['ext'] }}</span>
|
|
||||||
<span>{{ format['resolution'] }}</span>
|
|
||||||
<span>{{ format['note'] }}</span>
|
|
||||||
</a>
|
|
||||||
{% endfor %}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<input class="checkbox" name="video_info_list" value="{{ video_info }}" form="playlist-edit" type="checkbox">
|
|
||||||
|
|
||||||
<span class="description">{{ description }}</span>
|
|
||||||
<div class="music-list">
|
|
||||||
{% if music_list.__len__() != 0 %}
|
|
||||||
<hr>
|
|
||||||
<table>
|
|
||||||
<caption>Music</caption>
|
|
||||||
<tr>
|
|
||||||
{% for attribute in music_attributes %}
|
|
||||||
<th>{{ attribute }}</th>
|
|
||||||
{% endfor %}
|
|
||||||
</tr>
|
|
||||||
{% for track in music_list %}
|
|
||||||
<tr>
|
|
||||||
{% for attribute in music_attributes %}
|
|
||||||
<td>{{ track.get(attribute.lower(), '') }}</td>
|
|
||||||
{% endfor %}
|
|
||||||
</tr>
|
|
||||||
{% endfor %}
|
|
||||||
</table>
|
|
||||||
{% endif %}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
{% if comments_mode != 0 %}
|
||||||
|
<details class="comments-area-outer" {{'open' if comments_mode == 1 else ''}}>
|
||||||
|
<summary>Comments</summary>
|
||||||
|
<section class="comments-area-inner comments-area">
|
||||||
{% if comments_info %}
|
{% if comments_info %}
|
||||||
{{ comments.video_comments(comments_info) }}
|
{{ comments.video_comments(comments_info) }}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</article>
|
</section>
|
||||||
|
</details>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
|
||||||
<nav id="related">
|
|
||||||
{% for info in related %}
|
|
||||||
{{ common_elements.item(info) }}
|
|
||||||
{% endfor %}
|
|
||||||
</nav>
|
|
||||||
|
|
||||||
{% endblock main %}
|
{% endblock main %}
|
||||||
|
@ -36,7 +36,6 @@ def watch_page_related_video_info(item):
|
|||||||
except KeyError:
|
except KeyError:
|
||||||
result['views'] = ''
|
result['views'] = ''
|
||||||
result['thumbnail'] = util.get_thumbnail_url(item['id'])
|
result['thumbnail'] = util.get_thumbnail_url(item['id'])
|
||||||
result['item_size'] = 'small'
|
|
||||||
result['type'] = 'video'
|
result['type'] = 'video'
|
||||||
return result
|
return result
|
||||||
|
|
||||||
@ -47,19 +46,24 @@ def watch_page_related_playlist_info(item):
|
|||||||
'id': item['list'],
|
'id': item['list'],
|
||||||
'first_video_id': item['video_id'],
|
'first_video_id': item['video_id'],
|
||||||
'thumbnail': util.get_thumbnail_url(item['video_id']),
|
'thumbnail': util.get_thumbnail_url(item['video_id']),
|
||||||
'item_size': 'small',
|
|
||||||
'type': 'playlist',
|
'type': 'playlist',
|
||||||
}
|
}
|
||||||
|
|
||||||
def get_video_sources(info):
|
def get_video_sources(info):
|
||||||
video_sources = []
|
video_sources = []
|
||||||
for format in info['formats']:
|
for format in info['formats']:
|
||||||
if format['acodec'] != 'none' and format['vcodec'] != 'none':
|
if format['acodec'] != 'none' and format['vcodec'] != 'none' and format['height'] <= settings.default_resolution:
|
||||||
video_sources.append({
|
video_sources.append({
|
||||||
'src': format['url'],
|
'src': format['url'],
|
||||||
'type': 'video/' + format['ext'],
|
'type': 'video/' + format['ext'],
|
||||||
|
'height': format['height'],
|
||||||
|
'width': format['width'],
|
||||||
})
|
})
|
||||||
|
|
||||||
|
#### order the videos sources so the preferred resolution is first ###
|
||||||
|
|
||||||
|
video_sources.sort(key=lambda source: source['height'], reverse=True)
|
||||||
|
|
||||||
return video_sources
|
return video_sources
|
||||||
|
|
||||||
def get_subtitle_sources(info):
|
def get_subtitle_sources(info):
|
||||||
@ -193,6 +197,12 @@ def get_watch_page():
|
|||||||
'note': yt_dl_downloader._format_note(format),
|
'note': yt_dl_downloader._format_note(format),
|
||||||
})
|
})
|
||||||
|
|
||||||
|
video_sources = get_video_sources(info)
|
||||||
|
video_height = video_sources[0]['height']
|
||||||
|
|
||||||
|
# 1 second per pixel, or the actual video width
|
||||||
|
theater_video_target_width = max(640, info['duration'], video_sources[0]['width'])
|
||||||
|
|
||||||
return flask.render_template('watch.html',
|
return flask.render_template('watch.html',
|
||||||
header_playlist_names = local_playlist.get_playlist_names(),
|
header_playlist_names = local_playlist.get_playlist_names(),
|
||||||
uploader_channel_url = '/' + info['uploader_url'],
|
uploader_channel_url = '/' + info['uploader_url'],
|
||||||
@ -202,13 +212,20 @@ def get_watch_page():
|
|||||||
dislikes = (lambda x: '{:,}'.format(x) if x is not None else "")(info.get("dislike_count", None)),
|
dislikes = (lambda x: '{:,}'.format(x) if x is not None else "")(info.get("dislike_count", None)),
|
||||||
download_formats = download_formats,
|
download_formats = download_formats,
|
||||||
video_info = json.dumps(video_info),
|
video_info = json.dumps(video_info),
|
||||||
video_sources = get_video_sources(info),
|
video_sources = video_sources,
|
||||||
subtitle_sources = get_subtitle_sources(info),
|
subtitle_sources = get_subtitle_sources(info),
|
||||||
related = related_videos,
|
related = related_videos,
|
||||||
music_list = info['music_list'],
|
music_list = info['music_list'],
|
||||||
music_attributes = get_ordered_music_list_attributes(info['music_list']),
|
music_attributes = get_ordered_music_list_attributes(info['music_list']),
|
||||||
comments_info = comments_info,
|
comments_info = comments_info,
|
||||||
|
|
||||||
|
theater_mode = settings.theater_mode,
|
||||||
|
related_videos_mode = settings.related_videos_mode,
|
||||||
|
comments_mode = settings.comments_mode,
|
||||||
|
|
||||||
|
video_height = video_height,
|
||||||
|
theater_video_target_width = theater_video_target_width,
|
||||||
|
|
||||||
title = info['title'],
|
title = info['title'],
|
||||||
uploader = info['uploader'],
|
uploader = info['uploader'],
|
||||||
description = info['description'],
|
description = info['description'],
|
||||||
|
@ -197,10 +197,6 @@ def renderer_info(renderer, additional_info={}):
|
|||||||
|
|
||||||
info.update(additional_info)
|
info.update(additional_info)
|
||||||
|
|
||||||
if type.startswith('compact') or (type.startswith('playlist') and type != 'playlistRenderer'):
|
|
||||||
info['item_size'] = 'small'
|
|
||||||
else:
|
|
||||||
info['item_size'] = 'medium'
|
|
||||||
|
|
||||||
if type in ('compactVideoRenderer', 'videoRenderer', 'playlistVideoRenderer', 'gridVideoRenderer'):
|
if type in ('compactVideoRenderer', 'videoRenderer', 'playlistVideoRenderer', 'gridVideoRenderer'):
|
||||||
info['type'] = 'video'
|
info['type'] = 'video'
|
||||||
|
Loading…
x
Reference in New Issue
Block a user