mirror of
https://github.com/chibicitiberiu/ytsm.git
synced 2024-02-24 05:43:31 +00:00
Merge pull request #22 from chibicitiberiu/development
Load all settings from config.ini, improve docker support and cleanup
This commit is contained in:
commit
d989cf4132
8
.gitignore
vendored
8
.gitignore
vendored
@ -115,10 +115,16 @@ venv.bak/
|
|||||||
.dmypy.json
|
.dmypy.json
|
||||||
dmypy.json
|
dmypy.json
|
||||||
|
|
||||||
media/
|
data/
|
||||||
|
|
||||||
.vscode/*
|
.vscode/*
|
||||||
!.vscode/settings.json
|
!.vscode/settings.json
|
||||||
!.vscode/tasks.json
|
!.vscode/tasks.json
|
||||||
!.vscode/launch.json
|
!.vscode/launch.json
|
||||||
!.vscode/extensions.json
|
!.vscode/extensions.json
|
||||||
|
|
||||||
|
.idea
|
||||||
|
|
||||||
|
# Dolphin generated file
|
||||||
|
.directory
|
||||||
|
|
||||||
|
@ -1,5 +0,0 @@
|
|||||||
<component name="ProjectCodeStyleConfiguration">
|
|
||||||
<state>
|
|
||||||
<option name="PREFERRED_PROJECT_CODE_STYLE" value="Default" />
|
|
||||||
</state>
|
|
||||||
</component>
|
|
@ -1,21 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project version="4">
|
|
||||||
<component name="dataSourceStorageLocal">
|
|
||||||
<data-source name="Django default" uuid="2dac2136-d902-4d27-8789-9371934602fd">
|
|
||||||
<database-info product="SQLite" version="3.25.1" jdbc-version="2.1" driver-name="SQLite JDBC" driver-version="3.25.1" family="SQLITE" exact-version="3.25.1">
|
|
||||||
<identifier-quote-string>"</identifier-quote-string>
|
|
||||||
</database-info>
|
|
||||||
<case-sensitivity plain-identifiers="mixed" quoted-identifiers="mixed" />
|
|
||||||
<auth-required>false</auth-required>
|
|
||||||
<introspection-schemas>*:@</introspection-schemas>
|
|
||||||
</data-source>
|
|
||||||
<data-source name="db" uuid="77df9da5-0b97-445e-a895-744ef8257a74">
|
|
||||||
<database-info product="SQLite" version="3.25.1" jdbc-version="2.1" driver-name="SQLite JDBC" driver-version="3.25.1" family="SQLITE" exact-version="3.25.1">
|
|
||||||
<identifier-quote-string>"</identifier-quote-string>
|
|
||||||
</database-info>
|
|
||||||
<case-sensitivity plain-identifiers="mixed" quoted-identifiers="mixed" />
|
|
||||||
<auth-required>false</auth-required>
|
|
||||||
<introspection-schemas>*:@</introspection-schemas>
|
|
||||||
</data-source>
|
|
||||||
</component>
|
|
||||||
</project>
|
|
@ -1,33 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project version="4">
|
|
||||||
<component name="DataSourceManagerImpl" format="xml" multifile-model="true">
|
|
||||||
<data-source source="LOCAL" name="Django default" uuid="2dac2136-d902-4d27-8789-9371934602fd">
|
|
||||||
<driver-ref>sqlite.xerial</driver-ref>
|
|
||||||
<synchronize>true</synchronize>
|
|
||||||
<imported>true</imported>
|
|
||||||
<remarks>$PROJECT_DIR$/YtManager/settings.py</remarks>
|
|
||||||
<jdbc-driver>org.sqlite.JDBC</jdbc-driver>
|
|
||||||
<jdbc-url>jdbc:sqlite:D:\Dev\youtube-channel-manager\db.sqlite3</jdbc-url>
|
|
||||||
<driver-properties>
|
|
||||||
<property name="enable_load_extension" value="true" />
|
|
||||||
</driver-properties>
|
|
||||||
</data-source>
|
|
||||||
<data-source source="LOCAL" name="db" uuid="77df9da5-0b97-445e-a895-744ef8257a74">
|
|
||||||
<driver-ref>sqlite.xerial</driver-ref>
|
|
||||||
<synchronize>true</synchronize>
|
|
||||||
<jdbc-driver>org.sqlite.JDBC</jdbc-driver>
|
|
||||||
<jdbc-url>jdbc:sqlite:$PROJECT_DIR$/db.sqlite3</jdbc-url>
|
|
||||||
<driver-properties>
|
|
||||||
<property name="enable_load_extension" value="true" />
|
|
||||||
</driver-properties>
|
|
||||||
<libraries>
|
|
||||||
<library>
|
|
||||||
<url>file://$APPLICATION_CONFIG_DIR$/jdbc-drivers/Xerial SQLiteJDBC/3.25.1/sqlite-jdbc-3.25.1.jar</url>
|
|
||||||
</library>
|
|
||||||
<library>
|
|
||||||
<url>file://$APPLICATION_CONFIG_DIR$/jdbc-drivers/Xerial SQLiteJDBC/3.25.1/license.txt</url>
|
|
||||||
</library>
|
|
||||||
</libraries>
|
|
||||||
</data-source>
|
|
||||||
</component>
|
|
||||||
</project>
|
|
@ -1,38 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<dataSource name="Django default">
|
|
||||||
<database-model serializer="dbm" rdbms="SQLITE" format-version="4.11">
|
|
||||||
<root id="1">
|
|
||||||
<ServerVersion>3.25.1</ServerVersion>
|
|
||||||
</root>
|
|
||||||
<schema id="2" parent="1" name="main">
|
|
||||||
<Current>1</Current>
|
|
||||||
<Visible>1</Visible>
|
|
||||||
</schema>
|
|
||||||
<collation id="3" parent="1" name="BINARY"/>
|
|
||||||
<collation id="4" parent="1" name="NOCASE"/>
|
|
||||||
<collation id="5" parent="1" name="RTRIM"/>
|
|
||||||
<table id="6" parent="2" name="sqlite_master">
|
|
||||||
<System>1</System>
|
|
||||||
</table>
|
|
||||||
<column id="7" parent="6" name="type">
|
|
||||||
<Position>1</Position>
|
|
||||||
<DataType>text|0s</DataType>
|
|
||||||
</column>
|
|
||||||
<column id="8" parent="6" name="name">
|
|
||||||
<Position>2</Position>
|
|
||||||
<DataType>text|0s</DataType>
|
|
||||||
</column>
|
|
||||||
<column id="9" parent="6" name="tbl_name">
|
|
||||||
<Position>3</Position>
|
|
||||||
<DataType>text|0s</DataType>
|
|
||||||
</column>
|
|
||||||
<column id="10" parent="6" name="rootpage">
|
|
||||||
<Position>4</Position>
|
|
||||||
<DataType>int|0s</DataType>
|
|
||||||
</column>
|
|
||||||
<column id="11" parent="6" name="sql">
|
|
||||||
<Position>5</Position>
|
|
||||||
<DataType>text|0s</DataType>
|
|
||||||
</column>
|
|
||||||
</database-model>
|
|
||||||
</dataSource>
|
|
@ -1,2 +0,0 @@
|
|||||||
#n:main
|
|
||||||
!<md> [0, 0, null, null, -2147483648, -2147483648]
|
|
@ -1,883 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<dataSource name="db">
|
|
||||||
<database-model serializer="dbm" rdbms="SQLITE" format-version="4.11">
|
|
||||||
<root id="1">
|
|
||||||
<ServerVersion>3.25.1</ServerVersion>
|
|
||||||
</root>
|
|
||||||
<schema id="2" parent="1" name="main">
|
|
||||||
<Current>1</Current>
|
|
||||||
<Visible>1</Visible>
|
|
||||||
</schema>
|
|
||||||
<collation id="3" parent="1" name="BINARY"/>
|
|
||||||
<collation id="4" parent="1" name="NOCASE"/>
|
|
||||||
<collation id="5" parent="1" name="RTRIM"/>
|
|
||||||
<table id="6" parent="2" name="YtManagerApp_channel"/>
|
|
||||||
<table id="7" parent="2" name="YtManagerApp_subscription"/>
|
|
||||||
<table id="8" parent="2" name="YtManagerApp_subscriptionfolder"/>
|
|
||||||
<table id="9" parent="2" name="YtManagerApp_usersettings"/>
|
|
||||||
<table id="10" parent="2" name="YtManagerApp_video"/>
|
|
||||||
<table id="11" parent="2" name="auth_group"/>
|
|
||||||
<table id="12" parent="2" name="auth_group_permissions"/>
|
|
||||||
<table id="13" parent="2" name="auth_permission"/>
|
|
||||||
<table id="14" parent="2" name="auth_user"/>
|
|
||||||
<table id="15" parent="2" name="auth_user_groups"/>
|
|
||||||
<table id="16" parent="2" name="auth_user_user_permissions"/>
|
|
||||||
<table id="17" parent="2" name="django_admin_log"/>
|
|
||||||
<table id="18" parent="2" name="django_content_type"/>
|
|
||||||
<table id="19" parent="2" name="django_migrations"/>
|
|
||||||
<table id="20" parent="2" name="django_session"/>
|
|
||||||
<table id="21" parent="2" name="sqlite_master">
|
|
||||||
<System>1</System>
|
|
||||||
</table>
|
|
||||||
<table id="22" parent="2" name="sqlite_sequence">
|
|
||||||
<System>1</System>
|
|
||||||
</table>
|
|
||||||
<column id="23" parent="6" name="id">
|
|
||||||
<Position>1</Position>
|
|
||||||
<DataType>integer|0s</DataType>
|
|
||||||
<NotNull>1</NotNull>
|
|
||||||
<SequenceIdentity>1</SequenceIdentity>
|
|
||||||
</column>
|
|
||||||
<column id="24" parent="6" name="channel_id">
|
|
||||||
<Position>2</Position>
|
|
||||||
<DataType>text|0s</DataType>
|
|
||||||
<NotNull>1</NotNull>
|
|
||||||
</column>
|
|
||||||
<column id="25" parent="6" name="username">
|
|
||||||
<Position>3</Position>
|
|
||||||
<DataType>text|0s</DataType>
|
|
||||||
</column>
|
|
||||||
<column id="26" parent="6" name="custom_url">
|
|
||||||
<Position>4</Position>
|
|
||||||
<DataType>text|0s</DataType>
|
|
||||||
</column>
|
|
||||||
<column id="27" parent="6" name="name">
|
|
||||||
<Position>5</Position>
|
|
||||||
<DataType>text|0s</DataType>
|
|
||||||
<NotNull>1</NotNull>
|
|
||||||
</column>
|
|
||||||
<column id="28" parent="6" name="description">
|
|
||||||
<Position>6</Position>
|
|
||||||
<DataType>text|0s</DataType>
|
|
||||||
<NotNull>1</NotNull>
|
|
||||||
</column>
|
|
||||||
<column id="29" parent="6" name="icon_default">
|
|
||||||
<Position>7</Position>
|
|
||||||
<DataType>text|0s</DataType>
|
|
||||||
<NotNull>1</NotNull>
|
|
||||||
</column>
|
|
||||||
<column id="30" parent="6" name="icon_best">
|
|
||||||
<Position>8</Position>
|
|
||||||
<DataType>text|0s</DataType>
|
|
||||||
<NotNull>1</NotNull>
|
|
||||||
</column>
|
|
||||||
<column id="31" parent="6" name="upload_playlist_id">
|
|
||||||
<Position>9</Position>
|
|
||||||
<DataType>text|0s</DataType>
|
|
||||||
<NotNull>1</NotNull>
|
|
||||||
</column>
|
|
||||||
<index id="32" parent="6" name="sqlite_autoindex_YtManagerApp_channel_1">
|
|
||||||
<NameSurrogate>1</NameSurrogate>
|
|
||||||
<ColNames>channel_id</ColNames>
|
|
||||||
<ColumnCollations></ColumnCollations>
|
|
||||||
<Unique>1</Unique>
|
|
||||||
</index>
|
|
||||||
<index id="33" parent="6" name="sqlite_autoindex_YtManagerApp_channel_2">
|
|
||||||
<NameSurrogate>1</NameSurrogate>
|
|
||||||
<ColNames>username</ColNames>
|
|
||||||
<ColumnCollations></ColumnCollations>
|
|
||||||
<Unique>1</Unique>
|
|
||||||
</index>
|
|
||||||
<index id="34" parent="6" name="sqlite_autoindex_YtManagerApp_channel_3">
|
|
||||||
<NameSurrogate>1</NameSurrogate>
|
|
||||||
<ColNames>custom_url</ColNames>
|
|
||||||
<ColumnCollations></ColumnCollations>
|
|
||||||
<Unique>1</Unique>
|
|
||||||
</index>
|
|
||||||
<key id="35" parent="6">
|
|
||||||
<ColNames>id</ColNames>
|
|
||||||
<Primary>1</Primary>
|
|
||||||
</key>
|
|
||||||
<key id="36" parent="6">
|
|
||||||
<ColNames>channel_id</ColNames>
|
|
||||||
<UnderlyingIndexName>sqlite_autoindex_YtManagerApp_channel_1</UnderlyingIndexName>
|
|
||||||
</key>
|
|
||||||
<key id="37" parent="6">
|
|
||||||
<ColNames>username</ColNames>
|
|
||||||
<UnderlyingIndexName>sqlite_autoindex_YtManagerApp_channel_2</UnderlyingIndexName>
|
|
||||||
</key>
|
|
||||||
<key id="38" parent="6">
|
|
||||||
<ColNames>custom_url</ColNames>
|
|
||||||
<UnderlyingIndexName>sqlite_autoindex_YtManagerApp_channel_3</UnderlyingIndexName>
|
|
||||||
</key>
|
|
||||||
<column id="39" parent="7" name="id">
|
|
||||||
<Position>1</Position>
|
|
||||||
<DataType>integer|0s</DataType>
|
|
||||||
<NotNull>1</NotNull>
|
|
||||||
<SequenceIdentity>1</SequenceIdentity>
|
|
||||||
</column>
|
|
||||||
<column id="40" parent="7" name="name">
|
|
||||||
<Position>2</Position>
|
|
||||||
<DataType>varchar(1024)|0s</DataType>
|
|
||||||
<NotNull>1</NotNull>
|
|
||||||
</column>
|
|
||||||
<column id="41" parent="7" name="playlist_id">
|
|
||||||
<Position>3</Position>
|
|
||||||
<DataType>varchar(128)|0s</DataType>
|
|
||||||
<NotNull>1</NotNull>
|
|
||||||
</column>
|
|
||||||
<column id="42" parent="7" name="description">
|
|
||||||
<Position>4</Position>
|
|
||||||
<DataType>text|0s</DataType>
|
|
||||||
<NotNull>1</NotNull>
|
|
||||||
</column>
|
|
||||||
<column id="43" parent="7" name="icon_default">
|
|
||||||
<Position>5</Position>
|
|
||||||
<DataType>varchar(1024)|0s</DataType>
|
|
||||||
<NotNull>1</NotNull>
|
|
||||||
</column>
|
|
||||||
<column id="44" parent="7" name="icon_best">
|
|
||||||
<Position>6</Position>
|
|
||||||
<DataType>varchar(1024)|0s</DataType>
|
|
||||||
<NotNull>1</NotNull>
|
|
||||||
</column>
|
|
||||||
<column id="45" parent="7" name="auto_download">
|
|
||||||
<Position>7</Position>
|
|
||||||
<DataType>bool|0s</DataType>
|
|
||||||
</column>
|
|
||||||
<column id="46" parent="7" name="download_limit">
|
|
||||||
<Position>8</Position>
|
|
||||||
<DataType>integer|0s</DataType>
|
|
||||||
</column>
|
|
||||||
<column id="47" parent="7" name="download_order">
|
|
||||||
<Position>9</Position>
|
|
||||||
<DataType>varchar(128)|0s</DataType>
|
|
||||||
</column>
|
|
||||||
<column id="48" parent="7" name="channel_id">
|
|
||||||
<Position>10</Position>
|
|
||||||
<DataType>integer|0s</DataType>
|
|
||||||
<NotNull>1</NotNull>
|
|
||||||
</column>
|
|
||||||
<column id="49" parent="7" name="parent_folder_id">
|
|
||||||
<Position>11</Position>
|
|
||||||
<DataType>integer|0s</DataType>
|
|
||||||
</column>
|
|
||||||
<column id="50" parent="7" name="user_id">
|
|
||||||
<Position>12</Position>
|
|
||||||
<DataType>integer|0s</DataType>
|
|
||||||
<NotNull>1</NotNull>
|
|
||||||
</column>
|
|
||||||
<column id="51" parent="7" name="delete_after_watched">
|
|
||||||
<Position>13</Position>
|
|
||||||
<DataType>bool|0s</DataType>
|
|
||||||
</column>
|
|
||||||
<index id="52" parent="7" name="YtManagerApp_subscription_channel_id_b83c6f21">
|
|
||||||
<ColNames>channel_id</ColNames>
|
|
||||||
<ColumnCollations></ColumnCollations>
|
|
||||||
</index>
|
|
||||||
<index id="53" parent="7" name="YtManagerApp_subscription_parent_folder_id_c4c64c21">
|
|
||||||
<ColNames>parent_folder_id</ColNames>
|
|
||||||
<ColumnCollations></ColumnCollations>
|
|
||||||
</index>
|
|
||||||
<index id="54" parent="7" name="YtManagerApp_subscription_user_id_9d38617d">
|
|
||||||
<ColNames>user_id</ColNames>
|
|
||||||
<ColumnCollations></ColumnCollations>
|
|
||||||
</index>
|
|
||||||
<key id="55" parent="7">
|
|
||||||
<ColNames>id</ColNames>
|
|
||||||
<Primary>1</Primary>
|
|
||||||
</key>
|
|
||||||
<foreign-key id="56" parent="7">
|
|
||||||
<ColNames>channel_id</ColNames>
|
|
||||||
<RefTableName>YtManagerApp_channel</RefTableName>
|
|
||||||
<RefColNames>id</RefColNames>
|
|
||||||
<Deferrable>1</Deferrable>
|
|
||||||
<InitiallyDeferred>1</InitiallyDeferred>
|
|
||||||
</foreign-key>
|
|
||||||
<foreign-key id="57" parent="7">
|
|
||||||
<ColNames>parent_folder_id</ColNames>
|
|
||||||
<RefTableName>YtManagerApp_subscriptionfolder</RefTableName>
|
|
||||||
<RefColNames>id</RefColNames>
|
|
||||||
<Deferrable>1</Deferrable>
|
|
||||||
<InitiallyDeferred>1</InitiallyDeferred>
|
|
||||||
</foreign-key>
|
|
||||||
<foreign-key id="58" parent="7">
|
|
||||||
<ColNames>user_id</ColNames>
|
|
||||||
<RefTableName>auth_user</RefTableName>
|
|
||||||
<RefColNames>id</RefColNames>
|
|
||||||
<Deferrable>1</Deferrable>
|
|
||||||
<InitiallyDeferred>1</InitiallyDeferred>
|
|
||||||
</foreign-key>
|
|
||||||
<column id="59" parent="8" name="id">
|
|
||||||
<Position>1</Position>
|
|
||||||
<DataType>integer|0s</DataType>
|
|
||||||
<NotNull>1</NotNull>
|
|
||||||
<SequenceIdentity>1</SequenceIdentity>
|
|
||||||
</column>
|
|
||||||
<column id="60" parent="8" name="user_id">
|
|
||||||
<Position>2</Position>
|
|
||||||
<DataType>integer|0s</DataType>
|
|
||||||
<NotNull>1</NotNull>
|
|
||||||
</column>
|
|
||||||
<column id="61" parent="8" name="name">
|
|
||||||
<Position>3</Position>
|
|
||||||
<DataType>varchar(250)|0s</DataType>
|
|
||||||
<NotNull>1</NotNull>
|
|
||||||
</column>
|
|
||||||
<column id="62" parent="8" name="parent_id">
|
|
||||||
<Position>4</Position>
|
|
||||||
<DataType>integer|0s</DataType>
|
|
||||||
</column>
|
|
||||||
<index id="63" parent="8" name="YtManagerApp_subscriptionfolder_user_id_6fb12da0">
|
|
||||||
<ColNames>user_id</ColNames>
|
|
||||||
<ColumnCollations></ColumnCollations>
|
|
||||||
</index>
|
|
||||||
<index id="64" parent="8" name="YtManagerApp_subscriptionfolder_parent_id_bd5f4bc1">
|
|
||||||
<ColNames>parent_id</ColNames>
|
|
||||||
<ColumnCollations></ColumnCollations>
|
|
||||||
</index>
|
|
||||||
<key id="65" parent="8">
|
|
||||||
<ColNames>id</ColNames>
|
|
||||||
<Primary>1</Primary>
|
|
||||||
</key>
|
|
||||||
<foreign-key id="66" parent="8">
|
|
||||||
<ColNames>user_id</ColNames>
|
|
||||||
<RefTableName>auth_user</RefTableName>
|
|
||||||
<RefColNames>id</RefColNames>
|
|
||||||
<Deferrable>1</Deferrable>
|
|
||||||
<InitiallyDeferred>1</InitiallyDeferred>
|
|
||||||
</foreign-key>
|
|
||||||
<foreign-key id="67" parent="8">
|
|
||||||
<ColNames>parent_id</ColNames>
|
|
||||||
<RefTableName>YtManagerApp_subscriptionfolder</RefTableName>
|
|
||||||
<RefColNames>id</RefColNames>
|
|
||||||
<Deferrable>1</Deferrable>
|
|
||||||
<InitiallyDeferred>1</InitiallyDeferred>
|
|
||||||
</foreign-key>
|
|
||||||
<column id="68" parent="9" name="id">
|
|
||||||
<Position>1</Position>
|
|
||||||
<DataType>integer|0s</DataType>
|
|
||||||
<NotNull>1</NotNull>
|
|
||||||
<SequenceIdentity>1</SequenceIdentity>
|
|
||||||
</column>
|
|
||||||
<column id="69" parent="9" name="delete_watched">
|
|
||||||
<Position>2</Position>
|
|
||||||
<DataType>bool|0s</DataType>
|
|
||||||
</column>
|
|
||||||
<column id="70" parent="9" name="auto_download">
|
|
||||||
<Position>3</Position>
|
|
||||||
<DataType>bool|0s</DataType>
|
|
||||||
</column>
|
|
||||||
<column id="71" parent="9" name="download_global_limit">
|
|
||||||
<Position>4</Position>
|
|
||||||
<DataType>integer|0s</DataType>
|
|
||||||
</column>
|
|
||||||
<column id="72" parent="9" name="download_subscription_limit">
|
|
||||||
<Position>5</Position>
|
|
||||||
<DataType>integer|0s</DataType>
|
|
||||||
</column>
|
|
||||||
<column id="73" parent="9" name="download_order">
|
|
||||||
<Position>6</Position>
|
|
||||||
<DataType>varchar(100)|0s</DataType>
|
|
||||||
</column>
|
|
||||||
<column id="74" parent="9" name="download_path">
|
|
||||||
<Position>7</Position>
|
|
||||||
<DataType>varchar(1024)|0s</DataType>
|
|
||||||
</column>
|
|
||||||
<column id="75" parent="9" name="download_file_pattern">
|
|
||||||
<Position>8</Position>
|
|
||||||
<DataType>varchar(1024)|0s</DataType>
|
|
||||||
</column>
|
|
||||||
<column id="76" parent="9" name="download_format">
|
|
||||||
<Position>9</Position>
|
|
||||||
<DataType>varchar(256)|0s</DataType>
|
|
||||||
</column>
|
|
||||||
<column id="77" parent="9" name="download_subtitles">
|
|
||||||
<Position>10</Position>
|
|
||||||
<DataType>bool|0s</DataType>
|
|
||||||
</column>
|
|
||||||
<column id="78" parent="9" name="download_autogenerated_subtitles">
|
|
||||||
<Position>11</Position>
|
|
||||||
<DataType>bool|0s</DataType>
|
|
||||||
</column>
|
|
||||||
<column id="79" parent="9" name="download_subtitles_all">
|
|
||||||
<Position>12</Position>
|
|
||||||
<DataType>bool|0s</DataType>
|
|
||||||
</column>
|
|
||||||
<column id="80" parent="9" name="download_subtitles_langs">
|
|
||||||
<Position>13</Position>
|
|
||||||
<DataType>varchar(250)|0s</DataType>
|
|
||||||
</column>
|
|
||||||
<column id="81" parent="9" name="download_subtitles_format">
|
|
||||||
<Position>14</Position>
|
|
||||||
<DataType>varchar(100)|0s</DataType>
|
|
||||||
</column>
|
|
||||||
<column id="82" parent="9" name="user_id">
|
|
||||||
<Position>15</Position>
|
|
||||||
<DataType>integer|0s</DataType>
|
|
||||||
<NotNull>1</NotNull>
|
|
||||||
</column>
|
|
||||||
<column id="83" parent="9" name="mark_deleted_as_watched">
|
|
||||||
<Position>16</Position>
|
|
||||||
<DataType>bool|0s</DataType>
|
|
||||||
</column>
|
|
||||||
<index id="84" parent="9" name="sqlite_autoindex_YtManagerApp_usersettings_1">
|
|
||||||
<NameSurrogate>1</NameSurrogate>
|
|
||||||
<ColNames>user_id</ColNames>
|
|
||||||
<ColumnCollations></ColumnCollations>
|
|
||||||
<Unique>1</Unique>
|
|
||||||
</index>
|
|
||||||
<key id="85" parent="9">
|
|
||||||
<ColNames>id</ColNames>
|
|
||||||
<Primary>1</Primary>
|
|
||||||
</key>
|
|
||||||
<key id="86" parent="9">
|
|
||||||
<ColNames>user_id</ColNames>
|
|
||||||
<UnderlyingIndexName>sqlite_autoindex_YtManagerApp_usersettings_1</UnderlyingIndexName>
|
|
||||||
</key>
|
|
||||||
<foreign-key id="87" parent="9">
|
|
||||||
<ColNames>user_id</ColNames>
|
|
||||||
<RefTableName>auth_user</RefTableName>
|
|
||||||
<RefColNames>id</RefColNames>
|
|
||||||
<Deferrable>1</Deferrable>
|
|
||||||
<InitiallyDeferred>1</InitiallyDeferred>
|
|
||||||
</foreign-key>
|
|
||||||
<column id="88" parent="10" name="id">
|
|
||||||
<Position>1</Position>
|
|
||||||
<DataType>integer|0s</DataType>
|
|
||||||
<NotNull>1</NotNull>
|
|
||||||
<SequenceIdentity>1</SequenceIdentity>
|
|
||||||
</column>
|
|
||||||
<column id="89" parent="10" name="video_id">
|
|
||||||
<Position>2</Position>
|
|
||||||
<DataType>text|0s</DataType>
|
|
||||||
<NotNull>1</NotNull>
|
|
||||||
</column>
|
|
||||||
<column id="90" parent="10" name="name">
|
|
||||||
<Position>3</Position>
|
|
||||||
<DataType>text|0s</DataType>
|
|
||||||
<NotNull>1</NotNull>
|
|
||||||
</column>
|
|
||||||
<column id="91" parent="10" name="description">
|
|
||||||
<Position>4</Position>
|
|
||||||
<DataType>text|0s</DataType>
|
|
||||||
<NotNull>1</NotNull>
|
|
||||||
</column>
|
|
||||||
<column id="92" parent="10" name="watched">
|
|
||||||
<Position>5</Position>
|
|
||||||
<DataType>bool|0s</DataType>
|
|
||||||
<NotNull>1</NotNull>
|
|
||||||
</column>
|
|
||||||
<column id="93" parent="10" name="downloaded_path">
|
|
||||||
<Position>6</Position>
|
|
||||||
<DataType>text|0s</DataType>
|
|
||||||
</column>
|
|
||||||
<column id="94" parent="10" name="playlist_index">
|
|
||||||
<Position>7</Position>
|
|
||||||
<DataType>integer|0s</DataType>
|
|
||||||
<NotNull>1</NotNull>
|
|
||||||
</column>
|
|
||||||
<column id="95" parent="10" name="publish_date">
|
|
||||||
<Position>8</Position>
|
|
||||||
<DataType>datetime|0s</DataType>
|
|
||||||
<NotNull>1</NotNull>
|
|
||||||
</column>
|
|
||||||
<column id="96" parent="10" name="icon_default">
|
|
||||||
<Position>9</Position>
|
|
||||||
<DataType>text|0s</DataType>
|
|
||||||
<NotNull>1</NotNull>
|
|
||||||
</column>
|
|
||||||
<column id="97" parent="10" name="icon_best">
|
|
||||||
<Position>10</Position>
|
|
||||||
<DataType>text|0s</DataType>
|
|
||||||
<NotNull>1</NotNull>
|
|
||||||
</column>
|
|
||||||
<column id="98" parent="10" name="subscription_id">
|
|
||||||
<Position>11</Position>
|
|
||||||
<DataType>integer|0s</DataType>
|
|
||||||
<NotNull>1</NotNull>
|
|
||||||
</column>
|
|
||||||
<column id="99" parent="10" name="rating">
|
|
||||||
<Position>12</Position>
|
|
||||||
<DataType>real|0s</DataType>
|
|
||||||
<NotNull>1</NotNull>
|
|
||||||
</column>
|
|
||||||
<column id="100" parent="10" name="uploader_name">
|
|
||||||
<Position>13</Position>
|
|
||||||
<DataType>text|0s</DataType>
|
|
||||||
<NotNull>1</NotNull>
|
|
||||||
</column>
|
|
||||||
<column id="101" parent="10" name="views">
|
|
||||||
<Position>14</Position>
|
|
||||||
<DataType>integer|0s</DataType>
|
|
||||||
<NotNull>1</NotNull>
|
|
||||||
</column>
|
|
||||||
<index id="102" parent="10" name="YtManagerApp_video_subscription_id_720d4227">
|
|
||||||
<ColNames>subscription_id</ColNames>
|
|
||||||
<ColumnCollations></ColumnCollations>
|
|
||||||
</index>
|
|
||||||
<key id="103" parent="10">
|
|
||||||
<ColNames>id</ColNames>
|
|
||||||
<Primary>1</Primary>
|
|
||||||
</key>
|
|
||||||
<foreign-key id="104" parent="10">
|
|
||||||
<ColNames>subscription_id</ColNames>
|
|
||||||
<RefTableName>YtManagerApp_subscription</RefTableName>
|
|
||||||
<RefColNames>id</RefColNames>
|
|
||||||
<Deferrable>1</Deferrable>
|
|
||||||
<InitiallyDeferred>1</InitiallyDeferred>
|
|
||||||
</foreign-key>
|
|
||||||
<column id="105" parent="11" name="id">
|
|
||||||
<Position>1</Position>
|
|
||||||
<DataType>integer|0s</DataType>
|
|
||||||
<NotNull>1</NotNull>
|
|
||||||
<SequenceIdentity>1</SequenceIdentity>
|
|
||||||
</column>
|
|
||||||
<column id="106" parent="11" name="name">
|
|
||||||
<Position>2</Position>
|
|
||||||
<DataType>varchar(80)|0s</DataType>
|
|
||||||
<NotNull>1</NotNull>
|
|
||||||
</column>
|
|
||||||
<index id="107" parent="11" name="sqlite_autoindex_auth_group_1">
|
|
||||||
<NameSurrogate>1</NameSurrogate>
|
|
||||||
<ColNames>name</ColNames>
|
|
||||||
<ColumnCollations></ColumnCollations>
|
|
||||||
<Unique>1</Unique>
|
|
||||||
</index>
|
|
||||||
<key id="108" parent="11">
|
|
||||||
<ColNames>id</ColNames>
|
|
||||||
<Primary>1</Primary>
|
|
||||||
</key>
|
|
||||||
<key id="109" parent="11">
|
|
||||||
<ColNames>name</ColNames>
|
|
||||||
<UnderlyingIndexName>sqlite_autoindex_auth_group_1</UnderlyingIndexName>
|
|
||||||
</key>
|
|
||||||
<column id="110" parent="12" name="id">
|
|
||||||
<Position>1</Position>
|
|
||||||
<DataType>integer|0s</DataType>
|
|
||||||
<NotNull>1</NotNull>
|
|
||||||
<SequenceIdentity>1</SequenceIdentity>
|
|
||||||
</column>
|
|
||||||
<column id="111" parent="12" name="group_id">
|
|
||||||
<Position>2</Position>
|
|
||||||
<DataType>integer|0s</DataType>
|
|
||||||
<NotNull>1</NotNull>
|
|
||||||
</column>
|
|
||||||
<column id="112" parent="12" name="permission_id">
|
|
||||||
<Position>3</Position>
|
|
||||||
<DataType>integer|0s</DataType>
|
|
||||||
<NotNull>1</NotNull>
|
|
||||||
</column>
|
|
||||||
<index id="113" parent="12" name="auth_group_permissions_group_id_permission_id_0cd325b0_uniq">
|
|
||||||
<ColNames>group_id
|
|
||||||
permission_id</ColNames>
|
|
||||||
<ColumnCollations></ColumnCollations>
|
|
||||||
<Unique>1</Unique>
|
|
||||||
</index>
|
|
||||||
<index id="114" parent="12" name="auth_group_permissions_group_id_b120cbf9">
|
|
||||||
<ColNames>group_id</ColNames>
|
|
||||||
<ColumnCollations></ColumnCollations>
|
|
||||||
</index>
|
|
||||||
<index id="115" parent="12" name="auth_group_permissions_permission_id_84c5c92e">
|
|
||||||
<ColNames>permission_id</ColNames>
|
|
||||||
<ColumnCollations></ColumnCollations>
|
|
||||||
</index>
|
|
||||||
<key id="116" parent="12">
|
|
||||||
<ColNames>id</ColNames>
|
|
||||||
<Primary>1</Primary>
|
|
||||||
</key>
|
|
||||||
<foreign-key id="117" parent="12">
|
|
||||||
<ColNames>group_id</ColNames>
|
|
||||||
<RefTableName>auth_group</RefTableName>
|
|
||||||
<RefColNames>id</RefColNames>
|
|
||||||
<Deferrable>1</Deferrable>
|
|
||||||
<InitiallyDeferred>1</InitiallyDeferred>
|
|
||||||
</foreign-key>
|
|
||||||
<foreign-key id="118" parent="12">
|
|
||||||
<ColNames>permission_id</ColNames>
|
|
||||||
<RefTableName>auth_permission</RefTableName>
|
|
||||||
<RefColNames>id</RefColNames>
|
|
||||||
<Deferrable>1</Deferrable>
|
|
||||||
<InitiallyDeferred>1</InitiallyDeferred>
|
|
||||||
</foreign-key>
|
|
||||||
<column id="119" parent="13" name="id">
|
|
||||||
<Position>1</Position>
|
|
||||||
<DataType>integer|0s</DataType>
|
|
||||||
<NotNull>1</NotNull>
|
|
||||||
<SequenceIdentity>1</SequenceIdentity>
|
|
||||||
</column>
|
|
||||||
<column id="120" parent="13" name="content_type_id">
|
|
||||||
<Position>2</Position>
|
|
||||||
<DataType>integer|0s</DataType>
|
|
||||||
<NotNull>1</NotNull>
|
|
||||||
</column>
|
|
||||||
<column id="121" parent="13" name="codename">
|
|
||||||
<Position>3</Position>
|
|
||||||
<DataType>varchar(100)|0s</DataType>
|
|
||||||
<NotNull>1</NotNull>
|
|
||||||
</column>
|
|
||||||
<column id="122" parent="13" name="name">
|
|
||||||
<Position>4</Position>
|
|
||||||
<DataType>varchar(255)|0s</DataType>
|
|
||||||
<NotNull>1</NotNull>
|
|
||||||
</column>
|
|
||||||
<index id="123" parent="13" name="auth_permission_content_type_id_codename_01ab375a_uniq">
|
|
||||||
<ColNames>content_type_id
|
|
||||||
codename</ColNames>
|
|
||||||
<ColumnCollations></ColumnCollations>
|
|
||||||
<Unique>1</Unique>
|
|
||||||
</index>
|
|
||||||
<index id="124" parent="13" name="auth_permission_content_type_id_2f476e4b">
|
|
||||||
<ColNames>content_type_id</ColNames>
|
|
||||||
<ColumnCollations></ColumnCollations>
|
|
||||||
</index>
|
|
||||||
<key id="125" parent="13">
|
|
||||||
<ColNames>id</ColNames>
|
|
||||||
<Primary>1</Primary>
|
|
||||||
</key>
|
|
||||||
<foreign-key id="126" parent="13">
|
|
||||||
<ColNames>content_type_id</ColNames>
|
|
||||||
<RefTableName>django_content_type</RefTableName>
|
|
||||||
<RefColNames>id</RefColNames>
|
|
||||||
<Deferrable>1</Deferrable>
|
|
||||||
<InitiallyDeferred>1</InitiallyDeferred>
|
|
||||||
</foreign-key>
|
|
||||||
<column id="127" parent="14" name="id">
|
|
||||||
<Position>1</Position>
|
|
||||||
<DataType>integer|0s</DataType>
|
|
||||||
<NotNull>1</NotNull>
|
|
||||||
<SequenceIdentity>1</SequenceIdentity>
|
|
||||||
</column>
|
|
||||||
<column id="128" parent="14" name="password">
|
|
||||||
<Position>2</Position>
|
|
||||||
<DataType>varchar(128)|0s</DataType>
|
|
||||||
<NotNull>1</NotNull>
|
|
||||||
</column>
|
|
||||||
<column id="129" parent="14" name="last_login">
|
|
||||||
<Position>3</Position>
|
|
||||||
<DataType>datetime|0s</DataType>
|
|
||||||
</column>
|
|
||||||
<column id="130" parent="14" name="is_superuser">
|
|
||||||
<Position>4</Position>
|
|
||||||
<DataType>bool|0s</DataType>
|
|
||||||
<NotNull>1</NotNull>
|
|
||||||
</column>
|
|
||||||
<column id="131" parent="14" name="username">
|
|
||||||
<Position>5</Position>
|
|
||||||
<DataType>varchar(150)|0s</DataType>
|
|
||||||
<NotNull>1</NotNull>
|
|
||||||
</column>
|
|
||||||
<column id="132" parent="14" name="first_name">
|
|
||||||
<Position>6</Position>
|
|
||||||
<DataType>varchar(30)|0s</DataType>
|
|
||||||
<NotNull>1</NotNull>
|
|
||||||
</column>
|
|
||||||
<column id="133" parent="14" name="email">
|
|
||||||
<Position>7</Position>
|
|
||||||
<DataType>varchar(254)|0s</DataType>
|
|
||||||
<NotNull>1</NotNull>
|
|
||||||
</column>
|
|
||||||
<column id="134" parent="14" name="is_staff">
|
|
||||||
<Position>8</Position>
|
|
||||||
<DataType>bool|0s</DataType>
|
|
||||||
<NotNull>1</NotNull>
|
|
||||||
</column>
|
|
||||||
<column id="135" parent="14" name="is_active">
|
|
||||||
<Position>9</Position>
|
|
||||||
<DataType>bool|0s</DataType>
|
|
||||||
<NotNull>1</NotNull>
|
|
||||||
</column>
|
|
||||||
<column id="136" parent="14" name="date_joined">
|
|
||||||
<Position>10</Position>
|
|
||||||
<DataType>datetime|0s</DataType>
|
|
||||||
<NotNull>1</NotNull>
|
|
||||||
</column>
|
|
||||||
<column id="137" parent="14" name="last_name">
|
|
||||||
<Position>11</Position>
|
|
||||||
<DataType>varchar(150)|0s</DataType>
|
|
||||||
<NotNull>1</NotNull>
|
|
||||||
</column>
|
|
||||||
<index id="138" parent="14" name="sqlite_autoindex_auth_user_1">
|
|
||||||
<NameSurrogate>1</NameSurrogate>
|
|
||||||
<ColNames>username</ColNames>
|
|
||||||
<ColumnCollations></ColumnCollations>
|
|
||||||
<Unique>1</Unique>
|
|
||||||
</index>
|
|
||||||
<key id="139" parent="14">
|
|
||||||
<ColNames>id</ColNames>
|
|
||||||
<Primary>1</Primary>
|
|
||||||
</key>
|
|
||||||
<key id="140" parent="14">
|
|
||||||
<ColNames>username</ColNames>
|
|
||||||
<UnderlyingIndexName>sqlite_autoindex_auth_user_1</UnderlyingIndexName>
|
|
||||||
</key>
|
|
||||||
<column id="141" parent="15" name="id">
|
|
||||||
<Position>1</Position>
|
|
||||||
<DataType>integer|0s</DataType>
|
|
||||||
<NotNull>1</NotNull>
|
|
||||||
<SequenceIdentity>1</SequenceIdentity>
|
|
||||||
</column>
|
|
||||||
<column id="142" parent="15" name="user_id">
|
|
||||||
<Position>2</Position>
|
|
||||||
<DataType>integer|0s</DataType>
|
|
||||||
<NotNull>1</NotNull>
|
|
||||||
</column>
|
|
||||||
<column id="143" parent="15" name="group_id">
|
|
||||||
<Position>3</Position>
|
|
||||||
<DataType>integer|0s</DataType>
|
|
||||||
<NotNull>1</NotNull>
|
|
||||||
</column>
|
|
||||||
<index id="144" parent="15" name="auth_user_groups_user_id_group_id_94350c0c_uniq">
|
|
||||||
<ColNames>user_id
|
|
||||||
group_id</ColNames>
|
|
||||||
<ColumnCollations></ColumnCollations>
|
|
||||||
<Unique>1</Unique>
|
|
||||||
</index>
|
|
||||||
<index id="145" parent="15" name="auth_user_groups_user_id_6a12ed8b">
|
|
||||||
<ColNames>user_id</ColNames>
|
|
||||||
<ColumnCollations></ColumnCollations>
|
|
||||||
</index>
|
|
||||||
<index id="146" parent="15" name="auth_user_groups_group_id_97559544">
|
|
||||||
<ColNames>group_id</ColNames>
|
|
||||||
<ColumnCollations></ColumnCollations>
|
|
||||||
</index>
|
|
||||||
<key id="147" parent="15">
|
|
||||||
<ColNames>id</ColNames>
|
|
||||||
<Primary>1</Primary>
|
|
||||||
</key>
|
|
||||||
<foreign-key id="148" parent="15">
|
|
||||||
<ColNames>user_id</ColNames>
|
|
||||||
<RefTableName>auth_user</RefTableName>
|
|
||||||
<RefColNames>id</RefColNames>
|
|
||||||
<Deferrable>1</Deferrable>
|
|
||||||
<InitiallyDeferred>1</InitiallyDeferred>
|
|
||||||
</foreign-key>
|
|
||||||
<foreign-key id="149" parent="15">
|
|
||||||
<ColNames>group_id</ColNames>
|
|
||||||
<RefTableName>auth_group</RefTableName>
|
|
||||||
<RefColNames>id</RefColNames>
|
|
||||||
<Deferrable>1</Deferrable>
|
|
||||||
<InitiallyDeferred>1</InitiallyDeferred>
|
|
||||||
</foreign-key>
|
|
||||||
<column id="150" parent="16" name="id">
|
|
||||||
<Position>1</Position>
|
|
||||||
<DataType>integer|0s</DataType>
|
|
||||||
<NotNull>1</NotNull>
|
|
||||||
<SequenceIdentity>1</SequenceIdentity>
|
|
||||||
</column>
|
|
||||||
<column id="151" parent="16" name="user_id">
|
|
||||||
<Position>2</Position>
|
|
||||||
<DataType>integer|0s</DataType>
|
|
||||||
<NotNull>1</NotNull>
|
|
||||||
</column>
|
|
||||||
<column id="152" parent="16" name="permission_id">
|
|
||||||
<Position>3</Position>
|
|
||||||
<DataType>integer|0s</DataType>
|
|
||||||
<NotNull>1</NotNull>
|
|
||||||
</column>
|
|
||||||
<index id="153" parent="16" name="auth_user_user_permissions_user_id_permission_id_14a6b632_uniq">
|
|
||||||
<ColNames>user_id
|
|
||||||
permission_id</ColNames>
|
|
||||||
<ColumnCollations></ColumnCollations>
|
|
||||||
<Unique>1</Unique>
|
|
||||||
</index>
|
|
||||||
<index id="154" parent="16" name="auth_user_user_permissions_user_id_a95ead1b">
|
|
||||||
<ColNames>user_id</ColNames>
|
|
||||||
<ColumnCollations></ColumnCollations>
|
|
||||||
</index>
|
|
||||||
<index id="155" parent="16" name="auth_user_user_permissions_permission_id_1fbb5f2c">
|
|
||||||
<ColNames>permission_id</ColNames>
|
|
||||||
<ColumnCollations></ColumnCollations>
|
|
||||||
</index>
|
|
||||||
<key id="156" parent="16">
|
|
||||||
<ColNames>id</ColNames>
|
|
||||||
<Primary>1</Primary>
|
|
||||||
</key>
|
|
||||||
<foreign-key id="157" parent="16">
|
|
||||||
<ColNames>user_id</ColNames>
|
|
||||||
<RefTableName>auth_user</RefTableName>
|
|
||||||
<RefColNames>id</RefColNames>
|
|
||||||
<Deferrable>1</Deferrable>
|
|
||||||
<InitiallyDeferred>1</InitiallyDeferred>
|
|
||||||
</foreign-key>
|
|
||||||
<foreign-key id="158" parent="16">
|
|
||||||
<ColNames>permission_id</ColNames>
|
|
||||||
<RefTableName>auth_permission</RefTableName>
|
|
||||||
<RefColNames>id</RefColNames>
|
|
||||||
<Deferrable>1</Deferrable>
|
|
||||||
<InitiallyDeferred>1</InitiallyDeferred>
|
|
||||||
</foreign-key>
|
|
||||||
<column id="159" parent="17" name="id">
|
|
||||||
<Position>1</Position>
|
|
||||||
<DataType>integer|0s</DataType>
|
|
||||||
<NotNull>1</NotNull>
|
|
||||||
<SequenceIdentity>1</SequenceIdentity>
|
|
||||||
</column>
|
|
||||||
<column id="160" parent="17" name="action_time">
|
|
||||||
<Position>2</Position>
|
|
||||||
<DataType>datetime|0s</DataType>
|
|
||||||
<NotNull>1</NotNull>
|
|
||||||
</column>
|
|
||||||
<column id="161" parent="17" name="object_id">
|
|
||||||
<Position>3</Position>
|
|
||||||
<DataType>text|0s</DataType>
|
|
||||||
</column>
|
|
||||||
<column id="162" parent="17" name="object_repr">
|
|
||||||
<Position>4</Position>
|
|
||||||
<DataType>varchar(200)|0s</DataType>
|
|
||||||
<NotNull>1</NotNull>
|
|
||||||
</column>
|
|
||||||
<column id="163" parent="17" name="change_message">
|
|
||||||
<Position>5</Position>
|
|
||||||
<DataType>text|0s</DataType>
|
|
||||||
<NotNull>1</NotNull>
|
|
||||||
</column>
|
|
||||||
<column id="164" parent="17" name="content_type_id">
|
|
||||||
<Position>6</Position>
|
|
||||||
<DataType>integer|0s</DataType>
|
|
||||||
</column>
|
|
||||||
<column id="165" parent="17" name="user_id">
|
|
||||||
<Position>7</Position>
|
|
||||||
<DataType>integer|0s</DataType>
|
|
||||||
<NotNull>1</NotNull>
|
|
||||||
</column>
|
|
||||||
<column id="166" parent="17" name="action_flag">
|
|
||||||
<Position>8</Position>
|
|
||||||
<DataType>smallint unsigned|0s</DataType>
|
|
||||||
<NotNull>1</NotNull>
|
|
||||||
</column>
|
|
||||||
<index id="167" parent="17" name="django_admin_log_content_type_id_c4bce8eb">
|
|
||||||
<ColNames>content_type_id</ColNames>
|
|
||||||
<ColumnCollations></ColumnCollations>
|
|
||||||
</index>
|
|
||||||
<index id="168" parent="17" name="django_admin_log_user_id_c564eba6">
|
|
||||||
<ColNames>user_id</ColNames>
|
|
||||||
<ColumnCollations></ColumnCollations>
|
|
||||||
</index>
|
|
||||||
<key id="169" parent="17">
|
|
||||||
<ColNames>id</ColNames>
|
|
||||||
<Primary>1</Primary>
|
|
||||||
</key>
|
|
||||||
<foreign-key id="170" parent="17">
|
|
||||||
<ColNames>content_type_id</ColNames>
|
|
||||||
<RefTableName>django_content_type</RefTableName>
|
|
||||||
<RefColNames>id</RefColNames>
|
|
||||||
<Deferrable>1</Deferrable>
|
|
||||||
<InitiallyDeferred>1</InitiallyDeferred>
|
|
||||||
</foreign-key>
|
|
||||||
<foreign-key id="171" parent="17">
|
|
||||||
<ColNames>user_id</ColNames>
|
|
||||||
<RefTableName>auth_user</RefTableName>
|
|
||||||
<RefColNames>id</RefColNames>
|
|
||||||
<Deferrable>1</Deferrable>
|
|
||||||
<InitiallyDeferred>1</InitiallyDeferred>
|
|
||||||
</foreign-key>
|
|
||||||
<column id="172" parent="18" name="id">
|
|
||||||
<Position>1</Position>
|
|
||||||
<DataType>integer|0s</DataType>
|
|
||||||
<NotNull>1</NotNull>
|
|
||||||
<SequenceIdentity>1</SequenceIdentity>
|
|
||||||
</column>
|
|
||||||
<column id="173" parent="18" name="app_label">
|
|
||||||
<Position>2</Position>
|
|
||||||
<DataType>varchar(100)|0s</DataType>
|
|
||||||
<NotNull>1</NotNull>
|
|
||||||
</column>
|
|
||||||
<column id="174" parent="18" name="model">
|
|
||||||
<Position>3</Position>
|
|
||||||
<DataType>varchar(100)|0s</DataType>
|
|
||||||
<NotNull>1</NotNull>
|
|
||||||
</column>
|
|
||||||
<index id="175" parent="18" name="django_content_type_app_label_model_76bd3d3b_uniq">
|
|
||||||
<ColNames>app_label
|
|
||||||
model</ColNames>
|
|
||||||
<ColumnCollations></ColumnCollations>
|
|
||||||
<Unique>1</Unique>
|
|
||||||
</index>
|
|
||||||
<key id="176" parent="18">
|
|
||||||
<ColNames>id</ColNames>
|
|
||||||
<Primary>1</Primary>
|
|
||||||
</key>
|
|
||||||
<column id="177" parent="19" name="id">
|
|
||||||
<Position>1</Position>
|
|
||||||
<DataType>integer|0s</DataType>
|
|
||||||
<NotNull>1</NotNull>
|
|
||||||
<SequenceIdentity>1</SequenceIdentity>
|
|
||||||
</column>
|
|
||||||
<column id="178" parent="19" name="app">
|
|
||||||
<Position>2</Position>
|
|
||||||
<DataType>varchar(255)|0s</DataType>
|
|
||||||
<NotNull>1</NotNull>
|
|
||||||
</column>
|
|
||||||
<column id="179" parent="19" name="name">
|
|
||||||
<Position>3</Position>
|
|
||||||
<DataType>varchar(255)|0s</DataType>
|
|
||||||
<NotNull>1</NotNull>
|
|
||||||
</column>
|
|
||||||
<column id="180" parent="19" name="applied">
|
|
||||||
<Position>4</Position>
|
|
||||||
<DataType>datetime|0s</DataType>
|
|
||||||
<NotNull>1</NotNull>
|
|
||||||
</column>
|
|
||||||
<key id="181" parent="19">
|
|
||||||
<ColNames>id</ColNames>
|
|
||||||
<Primary>1</Primary>
|
|
||||||
</key>
|
|
||||||
<column id="182" parent="20" name="session_key">
|
|
||||||
<Position>1</Position>
|
|
||||||
<DataType>varchar(40)|0s</DataType>
|
|
||||||
<NotNull>1</NotNull>
|
|
||||||
</column>
|
|
||||||
<column id="183" parent="20" name="session_data">
|
|
||||||
<Position>2</Position>
|
|
||||||
<DataType>text|0s</DataType>
|
|
||||||
<NotNull>1</NotNull>
|
|
||||||
</column>
|
|
||||||
<column id="184" parent="20" name="expire_date">
|
|
||||||
<Position>3</Position>
|
|
||||||
<DataType>datetime|0s</DataType>
|
|
||||||
<NotNull>1</NotNull>
|
|
||||||
</column>
|
|
||||||
<index id="185" parent="20" name="sqlite_autoindex_django_session_1">
|
|
||||||
<NameSurrogate>1</NameSurrogate>
|
|
||||||
<ColNames>session_key</ColNames>
|
|
||||||
<ColumnCollations></ColumnCollations>
|
|
||||||
<Unique>1</Unique>
|
|
||||||
</index>
|
|
||||||
<index id="186" parent="20" name="django_session_expire_date_a5c62663">
|
|
||||||
<ColNames>expire_date</ColNames>
|
|
||||||
<ColumnCollations></ColumnCollations>
|
|
||||||
</index>
|
|
||||||
<key id="187" parent="20">
|
|
||||||
<ColNames>session_key</ColNames>
|
|
||||||
<Primary>1</Primary>
|
|
||||||
<UnderlyingIndexName>sqlite_autoindex_django_session_1</UnderlyingIndexName>
|
|
||||||
</key>
|
|
||||||
<column id="188" parent="21" name="type">
|
|
||||||
<Position>1</Position>
|
|
||||||
<DataType>text|0s</DataType>
|
|
||||||
</column>
|
|
||||||
<column id="189" parent="21" name="name">
|
|
||||||
<Position>2</Position>
|
|
||||||
<DataType>text|0s</DataType>
|
|
||||||
</column>
|
|
||||||
<column id="190" parent="21" name="tbl_name">
|
|
||||||
<Position>3</Position>
|
|
||||||
<DataType>text|0s</DataType>
|
|
||||||
</column>
|
|
||||||
<column id="191" parent="21" name="rootpage">
|
|
||||||
<Position>4</Position>
|
|
||||||
<DataType>int|0s</DataType>
|
|
||||||
</column>
|
|
||||||
<column id="192" parent="21" name="sql">
|
|
||||||
<Position>5</Position>
|
|
||||||
<DataType>text|0s</DataType>
|
|
||||||
</column>
|
|
||||||
<column id="193" parent="22" name="name">
|
|
||||||
<Position>1</Position>
|
|
||||||
</column>
|
|
||||||
<column id="194" parent="22" name="seq">
|
|
||||||
<Position>2</Position>
|
|
||||||
</column>
|
|
||||||
</database-model>
|
|
||||||
</dataSource>
|
|
@ -1,2 +0,0 @@
|
|||||||
#n:main
|
|
||||||
!<md> [0, 0, null, null, -2147483648, -2147483648]
|
|
@ -1,6 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project version="4">
|
|
||||||
<component name="JavaScriptLibraryMappings">
|
|
||||||
<file url="file://$PROJECT_DIR$" libraries="{bootstrap, jquery-3.3.1, jstree, popper}" />
|
|
||||||
</component>
|
|
||||||
</project>
|
|
@ -1,7 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project version="4">
|
|
||||||
<component name="JavaScriptSettings">
|
|
||||||
<option name="languageLevel" value="ES6" />
|
|
||||||
</component>
|
|
||||||
<component name="ProjectRootManager" version="2" project-jdk-name="Python 3.6" project-jdk-type="Python SDK" />
|
|
||||||
</project>
|
|
@ -1,8 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project version="4">
|
|
||||||
<component name="ProjectModuleManager">
|
|
||||||
<modules>
|
|
||||||
<module fileurl="file://$PROJECT_DIR$/.idea/youtube-channel-manager.iml" filepath="$PROJECT_DIR$/.idea/youtube-channel-manager.iml" />
|
|
||||||
</modules>
|
|
||||||
</component>
|
|
||||||
</project>
|
|
@ -1,6 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project version="4">
|
|
||||||
<component name="VcsDirectoryMappings">
|
|
||||||
<mapping directory="$PROJECT_DIR$" vcs="Git" />
|
|
||||||
</component>
|
|
||||||
</project>
|
|
@ -1,51 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project version="4">
|
|
||||||
<component name="ProjectTasksOptions">
|
|
||||||
<TaskOptions isEnabled="true">
|
|
||||||
<option name="arguments" value="$FileName$ $FileNameWithoutExtension$.css --source-map" />
|
|
||||||
<option name="checkSyntaxErrors" value="true" />
|
|
||||||
<option name="description" />
|
|
||||||
<option name="exitCodeBehavior" value="ERROR" />
|
|
||||||
<option name="fileExtension" value="less" />
|
|
||||||
<option name="immediateSync" value="true" />
|
|
||||||
<option name="name" value="Less" />
|
|
||||||
<option name="output" value="$FileNameWithoutExtension$.css:$FileNameWithoutExtension$.css.map" />
|
|
||||||
<option name="outputFilters">
|
|
||||||
<array>
|
|
||||||
<FilterInfo>
|
|
||||||
<option name="description" value="" />
|
|
||||||
<option name="name" value="" />
|
|
||||||
<option name="regExp" value="$MESSAGE$\Q in \E$FILE_PATH$\Q on line \E$LINE$\Q, column \E$COLUMN$" />
|
|
||||||
</FilterInfo>
|
|
||||||
</array>
|
|
||||||
</option>
|
|
||||||
<option name="outputFromStdout" value="false" />
|
|
||||||
<option name="program" value="$USER_HOME$/AppData/Roaming/npm/lessc.cmd" />
|
|
||||||
<option name="runOnExternalChanges" value="true" />
|
|
||||||
<option name="scopeName" value="Project Files" />
|
|
||||||
<option name="trackOnlyRoot" value="true" />
|
|
||||||
<option name="workingDir" value="$FileDir$" />
|
|
||||||
<envs />
|
|
||||||
</TaskOptions>
|
|
||||||
<TaskOptions isEnabled="true">
|
|
||||||
<option name="arguments" value="--no-cache --update $FileName$:$FileNameWithoutExtension$.css" />
|
|
||||||
<option name="checkSyntaxErrors" value="true" />
|
|
||||||
<option name="description" />
|
|
||||||
<option name="exitCodeBehavior" value="ERROR" />
|
|
||||||
<option name="fileExtension" value="scss" />
|
|
||||||
<option name="immediateSync" value="true" />
|
|
||||||
<option name="name" value="SCSS" />
|
|
||||||
<option name="output" value="$FileNameWithoutExtension$.css:$FileNameWithoutExtension$.css.map" />
|
|
||||||
<option name="outputFilters">
|
|
||||||
<array />
|
|
||||||
</option>
|
|
||||||
<option name="outputFromStdout" value="false" />
|
|
||||||
<option name="program" value="scss" />
|
|
||||||
<option name="runOnExternalChanges" value="true" />
|
|
||||||
<option name="scopeName" value="Project Files" />
|
|
||||||
<option name="trackOnlyRoot" value="true" />
|
|
||||||
<option name="workingDir" value="$FileDir$" />
|
|
||||||
<envs />
|
|
||||||
</TaskOptions>
|
|
||||||
</component>
|
|
||||||
</project>
|
|
1033
.idea/workspace.xml
1033
.idea/workspace.xml
File diff suppressed because it is too large
Load Diff
@ -1,38 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<module type="PYTHON_MODULE" version="4">
|
|
||||||
<component name="FacetManager">
|
|
||||||
<facet type="django" name="Django">
|
|
||||||
<configuration>
|
|
||||||
<option name="rootFolder" value="$MODULE_DIR$" />
|
|
||||||
<option name="settingsModule" value="YtManager/settings.py" />
|
|
||||||
<option name="manageScript" value="$MODULE_DIR$/manage.py" />
|
|
||||||
<option name="environment" value="<map/>" />
|
|
||||||
<option name="doNotUseTestRunner" value="false" />
|
|
||||||
<option name="trackFilePattern" value="migrations" />
|
|
||||||
</configuration>
|
|
||||||
</facet>
|
|
||||||
</component>
|
|
||||||
<component name="NewModuleRootManager">
|
|
||||||
<content url="file://$MODULE_DIR$" />
|
|
||||||
<orderEntry type="jdk" jdkName="Python 3.6" jdkType="Python SDK" />
|
|
||||||
<orderEntry type="sourceFolder" forTests="false" />
|
|
||||||
<orderEntry type="library" name="jquery-3.3.1" level="application" />
|
|
||||||
<orderEntry type="library" name="popper" level="application" />
|
|
||||||
<orderEntry type="library" name="bootstrap" level="application" />
|
|
||||||
<orderEntry type="library" name="popper" level="application" />
|
|
||||||
<orderEntry type="library" name="jquery-3.3.1" level="application" />
|
|
||||||
<orderEntry type="library" name="bootstrap" level="application" />
|
|
||||||
<orderEntry type="library" name="jstree" level="application" />
|
|
||||||
</component>
|
|
||||||
<component name="TemplatesService">
|
|
||||||
<option name="TEMPLATE_CONFIGURATION" value="Django" />
|
|
||||||
<option name="TEMPLATE_FOLDERS">
|
|
||||||
<list>
|
|
||||||
<option value="$MODULE_DIR$/YtManagerApp/templates" />
|
|
||||||
</list>
|
|
||||||
</option>
|
|
||||||
</component>
|
|
||||||
<component name="TestRunnerService">
|
|
||||||
<option name="PROJECT_TEST_RUNNER" value="Unittests" />
|
|
||||||
</component>
|
|
||||||
</module>
|
|
24
Dockerfile
24
Dockerfile
@ -1,27 +1,23 @@
|
|||||||
FROM python:3
|
FROM python:3
|
||||||
|
|
||||||
WORKDIR /usr/src/app
|
WORKDIR /usr/src/ytsm/app
|
||||||
|
|
||||||
|
# ffmpeg is needed for youtube-dl
|
||||||
RUN apt-get update
|
RUN apt-get update
|
||||||
RUN apt-get install ffmpeg -y
|
RUN apt-get install ffmpeg -y
|
||||||
|
|
||||||
COPY ./app/requirements.txt ./
|
COPY ./requirements.txt ./
|
||||||
RUN pip install --no-cache-dir -r requirements.txt
|
RUN pip install --no-cache-dir -r requirements.txt
|
||||||
|
|
||||||
ENV YTSM_DATABASE_ENGINE='django.db.backends.sqlite3'
|
ENV YTSM_DEBUG='False'
|
||||||
ENV YTSM_DATABASE_NAME='/usr/src/app/data/db/ytmanager.db'
|
ENV YTSM_DATA_PATH='/usr/src/ytsm/data'
|
||||||
ENV YTSM_DATABASE_HOST=''
|
|
||||||
ENV YTSM_DATABASE_USERNAME=''
|
|
||||||
ENV YTSM_DATABASE_PASSWORD=''
|
|
||||||
ENV YTSM_DATABASE_PORT=''
|
|
||||||
ENV YTSM_YOUTUBE_API_KEY='AIzaSyBabzE4Bup77WexdLMa9rN9z-wJidEfNX8'
|
|
||||||
|
|
||||||
VOLUME /usr/src/app/data/media
|
VOLUME /usr/src/ytsm/config
|
||||||
VOLUME /usr/src/app/data/db
|
VOLUME /usr/src/ytsm/data
|
||||||
|
|
||||||
COPY ./app/ .
|
COPY ./app/ ./
|
||||||
COPY ./config/ ./config/
|
COPY ./docker/init.sh ./
|
||||||
|
|
||||||
EXPOSE 8000
|
EXPOSE 8000
|
||||||
|
|
||||||
CMD ["/bin/bash", "init.sh"]
|
CMD ["/bin/bash", "init.sh"]
|
||||||
|
105
README.md
105
README.md
@ -24,8 +24,10 @@ Of course, there are a lot of things that still need to be done. The web interfa
|
|||||||
|
|
||||||
* python3: `$ apt install python3`
|
* python3: `$ apt install python3`
|
||||||
* pip: `$ apt install python3-pip`
|
* pip: `$ apt install python3-pip`
|
||||||
|
* ffmpeg: `$ apt install ffmpeg`
|
||||||
* django: `$ pip3 install django`
|
* django: `$ pip3 install django`
|
||||||
* crispy_forms: `$ pip3 install django-crispy-forms`
|
* crispy_forms: `$ pip3 install django-crispy-forms`
|
||||||
|
* dj-config-url: `$ pip3 install dj-config-url`
|
||||||
* youtube-dl: `$ pip3 install youtube-dl`
|
* youtube-dl: `$ pip3 install youtube-dl`
|
||||||
* google-api-python-client: `$ pip3 install google-api-python-client`
|
* google-api-python-client: `$ pip3 install google-api-python-client`
|
||||||
* google_auth_oauthlib: `$ pip3 install google_auth_oauthlib`
|
* google_auth_oauthlib: `$ pip3 install google_auth_oauthlib`
|
||||||
@ -34,65 +36,104 @@ Of course, there are a lot of things that still need to be done. The web interfa
|
|||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
|
|
||||||
|
There are 2 ways you can install this server. Using docker is the quickest and easiest method.
|
||||||
|
|
||||||
### Normal installation for development/testing
|
### Normal installation for development/testing
|
||||||
|
|
||||||
1. Install all the dependencies listed above.
|
1. Clone this repository:
|
||||||
|
|
||||||
```bash
|
|
||||||
sudo apt install python3 python3-pip
|
|
||||||
sudo pip3 install apscheduler django django-crispy-forms youtube-dl google-api-python-client google_auth_oauthlib oauth2client
|
|
||||||
```
|
|
||||||
|
|
||||||
2. Clone this repository:
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
git clone https://github.com/chibicitiberiu/ytsm.git
|
git clone https://github.com/chibicitiberiu/ytsm.git
|
||||||
cd ytsm
|
cd ytsm
|
||||||
```
|
```
|
||||||
|
|
||||||
3. Set up the database: `python3 manage.py migrate`
|
2. Install all the dependencies listed above.
|
||||||
|
|
||||||
By default, a SQLite database is used, which is located in the project's folder.
|
|
||||||
You can customize that in `YtManager/settings.py`, by modifying the `DATABASES` variable (search Django documentation for details).
|
|
||||||
|
|
||||||
4. Set up the `MEDIA_ROOT` variable in `YtManager/settings.py`. This is where the thumbnails will be downloaded.
|
|
||||||
(note: this will be moved to `config.ini` in the future).
|
|
||||||
|
|
||||||
5. Obtain an YouTube API developer key from [https://console.developers.google.com/apis/dashboard](https://console.developers.google.com/apis/dashboard).
|
```bash
|
||||||
|
sudo apt install python3 python3-pip ffmpeg
|
||||||
|
sudo pip3 install --no-cache-dir -r requirements.txt
|
||||||
|
```
|
||||||
|
|
||||||
|
3. Modify `config/config.ini` to your liking. All the settings should be documented through comments.
|
||||||
|
All these settings apply server-wide. The settings in the `user` section can be overriden from the web page for each
|
||||||
|
individual user.
|
||||||
|
|
||||||
|
4. Obtain an YouTube API developer key from [https://console.developers.google.com/apis/dashboard](https://console.developers.google.com/apis/dashboard).
|
||||||
You can find a detailed guide on [this page](https://www.slickremix.com/docs/get-api-key-for-youtube/).
|
You can find a detailed guide on [this page](https://www.slickremix.com/docs/get-api-key-for-youtube/).
|
||||||
|
|
||||||
The `defaults.ini` file already has an API key, but if the quotas are reached, you won't be able to use this program
|
The `defaults.ini` file already has an API key, but if the quotas are reached, you won't be able to use this program
|
||||||
any more. Also, I might decide to delete that key, which will break your installation.
|
any more. Also, I might decide to delete that key, which will break your installation.
|
||||||
|
|
||||||
|
After obtaining the key, set it in `config.ini`.
|
||||||
|
|
||||||
6. Modify `config/config.ini` to your liking. All the settings should be documented through comments.
|
5. Set up the database:
|
||||||
All these settings apply server-wide. The settings in the `user` section can be overriden from the web page for each
|
|
||||||
individual user.
|
|
||||||
|
|
||||||
The most important settings are:
|
```bash
|
||||||
|
cd app
|
||||||
* `[Global] YoutubeApiKey` - put your YouTube API key here
|
python3 manage.py migrate
|
||||||
* `[User] DownloadPath` - sets the folder where videos will be downloaded
|
```
|
||||||
|
|
||||||
7. Start the server: `python3 manage.py runserver [port] --noreload`
|
By default, a SQLite database is used, which is located in the project's folder. The database can be configured
|
||||||
|
in `settings.ini`.
|
||||||
|
|
||||||
|
6. Start the server: `python3 manage.py runserver [port] --noreload --insecure`
|
||||||
|
|
||||||
The `port` parameter is optional.
|
The `port` parameter is optional.
|
||||||
|
|
||||||
The `--noreload` option is necessary, otherwise the scheduler will run on 2 separate processes at the same time,
|
The `--noreload` option is necessary, otherwise the scheduler will run on 2 separate processes at the same time,
|
||||||
which is not ideal.
|
which is not ideal.
|
||||||
|
|
||||||
|
The `--insecure` option is required only if `Debug=False` in `config.ini`, Without this option, the static resources
|
||||||
|
(CSS, javascript) won't work.
|
||||||
|
|
||||||
8. Open the server's page in your browser, by entering `http://localhost:port` in your address bar.
|
7. Open the server's page in your browser, by entering `http://localhost:port` in your address bar.
|
||||||
|
|
||||||
9. Create an admin user by going to the *register* page, and creating an user account.
|
8. Create an admin user by going to the *register* page, and creating an user account.
|
||||||
|
|
||||||
10. Add some subscriptions, and enjoy!
|
9. Add some subscriptions, and enjoy!
|
||||||
|
|
||||||
### Docker
|
### Docker
|
||||||
|
|
||||||
A much easier way to install is to use Docker.
|
1. Clone this repository:
|
||||||
|
|
||||||
To run with docker, edit the config file (config/config.ini) and then run `docker-compose up -d`, it will bind to port 80.
|
```bash
|
||||||
|
git clone https://github.com/chibicitiberiu/ytsm.git
|
||||||
|
cd ytsm
|
||||||
|
```
|
||||||
|
|
||||||
You can edit the default download locations in the docker-compose.yml file.
|
2. Install docker (if not installed)
|
||||||
|
|
||||||
|
3. Modify `config/config.ini` to your liking. All the settings should be documented through comments.
|
||||||
|
All these settings apply server-wide. The settings in the `user` section can be overriden from the web page for each
|
||||||
|
individual user.
|
||||||
|
|
||||||
|
**Attention**: you cannot modify the download location from `settings.ini` when using docker.
|
||||||
|
To do so, you will need to modify the volume mapping in `docker-compose.yml`.
|
||||||
|
|
||||||
|
4. Obtain an YouTube API developer key from [https://console.developers.google.com/apis/dashboard](https://console.developers.google.com/apis/dashboard).
|
||||||
|
You can find a detailed guide on [this page](https://www.slickremix.com/docs/get-api-key-for-youtube/).
|
||||||
|
|
||||||
|
The `defaults.ini` file already has an API key, but if the quotas are reached, you won't be able to use this program
|
||||||
|
any more. Also, I might decide to delete that key, which will break your installation.
|
||||||
|
|
||||||
|
After obtaining the key, set it in `config.ini`.
|
||||||
|
|
||||||
|
5. Build and run docker compose image:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker-compose up -d
|
||||||
|
```
|
||||||
|
|
||||||
|
6. Open the server's page in your browser, by entering `http://localhost` in your address bar.
|
||||||
|
|
||||||
|
7. Create an admin user by going to the *register* page, and creating an user account.
|
||||||
|
|
||||||
|
8. Add some subscriptions, and enjoy!
|
||||||
|
|
||||||
|
The docker image uses a sqlite database, and stores the data in a folder `data/` located in the project directory.
|
||||||
|
You can edit the default download locations in the `docker-compose.yml` file.
|
||||||
|
|
||||||
|
For more information about using Docker, check [this page](Docker_README.md).
|
||||||
|
|
||||||
### Deploying for production
|
### Deploying for production
|
||||||
|
|
||||||
|
@ -11,23 +11,13 @@ https://docs.djangoproject.com/en/1.11/ref/settings/
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
import os
|
import os
|
||||||
|
import logging
|
||||||
|
from os.path import dirname as up
|
||||||
|
|
||||||
# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
|
#
|
||||||
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
# Basic Django stuff
|
||||||
|
#
|
||||||
# Quick-start development settings - unsuitable for production
|
|
||||||
# See https://docs.djangoproject.com/en/1.11/howto/deployment/checklist/
|
|
||||||
|
|
||||||
# SECURITY WARNING: keep the secret key used in production secret!
|
|
||||||
SECRET_KEY = '^zv8@i2h!ko2lo=%ivq(9e#x=%q*i^^)6#4@(juzdx%&0c+9a0'
|
|
||||||
|
|
||||||
YOUTUBE_API_KEY = os.getenv('YTSM_YOUTUBE_API_KEY', 'AIzaSyBabzE4Bup77WexdLMa9rN9z-wJidEfNX8')
|
|
||||||
|
|
||||||
# SECURITY WARNING: don't run with debug turned on in production!
|
|
||||||
DEBUG = True
|
|
||||||
|
|
||||||
ALLOWED_HOSTS = ['*']
|
ALLOWED_HOSTS = ['*']
|
||||||
|
|
||||||
SESSION_COOKIE_AGE = 3600 * 30 # one month
|
SESSION_COOKIE_AGE = 3600 * 30 # one month
|
||||||
|
|
||||||
# Application definition
|
# Application definition
|
||||||
@ -76,24 +66,6 @@ TEMPLATES = [
|
|||||||
WSGI_APPLICATION = 'YtManager.wsgi.application'
|
WSGI_APPLICATION = 'YtManager.wsgi.application'
|
||||||
|
|
||||||
|
|
||||||
# Database
|
|
||||||
# https://docs.djangoproject.com/en/1.11/ref/settings/#databases
|
|
||||||
|
|
||||||
DATABASES = {
|
|
||||||
'default': {
|
|
||||||
'ENGINE': os.getenv('YTSM_DATABASE_ENGINE', 'django.db.backends.sqlite3'),
|
|
||||||
'NAME': os.getenv('YTSM_DATABASE_NAME', os.path.join(BASE_DIR, 'ytmanager.db')),
|
|
||||||
'HOST': os.getenv('YTSM_DATABASE_HOST', None),
|
|
||||||
'USER': os.getenv('YTSM_DATABASE_USERNAME', None),
|
|
||||||
'PASSWORD': os.getenv('YTSM_DATABASE_PASSWORD', None),
|
|
||||||
'PORT': os.getenv('YTSM_DATABASE_PORT', None)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if os.getenv('YTSM_DATABASE_URL', None):
|
|
||||||
import dj_database_url
|
|
||||||
DATABASES['default'] = dj_database_url.parse(os.environ['YTSM_DATABASE_URL'], conn_max_age=600)
|
|
||||||
|
|
||||||
# Password validation
|
# Password validation
|
||||||
# https://docs.djangoproject.com/en/1.11/ref/settings/#auth-password-validators
|
# https://docs.djangoproject.com/en/1.11/ref/settings/#auth-password-validators
|
||||||
|
|
||||||
@ -112,6 +84,9 @@ AUTH_PASSWORD_VALIDATORS = [
|
|||||||
},
|
},
|
||||||
]
|
]
|
||||||
|
|
||||||
|
LOGIN_REDIRECT_URL = '/'
|
||||||
|
LOGIN_URL = '/login'
|
||||||
|
|
||||||
|
|
||||||
# Internationalization
|
# Internationalization
|
||||||
# https://docs.djangoproject.com/en/1.11/topics/i18n/
|
# https://docs.djangoproject.com/en/1.11/topics/i18n/
|
||||||
@ -126,14 +101,126 @@ USE_L10N = True
|
|||||||
|
|
||||||
USE_TZ = True
|
USE_TZ = True
|
||||||
|
|
||||||
|
|
||||||
# Static files (CSS, JavaScript, Images)
|
# Static files (CSS, JavaScript, Images)
|
||||||
# https://docs.djangoproject.com/en/1.11/howto/static-files/
|
# https://docs.djangoproject.com/en/1.11/howto/static-files/
|
||||||
|
|
||||||
STATIC_URL = '/static/'
|
STATIC_URL = '/static/'
|
||||||
MEDIA_URL = '/media/'
|
MEDIA_URL = '/media/'
|
||||||
MEDIA_ROOT = 'data/media'
|
|
||||||
|
|
||||||
|
# Misc Django stuff
|
||||||
|
|
||||||
CRISPY_TEMPLATE_PACK = 'bootstrap4'
|
CRISPY_TEMPLATE_PACK = 'bootstrap4'
|
||||||
|
|
||||||
LOGIN_REDIRECT_URL = '/'
|
LOG_FORMAT = '%(asctime)s|%(process)d|%(thread)d|%(name)s|%(filename)s|%(lineno)d|%(levelname)s|%(message)s'
|
||||||
LOGIN_URL = '/login'
|
|
||||||
|
#
|
||||||
|
# Directories
|
||||||
|
#
|
||||||
|
|
||||||
|
# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
|
||||||
|
PROJECT_ROOT = up(up(os.path.dirname(__file__))) # Project root
|
||||||
|
BASE_DIR = os.path.join(PROJECT_ROOT, "app") # Base dir of the application
|
||||||
|
CONFIG_DIR = os.path.join(PROJECT_ROOT, "config")
|
||||||
|
DATA_DIR = os.path.join(PROJECT_ROOT, "data")
|
||||||
|
STATIC_ROOT = os.path.join(PROJECT_ROOT, "static")
|
||||||
|
|
||||||
|
_DEFAULT_CONFIG_FILE = os.path.join(CONFIG_DIR, 'config.ini')
|
||||||
|
_DEFAULT_LOG_FILE = os.path.join(DATA_DIR, 'log.log')
|
||||||
|
_DEFAULT_MEDIA_ROOT = os.path.join(DATA_DIR, 'media')
|
||||||
|
|
||||||
|
DEFAULTS_FILE = os.path.join(CONFIG_DIR, 'defaults.ini')
|
||||||
|
CONFIG_FILE = os.getenv('YTSM_CONFIG_FILE', _DEFAULT_CONFIG_FILE)
|
||||||
|
|
||||||
|
#
|
||||||
|
# Defaults
|
||||||
|
#
|
||||||
|
_DEFAULT_DEBUG = False
|
||||||
|
|
||||||
|
_DEFAULT_SECRET_KEY = '^zv8@i2h!ko2lo=%ivq(9e#x=%q*i^^)6#4@(juzdx%&0c+9a0'
|
||||||
|
_DEFAULT_YOUTUBE_API_KEY = 'AIzaSyBabzE4Bup77WexdLMa9rN9z-wJidEfNX8'
|
||||||
|
|
||||||
|
_DEFAULT_DATABASE = {
|
||||||
|
'ENGINE': 'django.db.backends.sqlite3',
|
||||||
|
'NAME': os.path.join(DATA_DIR, 'ytmanager.db'),
|
||||||
|
'HOST': None,
|
||||||
|
'USER': None,
|
||||||
|
'PASSWORD': None,
|
||||||
|
'PORT': None,
|
||||||
|
}
|
||||||
|
|
||||||
|
_SCHEDULER_SYNC_SCHEDULE = '5 * * * *'
|
||||||
|
_DEFAULT_SCHEDULER_CONCURRENCY = 1
|
||||||
|
|
||||||
|
|
||||||
|
#
|
||||||
|
# Load globals from config.ini
|
||||||
|
#
|
||||||
|
def load_config_ini():
|
||||||
|
from configparser import ConfigParser
|
||||||
|
from YtManagerApp.utils.extended_interpolation_with_env import ExtendedInterpolatorWithEnv
|
||||||
|
import dj_database_url
|
||||||
|
|
||||||
|
cfg = ConfigParser(allow_no_value=True, interpolation=ExtendedInterpolatorWithEnv())
|
||||||
|
read_ok = cfg.read([DEFAULTS_FILE, CONFIG_FILE])
|
||||||
|
|
||||||
|
if DEFAULTS_FILE not in read_ok:
|
||||||
|
print('Failed to read file ' + DEFAULTS_FILE)
|
||||||
|
raise Exception('Cannot read file ' + DEFAULTS_FILE)
|
||||||
|
if CONFIG_FILE not in read_ok:
|
||||||
|
print('Failed to read file ' + CONFIG_FILE)
|
||||||
|
raise Exception('Cannot read file ' + CONFIG_FILE)
|
||||||
|
|
||||||
|
# Debug
|
||||||
|
global DEBUG
|
||||||
|
DEBUG = cfg.getboolean('global', 'Debug', fallback=_DEFAULT_DEBUG)
|
||||||
|
|
||||||
|
# Media root, which is where thumbnails are stored
|
||||||
|
global MEDIA_ROOT
|
||||||
|
MEDIA_ROOT = cfg.get('global', 'MediaRoot', fallback=_DEFAULT_MEDIA_ROOT)
|
||||||
|
|
||||||
|
# Keys - secret key, youtube API key
|
||||||
|
# SECURITY WARNING: keep the secret key used in production secret!
|
||||||
|
global SECRET_KEY, YOUTUBE_API_KEY
|
||||||
|
SECRET_KEY = cfg.get('global', 'SecretKey', fallback=_DEFAULT_SECRET_KEY)
|
||||||
|
YOUTUBE_API_KEY = cfg.get('global', 'YoutubeApiKey', fallback=_DEFAULT_YOUTUBE_API_KEY)
|
||||||
|
|
||||||
|
# Database
|
||||||
|
global DATABASES
|
||||||
|
DATABASES = {
|
||||||
|
'default': _DEFAULT_DATABASE
|
||||||
|
}
|
||||||
|
|
||||||
|
if cfg.has_option('global', 'DatabaseURL'):
|
||||||
|
DATABASES['default'] = dj_database_url.parse(cfg.get('global', 'DatabaseURL'), conn_max_age=600)
|
||||||
|
|
||||||
|
else:
|
||||||
|
DATABASES['default'] = {
|
||||||
|
'ENGINE': cfg.get('global', 'DatabaseEngine', fallback=_DEFAULT_DATABASE['ENGINE']),
|
||||||
|
'NAME': cfg.get('global', 'DatabaseName', fallback=_DEFAULT_DATABASE['NAME']),
|
||||||
|
'HOST': cfg.get('global', 'DatabaseHost', fallback=_DEFAULT_DATABASE['HOST']),
|
||||||
|
'USER': cfg.get('global', 'DatabaseUser', fallback=_DEFAULT_DATABASE['USER']),
|
||||||
|
'PASSWORD': cfg.get('global', 'DatabasePassword', fallback=_DEFAULT_DATABASE['PASSWORD']),
|
||||||
|
'PORT': cfg.get('global', 'DatabasePort', fallback=_DEFAULT_DATABASE['PORT']),
|
||||||
|
}
|
||||||
|
|
||||||
|
# Log settings
|
||||||
|
global LOG_LEVEL, LOG_FILE
|
||||||
|
log_level_str = cfg.get('global', 'LogLevel', fallback='INFO')
|
||||||
|
|
||||||
|
try:
|
||||||
|
LOG_LEVEL = getattr(logging, log_level_str)
|
||||||
|
except AttributeError:
|
||||||
|
print("Invalid log level " + LOG_LEVEL)
|
||||||
|
LOG_LEVEL = logging.INFO
|
||||||
|
|
||||||
|
LOG_FILE = cfg.get('global', 'LogFile', fallback=_DEFAULT_LOG_FILE)
|
||||||
|
|
||||||
|
# Scheduler settings
|
||||||
|
global SCHEDULER_SYNC_SCHEDULE, SCHEDULER_CONCURRENCY
|
||||||
|
SCHEDULER_SYNC_SCHEDULE = cfg.get('global', 'SynchronizationSchedule', fallback=_SCHEDULER_SYNC_SCHEDULE)
|
||||||
|
SCHEDULER_CONCURRENCY = cfg.getint('global', 'SchedulerConcurrency', fallback=_DEFAULT_SCHEDULER_CONCURRENCY)
|
||||||
|
|
||||||
|
|
||||||
|
load_config_ini()
|
||||||
|
@ -12,35 +12,26 @@ from django.contrib.auth.models import User
|
|||||||
from .models import UserSettings, Subscription
|
from .models import UserSettings, Subscription
|
||||||
from .utils.extended_interpolation_with_env import ExtendedInterpolatorWithEnv
|
from .utils.extended_interpolation_with_env import ExtendedInterpolatorWithEnv
|
||||||
|
|
||||||
_CONFIG_DIR = os.path.join(dj_settings.BASE_DIR, 'config')
|
|
||||||
_LOG_FILE = 'log.log'
|
|
||||||
_LOG_PATH = os.path.join(_CONFIG_DIR, _LOG_FILE)
|
|
||||||
_LOG_FORMAT = '%(asctime)s|%(process)d|%(thread)d|%(name)s|%(filename)s|%(lineno)d|%(levelname)s|%(message)s'
|
|
||||||
|
|
||||||
|
|
||||||
class AppSettings(ConfigParser):
|
class AppSettings(ConfigParser):
|
||||||
_DEFAULT_INTERPOLATION = ExtendedInterpolatorWithEnv()
|
_DEFAULT_INTERPOLATION = ExtendedInterpolatorWithEnv()
|
||||||
__DEFAULTS_FILE = 'defaults.ini'
|
|
||||||
__SETTINGS_FILE = 'config.ini'
|
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
super().__init__(allow_no_value=True, *args, **kwargs)
|
super().__init__(allow_no_value=True, *args, **kwargs)
|
||||||
self.__defaults_path = os.path.join(_CONFIG_DIR, AppSettings.__DEFAULTS_FILE)
|
|
||||||
self.__settings_path = os.path.join(_CONFIG_DIR, AppSettings.__SETTINGS_FILE)
|
|
||||||
|
|
||||||
def initialize(self):
|
def initialize(self):
|
||||||
self.read([self.__defaults_path, self.__settings_path])
|
self.read([dj_settings.DEFAULTS_FILE, dj_settings.CONFIG_FILE])
|
||||||
|
|
||||||
def save(self):
|
def save(self):
|
||||||
if os.path.exists(self.__settings_path):
|
if os.path.exists(dj_settings.CONFIG_FILE):
|
||||||
# Create a backup
|
# Create a backup
|
||||||
copyfile(self.__settings_path, self.__settings_path + ".backup")
|
copyfile(dj_settings.CONFIG_FILE, dj_settings.CONFIG_FILE + ".backup")
|
||||||
else:
|
else:
|
||||||
# Ensure directory exists
|
# Ensure directory exists
|
||||||
settings_dir = os.path.dirname(self.__settings_path)
|
settings_dir = os.path.dirname(dj_settings.CONFIG_FILE)
|
||||||
os.makedirs(settings_dir, exist_ok=True)
|
os.makedirs(settings_dir, exist_ok=True)
|
||||||
|
|
||||||
with open(self.__settings_path, 'w') as f:
|
with open(dj_settings.CONFIG_FILE, 'w') as f:
|
||||||
self.write(f)
|
self.write(f)
|
||||||
|
|
||||||
def __get_combined_dict(self, vars: Optional[Any], sub: Optional[Subscription], user: Optional[User]) -> ChainMap:
|
def __get_combined_dict(self, vars: Optional[Any], sub: Optional[Subscription], user: Optional[User]) -> ChainMap:
|
||||||
@ -112,12 +103,10 @@ def initialize_app_config():
|
|||||||
|
|
||||||
|
|
||||||
def __initialize_logger():
|
def __initialize_logger():
|
||||||
log_level_str = settings.get('global', 'LogLevel', fallback='INFO')
|
log_dir = os.path.dirname(dj_settings.LOG_FILE)
|
||||||
|
os.makedirs(log_dir, exist_ok=True)
|
||||||
|
|
||||||
try:
|
logging.basicConfig(
|
||||||
log_level = getattr(logging, log_level_str)
|
filename=dj_settings.LOG_FILE,
|
||||||
logging.basicConfig(filename=_LOG_PATH, level=log_level, format=_LOG_FORMAT)
|
level=dj_settings.LOG_LEVEL,
|
||||||
|
format=dj_settings.LOG_FORMAT)
|
||||||
except AttributeError:
|
|
||||||
logging.basicConfig(filename=_LOG_PATH, level=logging.INFO, format=_LOG_FORMAT)
|
|
||||||
logging.warning('Invalid log level "%s" in config file.', log_level_str)
|
|
||||||
|
@ -5,10 +5,13 @@ import os
|
|||||||
import youtube_dl
|
import youtube_dl
|
||||||
import logging
|
import logging
|
||||||
import re
|
import re
|
||||||
|
from threading import Lock
|
||||||
|
|
||||||
log = logging.getLogger('video_downloader')
|
log = logging.getLogger('video_downloader')
|
||||||
log_youtube_dl = log.getChild('youtube_dl')
|
log_youtube_dl = log.getChild('youtube_dl')
|
||||||
|
|
||||||
|
_lock = Lock()
|
||||||
|
|
||||||
|
|
||||||
def __get_valid_path(path):
|
def __get_valid_path(path):
|
||||||
"""
|
"""
|
||||||
@ -73,27 +76,36 @@ def download_video(video: Video, attempt: int = 1):
|
|||||||
|
|
||||||
log.info('Downloading video %d [%s %s]', video.id, video.video_id, video.name)
|
log.info('Downloading video %d [%s %s]', video.id, video.video_id, video.name)
|
||||||
|
|
||||||
max_attempts = settings.getint_sub(video.subscription, 'user', 'DownloadMaxAttempts', fallback=3)
|
# Issue: if multiple videos are downloaded at the same time, a race condition appears in the mkdirs() call that
|
||||||
|
# youtube-dl makes, which causes it to fail with the error 'Cannot create folder - file already exists'.
|
||||||
|
# For now, allow a single download instance.
|
||||||
|
_lock.acquire()
|
||||||
|
|
||||||
youtube_dl_params, output_path = __build_youtube_dl_params(video)
|
try:
|
||||||
with youtube_dl.YoutubeDL(youtube_dl_params) as yt:
|
max_attempts = settings.getint_sub(video.subscription, 'user', 'DownloadMaxAttempts', fallback=3)
|
||||||
ret = yt.download(["https://www.youtube.com/watch?v=" + video.video_id])
|
|
||||||
|
|
||||||
log.info('Download finished with code %d', ret)
|
youtube_dl_params, output_path = __build_youtube_dl_params(video)
|
||||||
|
with youtube_dl.YoutubeDL(youtube_dl_params) as yt:
|
||||||
|
ret = yt.download(["https://www.youtube.com/watch?v=" + video.video_id])
|
||||||
|
|
||||||
if ret == 0:
|
log.info('Download finished with code %d', ret)
|
||||||
video.downloaded_path = output_path
|
|
||||||
video.save()
|
|
||||||
log.info('Video %d [%s %s] downloaded successfully!', video.id, video.video_id, video.name)
|
|
||||||
|
|
||||||
elif attempt <= max_attempts:
|
if ret == 0:
|
||||||
log.warning('Re-enqueueing video (attempt %d/%d)', attempt, max_attempts)
|
video.downloaded_path = output_path
|
||||||
__schedule_download_video(video, attempt + 1)
|
video.save()
|
||||||
|
log.info('Video %d [%s %s] downloaded successfully!', video.id, video.video_id, video.name)
|
||||||
|
|
||||||
else:
|
elif attempt <= max_attempts:
|
||||||
log.error('Multiple attempts to download video %d [%s %s] failed!', video.id, video.video_id, video.name)
|
log.warning('Re-enqueueing video (attempt %d/%d)', attempt, max_attempts)
|
||||||
video.downloaded_path = ''
|
__schedule_download_video(video, attempt + 1)
|
||||||
video.save()
|
|
||||||
|
else:
|
||||||
|
log.error('Multiple attempts to download video %d [%s %s] failed!', video.id, video.video_id, video.name)
|
||||||
|
video.downloaded_path = ''
|
||||||
|
video.save()
|
||||||
|
|
||||||
|
finally:
|
||||||
|
_lock.release()
|
||||||
|
|
||||||
|
|
||||||
def __schedule_download_video(video: Video, attempt=1):
|
def __schedule_download_video(video: Video, attempt=1):
|
||||||
|
@ -35,7 +35,7 @@ class ExtendedInterpolatorWithEnv(Interpolation):
|
|||||||
def _resolve_section_option(self, section, option, parser):
|
def _resolve_section_option(self, section, option, parser):
|
||||||
if section == 'env':
|
if section == 'env':
|
||||||
return os.getenv(option, '')
|
return os.getenv(option, '')
|
||||||
return parser.get(section, option, raw=True)
|
return parser.get(section, parser.optionxform(option), raw=True)
|
||||||
|
|
||||||
def _interpolate_some(self, parser, option, accum, rest, section, map,
|
def _interpolate_some(self, parser, option, accum, rest, section, map,
|
||||||
depth):
|
depth):
|
||||||
@ -70,7 +70,7 @@ class ExtendedInterpolatorWithEnv(Interpolation):
|
|||||||
v = self._resolve_option(opt, map)
|
v = self._resolve_option(opt, map)
|
||||||
elif len(path) == 2:
|
elif len(path) == 2:
|
||||||
sect = path[0]
|
sect = path[0]
|
||||||
opt = parser.optionxform(path[1])
|
opt = path[1]
|
||||||
v = self._resolve_section_option(sect, opt, parser)
|
v = self._resolve_section_option(sect, opt, parser)
|
||||||
else:
|
else:
|
||||||
raise InterpolationSyntaxError(
|
raise InterpolationSyntaxError(
|
||||||
|
@ -1,59 +0,0 @@
|
|||||||
; Use $<env:environment_variable> to use the value of an environment variable.
|
|
||||||
; The global section contains settings that apply to the entire server
|
|
||||||
[global]
|
|
||||||
; YouTube API key - get this from your user account
|
|
||||||
;YoutubeApiKey=
|
|
||||||
|
|
||||||
; Specifies the synchronization schedule, in crontab format.
|
|
||||||
; Format: <minute> <hour> <day-of-month> <month-of-year> <day of week>
|
|
||||||
SynchronizationSchedule=5 * * * *
|
|
||||||
|
|
||||||
; Number of threads running the scheduler
|
|
||||||
; Since most of the jobs scheduled are downloads, there is no advantage to having
|
|
||||||
; a higher concurrency
|
|
||||||
SchedulerConcurrency=1
|
|
||||||
|
|
||||||
; Log level
|
|
||||||
LogLevel=DEBUG
|
|
||||||
|
|
||||||
; Default user settings
|
|
||||||
[user]
|
|
||||||
; When a video is deleted on the system, it will be marked as 'watched'
|
|
||||||
MarkDeletedAsWatched=True
|
|
||||||
|
|
||||||
; Videos marked as watched are automatically deleted
|
|
||||||
DeleteWatched=True
|
|
||||||
|
|
||||||
; Enable automatic downloading
|
|
||||||
AutoDownload=True
|
|
||||||
|
|
||||||
; Limit the total number of videos downloaded (-1 or empty = no limit)
|
|
||||||
DownloadGlobalLimit=10
|
|
||||||
|
|
||||||
; Limit the numbers of videos per subscription (-1 or empty = no limit)
|
|
||||||
DownloadSubscriptionLimit=5
|
|
||||||
|
|
||||||
; Number of download attempts
|
|
||||||
DownloadMaxAttempts=3
|
|
||||||
|
|
||||||
; Download order
|
|
||||||
; Options: newest, oldest, playlist, playlist_reverse, popularity, rating
|
|
||||||
DownloadOrder=playlist
|
|
||||||
|
|
||||||
; Path where downloaded videos are stored
|
|
||||||
DownloadPath=data/media/videos
|
|
||||||
|
|
||||||
; A pattern which describes how downloaded files are organized. Extensions are automatically appended.
|
|
||||||
; Supported fields: channel, channel_id, playlist, playlist_id, playlist_index, title, id
|
|
||||||
; The default pattern should work pretty well with Plex
|
|
||||||
;DownloadFilePattern=${channel}/${playlist}/S01E${playlist_index} - ${title} [${id}]
|
|
||||||
|
|
||||||
; Download format that will be passed to youtube-dl. See the youtube-dl documentation for more details.
|
|
||||||
DownloadFormat=bestvideo+bestaudio
|
|
||||||
|
|
||||||
; Subtitles - these options match the youtube-dl options
|
|
||||||
;DownloadSubtitles=True
|
|
||||||
;DownloadAutogeneratedSubtitles=False
|
|
||||||
;DownloadSubtitlesAll=False
|
|
||||||
;DownloadSubtitlesLangs=en,ro
|
|
||||||
;DownloadSubtitlesFormat=
|
|
@ -1,59 +0,0 @@
|
|||||||
; Use $<env:environment_variable> to use the value of an environment variable.
|
|
||||||
; The global section contains settings that apply to the entire server
|
|
||||||
[global]
|
|
||||||
; YouTube API key - get this from your user account
|
|
||||||
YoutubeApiKey=AIzaSyBabzE4Bup77WexdLMa9rN9z-wJidEfNX8
|
|
||||||
|
|
||||||
; Specifies the synchronization schedule, in crontab format.
|
|
||||||
; Format: <minute> <hour> <day-of-month> <month-of-year> <day of week>
|
|
||||||
SynchronizationSchedule=0 * * * *
|
|
||||||
|
|
||||||
; Number of threads running the scheduler
|
|
||||||
; Since most of the jobs scheduled are downloads, there is no advantage to having
|
|
||||||
; a higher concurrency
|
|
||||||
SchedulerConcurrency=2
|
|
||||||
|
|
||||||
; Log level
|
|
||||||
LogLevel=INFO
|
|
||||||
|
|
||||||
; Default user settings
|
|
||||||
[user]
|
|
||||||
; When a video is deleted on the system, it will be marked as 'watched'
|
|
||||||
MarkDeletedAsWatched=True
|
|
||||||
|
|
||||||
; Videos marked as watched are automatically deleted
|
|
||||||
DeleteWatched=True
|
|
||||||
|
|
||||||
; Enable automatic downloading
|
|
||||||
AutoDownload=True
|
|
||||||
|
|
||||||
; Limit the total number of videos downloaded (-1 or empty = no limit)
|
|
||||||
DownloadGlobalLimit=
|
|
||||||
|
|
||||||
; Limit the numbers of videos per subscription (-1 or empty = no limit)
|
|
||||||
DownloadSubscriptionLimit=5
|
|
||||||
|
|
||||||
; Number of download attempts
|
|
||||||
DownloadMaxAttempts=3
|
|
||||||
|
|
||||||
; Download order
|
|
||||||
; Options: newest, oldest, playlist, playlist_reverse, popularity, rating
|
|
||||||
DownloadOrder=playlist
|
|
||||||
|
|
||||||
; Path where downloaded videos are stored
|
|
||||||
DownloadPath=${env:USERPROFILE}${env:HOME}/Downloads
|
|
||||||
|
|
||||||
; A pattern which describes how downloaded files are organized. Extensions are automatically appended.
|
|
||||||
; Supported fields: channel, channel_id, playlist, playlist_id, playlist_index, title, id
|
|
||||||
; The default pattern should work pretty well with Plex
|
|
||||||
DownloadFilePattern=${channel}/${playlist}/S01E${playlist_index} - ${title} [${id}]
|
|
||||||
|
|
||||||
; Download format that will be passed to youtube-dl. See the youtube-dl documentation for more details.
|
|
||||||
DownloadFormat=bestvideo+bestaudio
|
|
||||||
|
|
||||||
; Subtitles - these options match the youtube-dl options
|
|
||||||
DownloadSubtitles=True
|
|
||||||
DownloadAutogeneratedSubtitles=False
|
|
||||||
DownloadSubtitlesAll=False
|
|
||||||
DownloadSubtitlesLangs=en,ro
|
|
||||||
DownloadSubtitlesFormat=
|
|
@ -1,47 +1,75 @@
|
|||||||
; Use $<env:environment_variable> to use the value of an environment variable.
|
; Use ${env:environment_variable} to use the value of an environment variable.
|
||||||
|
; If a variable is not set here, it will be loaded from defaults.ini.
|
||||||
|
|
||||||
; The global section contains settings that apply to the entire server
|
; The global section contains settings that apply to the entire server
|
||||||
[global]
|
[global]
|
||||||
|
|
||||||
|
Debug=${env:YTSM_DEBUG}
|
||||||
|
|
||||||
|
; This is the folder where thumbnails will be downloaded. By default project_root/data/media is used.
|
||||||
|
;MediaRoot=
|
||||||
|
|
||||||
|
; Secret key - django secret key
|
||||||
|
;SecretKey=^zv8@i2h!ko2lo=%ivq(9e#x=%q*i^^)6#4@(juzdx%&0c+9a0
|
||||||
|
|
||||||
; YouTube API key - get this from your user account
|
; YouTube API key - get this from your user account
|
||||||
YoutubeApiKey=AIzaSyAonB6T-DrKjfGxBGuHyFMg0x_d0T9nlP8
|
;YoutubeApiKey=AIzaSyAonB6T-DrKjfGxBGuHyFMg0x_d0T9nlP8
|
||||||
|
|
||||||
|
; Database settings
|
||||||
|
; You can use any database engine supported by Django, as long as you add the required dependencies.
|
||||||
|
; Built-in engines: https://docs.djangoproject.com/en/2.1/ref/settings/#std:setting-DATABASE-ENGINE
|
||||||
|
; Others databases might be supported by installing the corect pip package.
|
||||||
|
|
||||||
|
;DatabaseEngine=django.db.backends.sqlite3
|
||||||
|
;DatabaseName=data/ytmanager.db
|
||||||
|
;DatabaseHost=
|
||||||
|
;DatabaseUser=
|
||||||
|
;DatabasePassword=
|
||||||
|
;DatabasePort=
|
||||||
|
|
||||||
|
; Database one-liner. If set, it will override any other Database* setting.
|
||||||
|
; Documentation: https://github.com/kennethreitz/dj-database-url
|
||||||
|
;DatabaseURL=sqlite:////full/path/to/your/database/file.sqlite
|
||||||
|
|
||||||
|
; Log settings, sets the log file location and the log level
|
||||||
|
;LogLevel=INFO
|
||||||
|
;LogFile=data/log.log
|
||||||
|
|
||||||
; Specifies the synchronization schedule, in crontab format.
|
; Specifies the synchronization schedule, in crontab format.
|
||||||
; Format: <minute> <hour> <day-of-month> <month-of-year> <day of week>
|
; Format: <minute> <hour> <day-of-month> <month-of-year> <day of week>
|
||||||
SynchronizationSchedule=5 * * * *
|
;SynchronizationSchedule=5 * * * *
|
||||||
|
|
||||||
; Number of threads running the scheduler
|
; Number of threads running the scheduler
|
||||||
; Since most of the jobs scheduled are downloads, there is no advantage to having
|
; Since most of the jobs scheduled are downloads, there is no advantage to having
|
||||||
; a higher concurrency
|
; a higher concurrency
|
||||||
SchedulerConcurrency=1
|
;SchedulerConcurrency=1
|
||||||
|
|
||||||
; Log level
|
|
||||||
LogLevel=DEBUG
|
|
||||||
|
|
||||||
; Default user settings
|
; Default user settings
|
||||||
[user]
|
[user]
|
||||||
; When a video is deleted on the system, it will be marked as 'watched'
|
; When a video is deleted on the system, it will be marked as 'watched'
|
||||||
MarkDeletedAsWatched=True
|
;MarkDeletedAsWatched=True
|
||||||
|
|
||||||
; Videos marked as watched are automatically deleted
|
; Videos marked as watched are automatically deleted
|
||||||
DeleteWatched=True
|
;DeleteWatched=True
|
||||||
|
|
||||||
; Enable automatic downloading
|
; Enable automatic downloading
|
||||||
AutoDownload=True
|
;AutoDownload=True
|
||||||
|
|
||||||
; Limit the total number of videos downloaded (-1 or empty = no limit)
|
; Limit the total number of videos downloaded (-1 or empty = no limit)
|
||||||
DownloadGlobalLimit=10
|
;DownloadGlobalLimit=10
|
||||||
|
|
||||||
; Limit the numbers of videos per subscription (-1 or empty = no limit)
|
; Limit the numbers of videos per subscription (-1 or empty = no limit)
|
||||||
DownloadSubscriptionLimit=5
|
;DownloadSubscriptionLimit=5
|
||||||
|
|
||||||
; Number of download attempts
|
; Number of download attempts
|
||||||
DownloadMaxAttempts=3
|
;DownloadMaxAttempts=3
|
||||||
|
|
||||||
; Download order
|
; Download order
|
||||||
; Options: newest, oldest, playlist, playlist_reverse, popularity, rating
|
; Options: newest, oldest, playlist, playlist_reverse, popularity, rating
|
||||||
DownloadOrder=playlist
|
;DownloadOrder=playlist
|
||||||
|
|
||||||
; Path where downloaded videos are stored
|
; Path where downloaded videos are stored
|
||||||
DownloadPath=data/media/videos
|
DownloadPath=${env:YTSM_DATA_PATH}/videos
|
||||||
|
|
||||||
; A pattern which describes how downloaded files are organized. Extensions are automatically appended.
|
; A pattern which describes how downloaded files are organized. Extensions are automatically appended.
|
||||||
; Supported fields: channel, channel_id, playlist, playlist_id, playlist_index, title, id
|
; Supported fields: channel, channel_id, playlist, playlist_id, playlist_index, title, id
|
||||||
@ -49,7 +77,7 @@ DownloadPath=data/media/videos
|
|||||||
;DownloadFilePattern=${channel}/${playlist}/S01E${playlist_index} - ${title} [${id}]
|
;DownloadFilePattern=${channel}/${playlist}/S01E${playlist_index} - ${title} [${id}]
|
||||||
|
|
||||||
; Download format that will be passed to youtube-dl. See the youtube-dl documentation for more details.
|
; Download format that will be passed to youtube-dl. See the youtube-dl documentation for more details.
|
||||||
DownloadFormat=bestvideo+bestaudio
|
;DownloadFormat=bestvideo+bestaudio
|
||||||
|
|
||||||
; Subtitles - these options match the youtube-dl options
|
; Subtitles - these options match the youtube-dl options
|
||||||
;DownloadSubtitles=True
|
;DownloadSubtitles=True
|
||||||
|
@ -1,20 +1,48 @@
|
|||||||
; Use $<env:environment_variable> to use the value of an environment variable.
|
; Use ${env:environment_variable} to use the value of an environment variable.
|
||||||
; The global section contains settings that apply to the entire server
|
; The global section contains settings that apply to the entire server
|
||||||
[global]
|
[global]
|
||||||
|
|
||||||
|
; Controls whether django debug mode is enabled. Should be false in production.
|
||||||
|
Debug=False
|
||||||
|
|
||||||
|
; This is the folder where thumbnails will be downloaded. By default project_root/data/media is used.
|
||||||
|
;MediaRoot=
|
||||||
|
|
||||||
|
; Secret key - django secret key
|
||||||
|
SecretKey=^zv8@i2h!ko2lo=%ivq(9e#x=%q*i^^)6#4@(juzdx%&0c+9a0
|
||||||
|
|
||||||
; YouTube API key - get this from your user account
|
; YouTube API key - get this from your user account
|
||||||
YoutubeApiKey=AIzaSyBabzE4Bup77WexdLMa9rN9z-wJidEfNX8
|
YoutubeApiKey=AIzaSyBabzE4Bup77WexdLMa9rN9z-wJidEfNX8
|
||||||
|
|
||||||
|
; Database settings
|
||||||
|
; You can use any database engine supported by Django, as long as you add the required dependencies.
|
||||||
|
; Built-in engines: https://docs.djangoproject.com/en/2.1/ref/settings/#std:setting-DATABASE-ENGINE
|
||||||
|
; Others databases might be supported by installing the corect pip package.
|
||||||
|
|
||||||
|
;DatabaseEngine=django.db.backends.sqlite3
|
||||||
|
;DatabaseName=data/ytmanager.db
|
||||||
|
;DatabaseHost=
|
||||||
|
;DatabaseUser=
|
||||||
|
;DatabasePassword=
|
||||||
|
;DatabasePort=
|
||||||
|
|
||||||
|
; Database one-liner. If set, it will override any other Database* setting.
|
||||||
|
; Documentation: https://github.com/kennethreitz/dj-database-url
|
||||||
|
;DatabaseURL=sqlite:////full/path/to/your/database/file.sqlite
|
||||||
|
|
||||||
|
; Log settings, sets the log file location and the log level
|
||||||
|
LogLevel=INFO
|
||||||
|
; LogFile=data/log.log
|
||||||
|
|
||||||
; Specifies the synchronization schedule, in crontab format.
|
; Specifies the synchronization schedule, in crontab format.
|
||||||
; Format: <minute> <hour> <day-of-month> <month-of-year> <day of week>
|
; Format: <minute> <hour> <day-of-month> <month-of-year> <day of week>
|
||||||
SynchronizationSchedule=0 * * * *
|
SynchronizationSchedule=5 * * * *
|
||||||
|
|
||||||
; Number of threads running the scheduler
|
; Number of threads running the scheduler
|
||||||
; Since most of the jobs scheduled are downloads, there is no advantage to having
|
; Since most of the jobs scheduled are downloads, there is no advantage to having
|
||||||
; a higher concurrency
|
; a higher concurrency
|
||||||
SchedulerConcurrency=2
|
SchedulerConcurrency=3
|
||||||
|
|
||||||
; Log level
|
|
||||||
LogLevel=INFO
|
|
||||||
|
|
||||||
; Default user settings
|
; Default user settings
|
||||||
[user]
|
[user]
|
||||||
@ -41,7 +69,7 @@ DownloadMaxAttempts=3
|
|||||||
DownloadOrder=playlist
|
DownloadOrder=playlist
|
||||||
|
|
||||||
; Path where downloaded videos are stored
|
; Path where downloaded videos are stored
|
||||||
DownloadPath=${env:USERPROFILE}${env:HOME}/Downloads
|
DownloadPath=data/videos
|
||||||
|
|
||||||
; A pattern which describes how downloaded files are organized. Extensions are automatically appended.
|
; A pattern which describes how downloaded files are organized. Extensions are automatically appended.
|
||||||
; Supported fields: channel, channel_id, playlist, playlist_id, playlist_index, title, id
|
; Supported fields: channel, channel_id, playlist, playlist_id, playlist_index, title, id
|
||||||
|
@ -4,8 +4,9 @@ services:
|
|||||||
nginx:
|
nginx:
|
||||||
image: nginx:latest
|
image: nginx:latest
|
||||||
volumes:
|
volumes:
|
||||||
- ./nginx:/etc/nginx/conf.d/
|
- ./docker/nginx:/etc/nginx/conf.d/
|
||||||
- ./app/YtManagerApp/static:/www/static
|
- ./app/YtManagerApp/static:/www/static
|
||||||
|
- ./data/media:/www/media
|
||||||
ports:
|
ports:
|
||||||
- "80:80"
|
- "80:80"
|
||||||
depends_on:
|
depends_on:
|
||||||
@ -13,11 +14,9 @@ services:
|
|||||||
|
|
||||||
web:
|
web:
|
||||||
build: .
|
build: .
|
||||||
env_file:
|
|
||||||
- sqlite3.env.env
|
|
||||||
tty: true
|
tty: true
|
||||||
ports:
|
ports:
|
||||||
- "8000:8000"
|
- "8000:8000"
|
||||||
volumes:
|
volumes:
|
||||||
- ./media:/usr/src/app/data/media
|
- ./config:/usr/src/ytsm/config
|
||||||
- ./db:/usr/src/app/data/db
|
- ./data:/usr/src/ytsm/data
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
#./manage.py runserver 0.0.0.0:8000 --noreload
|
|
||||||
./manage.py migrate
|
./manage.py migrate
|
||||||
gunicorn -b 0.0.0.0:8000 -w 4 YtManager.wsgi
|
gunicorn -b 0.0.0.0:8000 -w 4 YtManager.wsgi
|
@ -15,6 +15,10 @@ server {
|
|||||||
alias /www/static;
|
alias /www/static;
|
||||||
expires 30d;
|
expires 30d;
|
||||||
}
|
}
|
||||||
|
location /media {
|
||||||
|
alias /www/media;
|
||||||
|
expires 30d;
|
||||||
|
}
|
||||||
|
|
||||||
location / {
|
location / {
|
||||||
try_files $uri @proxy_to_app;
|
try_files $uri @proxy_to_app;
|
@ -1,3 +0,0 @@
|
|||||||
YTSM_DATABASE_ENGINE=django.db.backends.sqlite3
|
|
||||||
YTSM_DATABASE_NAME=/usr/src/app/data/db/ytmanager.db
|
|
||||||
YTSM_YOUTUBE_API_KEY=AIzaSyBabzE4Bup77WexdLMa9rN9z-wJidEfNX8
|
|
Loading…
Reference in New Issue
Block a user