miqt: split some functions to separate files, update function calls
This commit is contained in:
parent
d629eebcdc
commit
f056e7e39c
3
.gitignore
vendored
3
.gitignore
vendored
@ -1 +1,2 @@
|
||||
/deploy
|
||||
annie-miqt
|
||||
|
||||
|
17
about.go
Normal file
17
about.go
Normal file
@ -0,0 +1,17 @@
|
||||
package main
|
||||
|
||||
const (
|
||||
appName = "annie-mingui"
|
||||
appAuthor = "Zhiming Wang"
|
||||
appAuthorDomain = "zhimingwang.org"
|
||||
about = `<p><strong>annie-mingui</strong> v2020.02.09</p>
|
||||
<p>Copyright (c) 2020 Zhiming Wang</p>
|
||||
<p>annie-mingui is a Qt wrapper for <a href="https://github.com/iawia002/annie">iawia002/annie</a> the video downloader. Credits:</p>
|
||||
<ul>
|
||||
<li>iawia002/annie, MIT license;</li>
|
||||
<li><a href="https://qt.io">Qt</a>, LGPLv3 license;</li>
|
||||
<li><a href="https://github.com/therecipe/qt">therecipe/qt</a>, Qt bindings for golang, LGPLv3 license.</li>
|
||||
</ul>
|
||||
<p>Project URL: <a href="https://github.com/fanaticscripter/annie-mingui">github.com/fanaticscripter/annie-mingui</a>.</p>
|
||||
`
|
||||
)
|
139
annie.go
Normal file
139
annie.go
Normal file
@ -0,0 +1,139 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"net/url"
|
||||
|
||||
"github.com/iawia002/annie/config"
|
||||
"github.com/iawia002/annie/downloader"
|
||||
"github.com/iawia002/annie/extractors/bcy"
|
||||
"github.com/iawia002/annie/extractors/bilibili"
|
||||
"github.com/iawia002/annie/extractors/douyin"
|
||||
"github.com/iawia002/annie/extractors/douyu"
|
||||
"github.com/iawia002/annie/extractors/facebook"
|
||||
"github.com/iawia002/annie/extractors/geekbang"
|
||||
"github.com/iawia002/annie/extractors/instagram"
|
||||
"github.com/iawia002/annie/extractors/iqiyi"
|
||||
"github.com/iawia002/annie/extractors/mgtv"
|
||||
"github.com/iawia002/annie/extractors/miaopai"
|
||||
"github.com/iawia002/annie/extractors/netease"
|
||||
"github.com/iawia002/annie/extractors/pixivision"
|
||||
"github.com/iawia002/annie/extractors/pornhub"
|
||||
"github.com/iawia002/annie/extractors/qq"
|
||||
"github.com/iawia002/annie/extractors/tangdou"
|
||||
"github.com/iawia002/annie/extractors/tiktok"
|
||||
"github.com/iawia002/annie/extractors/tumblr"
|
||||
"github.com/iawia002/annie/extractors/twitter"
|
||||
"github.com/iawia002/annie/extractors/udn"
|
||||
"github.com/iawia002/annie/extractors/universal"
|
||||
"github.com/iawia002/annie/extractors/vimeo"
|
||||
"github.com/iawia002/annie/extractors/weibo"
|
||||
"github.com/iawia002/annie/extractors/xvideos"
|
||||
"github.com/iawia002/annie/extractors/yinyuetai"
|
||||
"github.com/iawia002/annie/extractors/youku"
|
||||
"github.com/iawia002/annie/extractors/youtube"
|
||||
"github.com/iawia002/annie/utils"
|
||||
)
|
||||
|
||||
// The following code is slightly modified from
|
||||
//
|
||||
// https://github.com/iawia002/annie/blob/master/main.go
|
||||
|
||||
func download(videoURL string) bool {
|
||||
var (
|
||||
domain string
|
||||
err error
|
||||
data []downloader.Data
|
||||
)
|
||||
bilibiliShortLink := utils.MatchOneOf(videoURL, `^(av|ep)\d+`)
|
||||
if bilibiliShortLink != nil && len(bilibiliShortLink) > 1 {
|
||||
bilibiliURL := map[string]string{
|
||||
"av": "https://www.bilibili.com/video/",
|
||||
"ep": "https://www.bilibili.com/bangumi/play/",
|
||||
}
|
||||
domain = "bilibili"
|
||||
videoURL = bilibiliURL[bilibiliShortLink[1]] + videoURL
|
||||
} else {
|
||||
u, err := url.ParseRequestURI(videoURL)
|
||||
if err != nil {
|
||||
printError(videoURL, err)
|
||||
return false
|
||||
}
|
||||
domain = utils.Domain(u.Host)
|
||||
}
|
||||
switch domain {
|
||||
case "douyin", "iesdouyin":
|
||||
data, err = douyin.Extract(videoURL)
|
||||
case "bilibili":
|
||||
data, err = bilibili.Extract(videoURL)
|
||||
case "bcy":
|
||||
data, err = bcy.Extract(videoURL)
|
||||
case "pixivision":
|
||||
data, err = pixivision.Extract(videoURL)
|
||||
case "youku":
|
||||
data, err = youku.Extract(videoURL)
|
||||
case "youtube", "youtu": // youtu.be
|
||||
data, err = youtube.Extract(videoURL)
|
||||
case "iqiyi":
|
||||
data, err = iqiyi.Extract(videoURL)
|
||||
case "mgtv":
|
||||
data, err = mgtv.Extract(videoURL)
|
||||
case "tangdou":
|
||||
data, err = tangdou.Extract(videoURL)
|
||||
case "tumblr":
|
||||
data, err = tumblr.Extract(videoURL)
|
||||
case "vimeo":
|
||||
data, err = vimeo.Extract(videoURL)
|
||||
case "facebook":
|
||||
data, err = facebook.Extract(videoURL)
|
||||
case "douyu":
|
||||
data, err = douyu.Extract(videoURL)
|
||||
case "miaopai":
|
||||
data, err = miaopai.Extract(videoURL)
|
||||
case "163":
|
||||
data, err = netease.Extract(videoURL)
|
||||
case "weibo":
|
||||
data, err = weibo.Extract(videoURL)
|
||||
case "instagram":
|
||||
data, err = instagram.Extract(videoURL)
|
||||
case "twitter":
|
||||
data, err = twitter.Extract(videoURL)
|
||||
case "qq":
|
||||
data, err = qq.Extract(videoURL)
|
||||
case "yinyuetai":
|
||||
data, err = yinyuetai.Extract(videoURL)
|
||||
case "geekbang":
|
||||
data, err = geekbang.Extract(videoURL)
|
||||
case "pornhub":
|
||||
data, err = pornhub.Extract(videoURL)
|
||||
case "xvideos":
|
||||
data, err = xvideos.Extract(videoURL)
|
||||
case "udn":
|
||||
data, err = udn.Extract(videoURL)
|
||||
case "tiktok":
|
||||
data, err = tiktok.Extract(videoURL)
|
||||
default:
|
||||
data, err = universal.Extract(videoURL)
|
||||
}
|
||||
if err != nil {
|
||||
// if this error occurs, it means that an error occurred before actually starting to extract data
|
||||
// (there is an error in the preparation step), and the data list is empty.
|
||||
printError(videoURL, err)
|
||||
return false
|
||||
}
|
||||
var isErr bool
|
||||
for _, item := range data {
|
||||
if item.Err != nil {
|
||||
// if this error occurs, the preparation step is normal, but the data extraction is wrong.
|
||||
// the data is an empty struct.
|
||||
printError(item.URL, item.Err)
|
||||
isErr = true
|
||||
continue
|
||||
}
|
||||
err = downloader.Download(item, videoURL, config.ChunkSizeMB)
|
||||
if err != nil {
|
||||
printError(item.URL, err)
|
||||
isErr = true
|
||||
}
|
||||
}
|
||||
return !isErr
|
||||
}
|
49
locale.go
Normal file
49
locale.go
Normal file
@ -0,0 +1,49 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/cloudfoundry-attic/jibber_jabber"
|
||||
"golang.org/x/text/language"
|
||||
)
|
||||
|
||||
var locales = map[string]map[string]string{
|
||||
"zh-Hans": {
|
||||
"About": "关于",
|
||||
"Application": "应用",
|
||||
"Awaiting user input": "等待用户输入",
|
||||
"Destination folder": "目标文件夹",
|
||||
"Download": "下载",
|
||||
"Download playlists": "下载完整播单",
|
||||
"Download started": "下载已开始",
|
||||
"On network errors, e.g. HTTP 403, please retry a few times.": "如遇HTTP 403等网络错误,请重试几次。",
|
||||
"Pick another folder": "选择文件夹",
|
||||
"Video URL": "视频链接",
|
||||
},
|
||||
}
|
||||
var locale map[string]string
|
||||
|
||||
// Poor man's gettext.
|
||||
func tr(s string) string {
|
||||
t, ok := locale[s]
|
||||
if ok {
|
||||
return t
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
func initLanguages() {
|
||||
|
||||
userLang, err := jibber_jabber.DetectIETF()
|
||||
if err != nil {
|
||||
userLang = "en"
|
||||
}
|
||||
availableLangs := []string{"en"}
|
||||
availableTags := []language.Tag{language.English}
|
||||
for l := range locales {
|
||||
availableLangs = append(availableLangs, l)
|
||||
availableTags = append(availableTags, language.Make(l))
|
||||
}
|
||||
matcher := language.NewMatcher(availableTags)
|
||||
_, index, _ := matcher.Match(language.Make(userLang))
|
||||
locale = locales[availableLangs[index]]
|
||||
|
||||
}
|
413
main.go
413
main.go
@ -5,7 +5,7 @@ import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/url"
|
||||
"log"
|
||||
"os"
|
||||
"os/signal"
|
||||
"regexp"
|
||||
@ -13,58 +13,10 @@ import (
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"golang.org/x/text/language"
|
||||
|
||||
"github.com/cloudfoundry-attic/jibber_jabber"
|
||||
"github.com/golang/glog"
|
||||
|
||||
qt "github.com/mappu/miqt/qt6"
|
||||
|
||||
"github.com/iawia002/annie/config"
|
||||
"github.com/iawia002/annie/downloader"
|
||||
"github.com/iawia002/annie/extractors/bcy"
|
||||
"github.com/iawia002/annie/extractors/bilibili"
|
||||
"github.com/iawia002/annie/extractors/douyin"
|
||||
"github.com/iawia002/annie/extractors/douyu"
|
||||
"github.com/iawia002/annie/extractors/facebook"
|
||||
"github.com/iawia002/annie/extractors/geekbang"
|
||||
"github.com/iawia002/annie/extractors/instagram"
|
||||
"github.com/iawia002/annie/extractors/iqiyi"
|
||||
"github.com/iawia002/annie/extractors/mgtv"
|
||||
"github.com/iawia002/annie/extractors/miaopai"
|
||||
"github.com/iawia002/annie/extractors/netease"
|
||||
"github.com/iawia002/annie/extractors/pixivision"
|
||||
"github.com/iawia002/annie/extractors/pornhub"
|
||||
"github.com/iawia002/annie/extractors/qq"
|
||||
"github.com/iawia002/annie/extractors/tangdou"
|
||||
"github.com/iawia002/annie/extractors/tiktok"
|
||||
"github.com/iawia002/annie/extractors/tumblr"
|
||||
"github.com/iawia002/annie/extractors/twitter"
|
||||
"github.com/iawia002/annie/extractors/udn"
|
||||
"github.com/iawia002/annie/extractors/universal"
|
||||
"github.com/iawia002/annie/extractors/vimeo"
|
||||
"github.com/iawia002/annie/extractors/weibo"
|
||||
"github.com/iawia002/annie/extractors/xvideos"
|
||||
"github.com/iawia002/annie/extractors/yinyuetai"
|
||||
"github.com/iawia002/annie/extractors/youku"
|
||||
"github.com/iawia002/annie/extractors/youtube"
|
||||
"github.com/iawia002/annie/utils"
|
||||
qt "github.com/mappu/miqt/qt6"
|
||||
)
|
||||
|
||||
const appName = "annie-mingui"
|
||||
const appAuthor = "Zhiming Wang"
|
||||
const appAuthorDomain = "zhimingwang.org"
|
||||
const about = `<p><strong>annie-mingui</strong> v2020.02.09</p>
|
||||
<p>Copyright (c) 2020 Zhiming Wang</p>
|
||||
<p>annie-mingui is a Qt wrapper for <a href="https://github.com/iawia002/annie">iawia002/annie</a> the video downloader. Credits:</p>
|
||||
<ul>
|
||||
<li>iawia002/annie, MIT license;</li>
|
||||
<li><a href="https://qt.io">Qt</a>, LGPLv3 license;</li>
|
||||
<li><a href="https://github.com/therecipe/qt">therecipe/qt</a>, Qt bindings for golang, LGPLv3 license.</li>
|
||||
</ul>
|
||||
<p>Project URL: <a href="https://github.com/fanaticscripter/annie-mingui">github.com/fanaticscripter/annie-mingui</a>.</p>
|
||||
`
|
||||
|
||||
// GUIConfig carries all application configurations.
|
||||
type GUIConfig struct {
|
||||
DestinationFolder string
|
||||
@ -75,7 +27,7 @@ type GUIConfig struct {
|
||||
// configured destination folder.
|
||||
func (c *GUIConfig) GetDestinationFolder() string {
|
||||
fallback := DefaultDownloadsFolder()
|
||||
val := settings.Value("destinationFolder", qt.NewQVariant12(fallback)).ToString()
|
||||
val := settings.Value(*qt.NewQAnyStringView3("destinationFolder"), qt.NewQVariant11(fallback)).ToString()
|
||||
c.DestinationFolder = val
|
||||
return val
|
||||
}
|
||||
@ -84,7 +36,7 @@ func (c *GUIConfig) GetDestinationFolder() string {
|
||||
// configured value of whether playlist download is enabled.
|
||||
func (c *GUIConfig) GetPlaylistEnabled() bool {
|
||||
fallback := true
|
||||
val := settings.Value("playlistEnabled", qt.NewQVariant9(fallback)).ToBool()
|
||||
val := settings.Value(*qt.NewQAnyStringView3("playlistEnabled"), qt.NewQVariant8(fallback)).ToBool()
|
||||
c.PlaylistEnabled = val
|
||||
return val
|
||||
}
|
||||
@ -92,14 +44,14 @@ func (c *GUIConfig) GetPlaylistEnabled() bool {
|
||||
// SetDestinationFolder sets and persists the configured destination folder.
|
||||
func (c *GUIConfig) SetDestinationFolder(val string) {
|
||||
c.DestinationFolder = val
|
||||
go func() { settings.SetValue("destinationFolder", qt.NewQVariant12(val)) }()
|
||||
go func() { settings.SetValue(*qt.NewQAnyStringView3("destinationFolder"), qt.NewQVariant11(val)) }()
|
||||
}
|
||||
|
||||
// SetPlaylistEnabled sets and persists the configured value of whether playlist
|
||||
// download is enabled.
|
||||
func (c *GUIConfig) SetPlaylistEnabled(val bool) {
|
||||
c.PlaylistEnabled = val
|
||||
go func() { settings.SetValue("playlistEnabled", qt.NewQVariant9(val)) }()
|
||||
go func() { settings.SetValue(*qt.NewQAnyStringView3("playlistEnabled"), qt.NewQVariant8(val)) }()
|
||||
}
|
||||
|
||||
// LoadGUIConfig loads config values from persisted settings if possible, or
|
||||
@ -114,208 +66,27 @@ func LoadGUIConfig() *GUIConfig {
|
||||
var settings *qt.QSettings
|
||||
var guiConfig *GUIConfig
|
||||
|
||||
var locales = map[string]map[string]string{
|
||||
"zh-Hans": {
|
||||
"About": "关于",
|
||||
"Application": "应用",
|
||||
"Awaiting user input": "等待用户输入",
|
||||
"Destination folder": "目标文件夹",
|
||||
"Download": "下载",
|
||||
"Download playlists": "下载完整播单",
|
||||
"Download started": "下载已开始",
|
||||
"On network errors, e.g. HTTP 403, please retry a few times.": "如遇HTTP 403等网络错误,请重试几次。",
|
||||
"Pick another folder": "选择文件夹",
|
||||
"Video URL": "视频链接",
|
||||
},
|
||||
}
|
||||
var locale map[string]string
|
||||
|
||||
// Poor man's gettext.
|
||||
func tr(s string) string {
|
||||
t, ok := locale[s]
|
||||
if ok {
|
||||
return t
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
// ----- START ANNIE CODE -----
|
||||
//
|
||||
// The following code is slightly modified from
|
||||
//
|
||||
// https://github.com/iawia002/annie/blob/master/main.go
|
||||
|
||||
func printError(url string, err error) {
|
||||
fmt.Printf(
|
||||
"Downloading %s error:\n%s\n", url, err,
|
||||
)
|
||||
}
|
||||
|
||||
func download(videoURL string) bool {
|
||||
var (
|
||||
domain string
|
||||
err error
|
||||
data []downloader.Data
|
||||
)
|
||||
bilibiliShortLink := utils.MatchOneOf(videoURL, `^(av|ep)\d+`)
|
||||
if bilibiliShortLink != nil && len(bilibiliShortLink) > 1 {
|
||||
bilibiliURL := map[string]string{
|
||||
"av": "https://www.bilibili.com/video/",
|
||||
"ep": "https://www.bilibili.com/bangumi/play/",
|
||||
}
|
||||
domain = "bilibili"
|
||||
videoURL = bilibiliURL[bilibiliShortLink[1]] + videoURL
|
||||
} else {
|
||||
u, err := url.ParseRequestURI(videoURL)
|
||||
if err != nil {
|
||||
printError(videoURL, err)
|
||||
return false
|
||||
}
|
||||
domain = utils.Domain(u.Host)
|
||||
}
|
||||
switch domain {
|
||||
case "douyin", "iesdouyin":
|
||||
data, err = douyin.Extract(videoURL)
|
||||
case "bilibili":
|
||||
data, err = bilibili.Extract(videoURL)
|
||||
case "bcy":
|
||||
data, err = bcy.Extract(videoURL)
|
||||
case "pixivision":
|
||||
data, err = pixivision.Extract(videoURL)
|
||||
case "youku":
|
||||
data, err = youku.Extract(videoURL)
|
||||
case "youtube", "youtu": // youtu.be
|
||||
data, err = youtube.Extract(videoURL)
|
||||
case "iqiyi":
|
||||
data, err = iqiyi.Extract(videoURL)
|
||||
case "mgtv":
|
||||
data, err = mgtv.Extract(videoURL)
|
||||
case "tangdou":
|
||||
data, err = tangdou.Extract(videoURL)
|
||||
case "tumblr":
|
||||
data, err = tumblr.Extract(videoURL)
|
||||
case "vimeo":
|
||||
data, err = vimeo.Extract(videoURL)
|
||||
case "facebook":
|
||||
data, err = facebook.Extract(videoURL)
|
||||
case "douyu":
|
||||
data, err = douyu.Extract(videoURL)
|
||||
case "miaopai":
|
||||
data, err = miaopai.Extract(videoURL)
|
||||
case "163":
|
||||
data, err = netease.Extract(videoURL)
|
||||
case "weibo":
|
||||
data, err = weibo.Extract(videoURL)
|
||||
case "instagram":
|
||||
data, err = instagram.Extract(videoURL)
|
||||
case "twitter":
|
||||
data, err = twitter.Extract(videoURL)
|
||||
case "qq":
|
||||
data, err = qq.Extract(videoURL)
|
||||
case "yinyuetai":
|
||||
data, err = yinyuetai.Extract(videoURL)
|
||||
case "geekbang":
|
||||
data, err = geekbang.Extract(videoURL)
|
||||
case "pornhub":
|
||||
data, err = pornhub.Extract(videoURL)
|
||||
case "xvideos":
|
||||
data, err = xvideos.Extract(videoURL)
|
||||
case "udn":
|
||||
data, err = udn.Extract(videoURL)
|
||||
case "tiktok":
|
||||
data, err = tiktok.Extract(videoURL)
|
||||
default:
|
||||
data, err = universal.Extract(videoURL)
|
||||
}
|
||||
if err != nil {
|
||||
// if this error occurs, it means that an error occurred before actually starting to extract data
|
||||
// (there is an error in the preparation step), and the data list is empty.
|
||||
printError(videoURL, err)
|
||||
return false
|
||||
}
|
||||
var isErr bool
|
||||
for _, item := range data {
|
||||
if item.Err != nil {
|
||||
// if this error occurs, the preparation step is normal, but the data extraction is wrong.
|
||||
// the data is an empty struct.
|
||||
printError(item.URL, item.Err)
|
||||
isErr = true
|
||||
continue
|
||||
}
|
||||
err = downloader.Download(item, videoURL, config.ChunkSizeMB)
|
||||
if err != nil {
|
||||
printError(item.URL, err)
|
||||
isErr = true
|
||||
}
|
||||
}
|
||||
return !isErr
|
||||
}
|
||||
|
||||
// ----- END ANNIE CODE -----
|
||||
|
||||
// PlainTextEdit extends QPlainTextEdit.
|
||||
type PlainTextEdit struct {
|
||||
qt.QPlainTextEdit
|
||||
|
||||
_ func() `constructor:"init"`
|
||||
|
||||
_ func(string) `slot:"addLine"`
|
||||
//
|
||||
|
||||
type outputBuffer struct {
|
||||
textEdit *qt.QPlainTextEdit
|
||||
reader *bufio.Reader
|
||||
scanner *bufio.Scanner
|
||||
carriageReturnInAction bool
|
||||
}
|
||||
|
||||
func (p *PlainTextEdit) init() {
|
||||
p.carriageReturnInAction = false
|
||||
p.ConnectAddLine(p.addLine)
|
||||
}
|
||||
|
||||
// addLines adds a line that might end in LF, CRLF, CR, or none of the above (in
|
||||
// which case an LF is appended). Aware of CR and scroll position.
|
||||
func (p *PlainTextEdit) addLine(line string) {
|
||||
scrollBar := p.VerticalScrollBar()
|
||||
currentScroll := scrollBar.Value()
|
||||
userScrolledBack := currentScroll != scrollBar.Maximum()
|
||||
|
||||
cursor := p.TextCursor()
|
||||
cursor.MovePosition(qt.QTextCursor__End, qt.QTextCursor__MoveAnchor, 1)
|
||||
if p.carriageReturnInAction {
|
||||
// Remove last line.
|
||||
cursor.Select(qt.QTextCursor__LineUnderCursor)
|
||||
cursor.RemoveSelectedText()
|
||||
}
|
||||
p.carriageReturnInAction = false
|
||||
if len(line) > 0 {
|
||||
switch lastCh := line[len(line)-1]; lastCh {
|
||||
case '\n':
|
||||
cursor.InsertText(line)
|
||||
case '\r':
|
||||
cursor.InsertText(line[:len(line)-1])
|
||||
p.carriageReturnInAction = true
|
||||
default:
|
||||
cursor.InsertText(line + "\n")
|
||||
}
|
||||
} else {
|
||||
cursor.InsertText("\n")
|
||||
}
|
||||
|
||||
if userScrolledBack {
|
||||
scrollBar.SetValue(currentScroll)
|
||||
} else {
|
||||
scrollBar.SetValue(scrollBar.Maximum())
|
||||
}
|
||||
}
|
||||
|
||||
type outputBuffer struct {
|
||||
textEdit *PlainTextEdit
|
||||
reader *bufio.Reader
|
||||
scanner *bufio.Scanner
|
||||
}
|
||||
|
||||
func newOutputBuffer(textEdit *PlainTextEdit) *outputBuffer {
|
||||
func newOutputBuffer(textEdit *qt.QPlainTextEdit) *outputBuffer {
|
||||
return &outputBuffer{
|
||||
textEdit: textEdit,
|
||||
reader: nil,
|
||||
scanner: nil,
|
||||
textEdit: textEdit,
|
||||
reader: nil,
|
||||
scanner: nil,
|
||||
carriageReturnInAction: false,
|
||||
}
|
||||
}
|
||||
|
||||
@ -335,8 +106,40 @@ func (b *outputBuffer) attachReader(r io.Reader) {
|
||||
})
|
||||
}
|
||||
|
||||
// addLine adds a line that might end in LF, CRLF, CR, or none of the above (in
|
||||
// which case an LF is appended). Aware of CR and scroll position.
|
||||
func (b *outputBuffer) addLine(line string) {
|
||||
b.textEdit.AddLine(line)
|
||||
scrollBar := b.textEdit.VerticalScrollBar()
|
||||
currentScroll := scrollBar.Value()
|
||||
userScrolledBack := currentScroll != scrollBar.Maximum()
|
||||
|
||||
cursor := b.textEdit.TextCursor()
|
||||
cursor.MovePosition3(qt.QTextCursor__End, qt.QTextCursor__MoveAnchor, 1)
|
||||
if b.carriageReturnInAction {
|
||||
// Remove last line.
|
||||
cursor.Select(qt.QTextCursor__LineUnderCursor)
|
||||
cursor.RemoveSelectedText()
|
||||
}
|
||||
b.carriageReturnInAction = false
|
||||
if len(line) > 0 {
|
||||
switch lastCh := line[len(line)-1]; lastCh {
|
||||
case '\n':
|
||||
cursor.InsertText(line)
|
||||
case '\r':
|
||||
cursor.InsertText(line[:len(line)-1])
|
||||
b.carriageReturnInAction = true
|
||||
default:
|
||||
cursor.InsertText(line + "\n")
|
||||
}
|
||||
} else {
|
||||
cursor.InsertText("\n")
|
||||
}
|
||||
|
||||
if userScrolledBack {
|
||||
scrollBar.SetValue(currentScroll)
|
||||
} else {
|
||||
scrollBar.SetValue(scrollBar.Maximum())
|
||||
}
|
||||
}
|
||||
|
||||
func (b *outputBuffer) readLineAndUpdate() (fullLine string, err error) {
|
||||
@ -357,115 +160,117 @@ func (b *outputBuffer) readLineAndUpdate() (fullLine string, err error) {
|
||||
func init() {
|
||||
flag.Parse()
|
||||
|
||||
userLang, err := jibber_jabber.DetectIETF()
|
||||
if err != nil {
|
||||
userLang = "en"
|
||||
}
|
||||
availableLangs := []string{"en"}
|
||||
availableTags := []language.Tag{language.English}
|
||||
for l := range locales {
|
||||
availableLangs = append(availableLangs, l)
|
||||
availableTags = append(availableTags, language.Make(l))
|
||||
}
|
||||
matcher := language.NewMatcher(availableTags)
|
||||
_, index, _ := matcher.Match(language.Make(userLang))
|
||||
locale = locales[availableLangs[index]]
|
||||
initLanguages()
|
||||
|
||||
qt.QCoreApplication_SetOrganizationName(appAuthor)
|
||||
qt.QCoreApplication_SetOrganizationDomain(appAuthorDomain)
|
||||
|
||||
settings = qt.NewQSettings5(nil)
|
||||
settings = qt.NewQSettings5()
|
||||
guiConfig = LoadGUIConfig()
|
||||
}
|
||||
|
||||
func initAboutWindow() *qt.QDialog {
|
||||
w := qt.NewQDialog(nil, 0)
|
||||
label := qt.NewQLabel2(about, nil, 0)
|
||||
func initAboutWindow(parent *qt.QWidget) *qt.QDialog {
|
||||
w := qt.NewQDialog(parent)
|
||||
label := qt.NewQLabel3(about)
|
||||
label.SetOpenExternalLinks(true)
|
||||
layout := qt.NewQVBoxLayout()
|
||||
layout.AddWidget(label, 0, 0)
|
||||
w.SetLayout(layout)
|
||||
layout := qt.NewQVBoxLayout2()
|
||||
layout.AddWidget(label.QWidget)
|
||||
w.SetLayout(layout.QLayout)
|
||||
return w
|
||||
}
|
||||
|
||||
func main() {
|
||||
qt.NewQApplication(len(os.Args), os.Args)
|
||||
qt.NewQApplication(os.Args)
|
||||
|
||||
window := qt.NewQMainWindow(nil, 0)
|
||||
window := qt.NewQMainWindow2()
|
||||
window.SetWindowTitle(appName)
|
||||
window.ConnectCloseEvent(func(*qt.QCloseEvent) {
|
||||
settings.SetValue("_geometry", qt.NewQVariant13(window.SaveGeometry()))
|
||||
settings.SetValue("_windowState", qt.NewQVariant13(window.SaveState(0)))
|
||||
|
||||
const WindowStateVersion = 0
|
||||
|
||||
window.OnCloseEvent(func(super func(event *qt.QCloseEvent), event *qt.QCloseEvent) {
|
||||
settings.SetValue(*qt.NewQAnyStringView3("_geometry"), qt.NewQVariant12(window.SaveGeometry()))
|
||||
settings.SetValue(*qt.NewQAnyStringView3("_windowState"), qt.NewQVariant12(window.SaveState1(WindowStateVersion)))
|
||||
|
||||
super(event)
|
||||
})
|
||||
|
||||
window.RestoreGeometry(settings.Value("_geometry", qt.NewQVariant()).ToByteArray())
|
||||
window.RestoreState(settings.Value("_windowState", qt.NewQVariant()).ToByteArray(), 0)
|
||||
{
|
||||
prevGeometry := settings.Value(*qt.NewQAnyStringView3("_geometry"), qt.NewQVariant()).ToByteArray()
|
||||
if len(prevGeometry) > 0 {
|
||||
window.RestoreGeometry(prevGeometry)
|
||||
}
|
||||
|
||||
centralWidget := qt.NewQWidget(window, 0)
|
||||
prevWindowState := settings.Value(*qt.NewQAnyStringView3("_windowState"), qt.NewQVariant()).ToByteArray()
|
||||
if len(prevWindowState) > 0 {
|
||||
window.RestoreState2(prevWindowState, WindowStateVersion)
|
||||
}
|
||||
}
|
||||
|
||||
centralWidget := qt.NewQWidget(window.QWidget)
|
||||
window.SetCentralWidget(centralWidget)
|
||||
|
||||
menuBar := window.MenuBar()
|
||||
applicationMenu := menuBar.AddMenu2(tr("Application"))
|
||||
aboutWindow := initAboutWindow()
|
||||
aboutAction := applicationMenu.AddAction(tr("About"))
|
||||
applicationMenu := menuBar.AddMenuWithTitle(tr("Application"))
|
||||
aboutWindow := initAboutWindow(window.QWidget)
|
||||
aboutAction := applicationMenu.AddActionWithText(tr("About"))
|
||||
aboutAction.SetMenuRole(qt.QAction__AboutRole)
|
||||
aboutAction.ConnectTriggered(func(bool) {
|
||||
aboutAction.OnTriggered(func() {
|
||||
aboutWindow.Show()
|
||||
aboutWindow.Raise()
|
||||
})
|
||||
|
||||
urlLineEdit := qt.NewQLineEdit(nil)
|
||||
|
||||
folderLineEdit := qt.NewQLineEdit2(guiConfig.DestinationFolder, nil)
|
||||
folderLineEdit := qt.NewQLineEdit3(guiConfig.DestinationFolder)
|
||||
folderLineEdit.SetReadOnly(true)
|
||||
folderLineEdit.SetMinimumWidth(250)
|
||||
folderButton := qt.NewQPushButton2(tr("Pick another folder"), nil)
|
||||
folderDialog := qt.NewQFileDialog2(nil, tr("Destination folder"), guiConfig.DestinationFolder, "")
|
||||
folderDialog.SetFileMode(qt.QFileDialog__DirectoryOnly)
|
||||
folderButton.ConnectClicked(func(bool) {
|
||||
if folderDialog.Exec() != int(qt.QDialog__Accepted) {
|
||||
folderButton := qt.NewQPushButton3(tr("Pick another folder"))
|
||||
folderDialog := qt.NewQFileDialog6(window.QWidget, tr("Destination folder"), guiConfig.DestinationFolder, "")
|
||||
folderDialog.SetFileMode(qt.QFileDialog__Directory)
|
||||
folderButton.OnClicked(func() {
|
||||
if folderDialog.Exec() != int(qt.QDialog__Accepted) { // FIXME blocking call
|
||||
return
|
||||
}
|
||||
destinationFolder := qt.QDir_ToNativeSeparators(folderDialog.SelectedFiles()[0])
|
||||
folderLineEdit.SetText(destinationFolder)
|
||||
guiConfig.SetDestinationFolder(destinationFolder)
|
||||
})
|
||||
folderHBoxLayout := qt.NewQHBoxLayout()
|
||||
folderHBoxLayout.AddWidget(folderLineEdit, 1, 0)
|
||||
folderHBoxLayout.AddWidget(folderButton, 0, 0)
|
||||
folderHBoxLayout := qt.NewQHBoxLayout2()
|
||||
folderHBoxLayout.AddWidget3(folderLineEdit.QWidget, 1, 0)
|
||||
folderHBoxLayout.AddWidget3(folderButton.QWidget, 0, 0)
|
||||
|
||||
playlistCheckBox := qt.NewQCheckBox(nil)
|
||||
playlistCheckBox.SetChecked(guiConfig.PlaylistEnabled)
|
||||
playlistCheckBox.ConnectToggled(func(checked bool) {
|
||||
playlistCheckBox.OnToggled(func(checked bool) {
|
||||
guiConfig.SetPlaylistEnabled(checked)
|
||||
})
|
||||
|
||||
inputFormLayout := qt.NewQFormLayout(nil)
|
||||
inputFormLayout.SetFieldGrowthPolicy(qt.QFormLayout__AllNonFixedFieldsGrow)
|
||||
inputFormLayout.AddRow3(tr("Video URL"), urlLineEdit)
|
||||
inputFormLayout.AddRow4(tr("Destination folder"), folderHBoxLayout)
|
||||
inputFormLayout.AddRow3(tr("Download playlists"), playlistCheckBox)
|
||||
inputFormLayout.AddRow3(tr("Video URL"), urlLineEdit.QWidget)
|
||||
inputFormLayout.AddRow4(tr("Destination folder"), folderHBoxLayout.QLayout)
|
||||
inputFormLayout.AddRow3(tr("Download playlists"), playlistCheckBox.QWidget)
|
||||
|
||||
outputTextEdit := NewPlainTextEdit(nil)
|
||||
outputTextEdit := qt.NewQPlainTextEdit2()
|
||||
outputTextEdit.SetReadOnly(true)
|
||||
outputTextEdit.SetMinimumHeight(400)
|
||||
outputTextEdit.SetMinimumWidth(1000)
|
||||
outputTextEdit.SetLineWrapMode(qt.QPlainTextEdit__NoWrap)
|
||||
monospaceFont := qt.NewQFont2("Courier", -1, -1, false)
|
||||
monospaceFont.SetStyleHint(qt.QFont__Monospace, 0)
|
||||
monospaceFont := qt.NewQFont2("Courier")
|
||||
monospaceFont.SetStyleHint(qt.QFont__Monospace)
|
||||
outputTextEdit.SetFont(monospaceFont)
|
||||
output := newOutputBuffer(outputTextEdit)
|
||||
output.addLine(tr("Awaiting user input"))
|
||||
|
||||
downloadButton := qt.NewQPushButton2(tr("Download"), nil)
|
||||
downloadButton.ConnectClicked(func(bool) {
|
||||
downloadButton := qt.NewQPushButton3(tr("Download"))
|
||||
downloadButton.OnClicked(func() {
|
||||
url := strings.TrimSpace(urlLineEdit.Text())
|
||||
if len(url) > 0 {
|
||||
output.addLine(time.Now().Format("15:04:05 ") + tr("Download started"))
|
||||
|
||||
config.OutputPath = guiConfig.DestinationFolder
|
||||
config.Playlist = guiConfig.PlaylistEnabled
|
||||
glog.Infof("downloading %s => %s", url, config.OutputPath)
|
||||
log.Printf("downloading %s => %s", url, config.OutputPath)
|
||||
|
||||
savedStdout := os.Stdout
|
||||
r, w, _ := os.Pipe()
|
||||
@ -479,7 +284,7 @@ func main() {
|
||||
if err == io.EOF {
|
||||
break
|
||||
}
|
||||
glog.Fatal(err)
|
||||
log.Fatal(err)
|
||||
}
|
||||
// fmt.Fprint(savedStdout, line)
|
||||
}
|
||||
@ -496,11 +301,11 @@ func main() {
|
||||
}
|
||||
})
|
||||
|
||||
layout := qt.NewQVBoxLayout()
|
||||
layout.AddLayout(inputFormLayout, 0)
|
||||
layout.AddWidget(downloadButton, 0, 0)
|
||||
layout.AddWidget(outputTextEdit, 1, 0)
|
||||
centralWidget.SetLayout(layout)
|
||||
layout := qt.NewQVBoxLayout2()
|
||||
layout.AddLayout2(inputFormLayout.QLayout, 0)
|
||||
layout.AddWidget3(downloadButton.QWidget, 0, 0)
|
||||
layout.AddWidget3(outputTextEdit.QWidget, 1, 0)
|
||||
centralWidget.SetLayout(layout.QLayout)
|
||||
|
||||
window.Show()
|
||||
|
||||
@ -509,7 +314,7 @@ func main() {
|
||||
go func() {
|
||||
for {
|
||||
sig := <-sigs
|
||||
glog.Error(sig)
|
||||
log.Print(sig)
|
||||
}
|
||||
}()
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user